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, LspAction, PrepareRenameResponse, Project,
  150    ProjectItem, 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
 6155        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6156        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6157            let CompletionSource::Lsp {
 6158                lsp_completion,
 6159                server_id,
 6160                ..
 6161            } = &completion.source
 6162            else {
 6163                return None;
 6164            };
 6165            let lsp_command = lsp_completion.command.as_ref()?;
 6166            let available_commands = lsp_store
 6167                .read(cx)
 6168                .lsp_server_capabilities
 6169                .get(server_id)
 6170                .and_then(|server_capabilities| {
 6171                    server_capabilities
 6172                        .execute_command_provider
 6173                        .as_ref()
 6174                        .map(|options| options.commands.as_slice())
 6175                })?;
 6176            if available_commands.contains(&lsp_command.command) {
 6177                Some(CodeAction {
 6178                    server_id: *server_id,
 6179                    range: language::Anchor::MIN..language::Anchor::MIN,
 6180                    lsp_action: LspAction::Command(lsp_command.clone()),
 6181                    resolved: false,
 6182                })
 6183            } else {
 6184                None
 6185            }
 6186        });
 6187
 6188        drop(completion);
 6189        let apply_edits = provider.apply_additional_edits_for_completion(
 6190            buffer_handle.clone(),
 6191            completions_menu.completions.clone(),
 6192            candidate_id,
 6193            true,
 6194            cx,
 6195        );
 6196
 6197        let editor_settings = EditorSettings::get_global(cx);
 6198        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6199            // After the code completion is finished, users often want to know what signatures are needed.
 6200            // so we should automatically call signature_help
 6201            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6202        }
 6203
 6204        Some(cx.spawn_in(window, async move |editor, cx| {
 6205            apply_edits.await?;
 6206
 6207            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6208                let title = command.lsp_action.title().to_owned();
 6209                let project_transaction = lsp_store
 6210                    .update(cx, |lsp_store, cx| {
 6211                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6212                    })?
 6213                    .await
 6214                    .context("applying post-completion command")?;
 6215                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6216                    Self::open_project_transaction(
 6217                        &editor,
 6218                        workspace.downgrade(),
 6219                        project_transaction,
 6220                        title,
 6221                        cx,
 6222                    )
 6223                    .await?;
 6224                }
 6225            }
 6226
 6227            Ok(())
 6228        }))
 6229    }
 6230
 6231    pub fn toggle_code_actions(
 6232        &mut self,
 6233        action: &ToggleCodeActions,
 6234        window: &mut Window,
 6235        cx: &mut Context<Self>,
 6236    ) {
 6237        let quick_launch = action.quick_launch;
 6238        let mut context_menu = self.context_menu.borrow_mut();
 6239        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6240            if code_actions.deployed_from == action.deployed_from {
 6241                // Toggle if we're selecting the same one
 6242                *context_menu = None;
 6243                cx.notify();
 6244                return;
 6245            } else {
 6246                // Otherwise, clear it and start a new one
 6247                *context_menu = None;
 6248                cx.notify();
 6249            }
 6250        }
 6251        drop(context_menu);
 6252        let snapshot = self.snapshot(window, cx);
 6253        let deployed_from = action.deployed_from.clone();
 6254        let action = action.clone();
 6255        self.completion_tasks.clear();
 6256        self.discard_edit_prediction(false, cx);
 6257
 6258        let multibuffer_point = match &action.deployed_from {
 6259            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6260                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6261            }
 6262            _ => self
 6263                .selections
 6264                .newest::<Point>(&snapshot.display_snapshot)
 6265                .head(),
 6266        };
 6267        let Some((buffer, buffer_row)) = snapshot
 6268            .buffer_snapshot()
 6269            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6270            .and_then(|(buffer_snapshot, range)| {
 6271                self.buffer()
 6272                    .read(cx)
 6273                    .buffer(buffer_snapshot.remote_id())
 6274                    .map(|buffer| (buffer, range.start.row))
 6275            })
 6276        else {
 6277            return;
 6278        };
 6279        let buffer_id = buffer.read(cx).remote_id();
 6280        let tasks = self
 6281            .tasks
 6282            .get(&(buffer_id, buffer_row))
 6283            .map(|t| Arc::new(t.to_owned()));
 6284
 6285        if !self.focus_handle.is_focused(window) {
 6286            return;
 6287        }
 6288        let project = self.project.clone();
 6289
 6290        let code_actions_task = match deployed_from {
 6291            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6292            _ => self.code_actions(buffer_row, window, cx),
 6293        };
 6294
 6295        let runnable_task = match deployed_from {
 6296            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6297            _ => {
 6298                let mut task_context_task = Task::ready(None);
 6299                if let Some(tasks) = &tasks
 6300                    && let Some(project) = project
 6301                {
 6302                    task_context_task =
 6303                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6304                }
 6305
 6306                cx.spawn_in(window, {
 6307                    let buffer = buffer.clone();
 6308                    async move |editor, cx| {
 6309                        let task_context = task_context_task.await;
 6310
 6311                        let resolved_tasks =
 6312                            tasks
 6313                                .zip(task_context.clone())
 6314                                .map(|(tasks, task_context)| ResolvedTasks {
 6315                                    templates: tasks.resolve(&task_context).collect(),
 6316                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6317                                        multibuffer_point.row,
 6318                                        tasks.column,
 6319                                    )),
 6320                                });
 6321                        let debug_scenarios = editor
 6322                            .update(cx, |editor, cx| {
 6323                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6324                            })?
 6325                            .await;
 6326                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6327                    }
 6328                })
 6329            }
 6330        };
 6331
 6332        cx.spawn_in(window, async move |editor, cx| {
 6333            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6334            let code_actions = code_actions_task.await;
 6335            let spawn_straight_away = quick_launch
 6336                && resolved_tasks
 6337                    .as_ref()
 6338                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6339                && code_actions
 6340                    .as_ref()
 6341                    .is_none_or(|actions| actions.is_empty())
 6342                && debug_scenarios.is_empty();
 6343
 6344            editor.update_in(cx, |editor, window, cx| {
 6345                crate::hover_popover::hide_hover(editor, cx);
 6346                let actions = CodeActionContents::new(
 6347                    resolved_tasks,
 6348                    code_actions,
 6349                    debug_scenarios,
 6350                    task_context.unwrap_or_default(),
 6351                );
 6352
 6353                // Don't show the menu if there are no actions available
 6354                if actions.is_empty() {
 6355                    cx.notify();
 6356                    return Task::ready(Ok(()));
 6357                }
 6358
 6359                *editor.context_menu.borrow_mut() =
 6360                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6361                        buffer,
 6362                        actions,
 6363                        selected_item: Default::default(),
 6364                        scroll_handle: UniformListScrollHandle::default(),
 6365                        deployed_from,
 6366                    }));
 6367                cx.notify();
 6368                if spawn_straight_away
 6369                    && let Some(task) = editor.confirm_code_action(
 6370                        &ConfirmCodeAction { item_ix: Some(0) },
 6371                        window,
 6372                        cx,
 6373                    )
 6374                {
 6375                    return task;
 6376                }
 6377
 6378                Task::ready(Ok(()))
 6379            })
 6380        })
 6381        .detach_and_log_err(cx);
 6382    }
 6383
 6384    fn debug_scenarios(
 6385        &mut self,
 6386        resolved_tasks: &Option<ResolvedTasks>,
 6387        buffer: &Entity<Buffer>,
 6388        cx: &mut App,
 6389    ) -> Task<Vec<task::DebugScenario>> {
 6390        maybe!({
 6391            let project = self.project()?;
 6392            let dap_store = project.read(cx).dap_store();
 6393            let mut scenarios = vec![];
 6394            let resolved_tasks = resolved_tasks.as_ref()?;
 6395            let buffer = buffer.read(cx);
 6396            let language = buffer.language()?;
 6397            let file = buffer.file();
 6398            let debug_adapter = language_settings(language.name().into(), file, cx)
 6399                .debuggers
 6400                .first()
 6401                .map(SharedString::from)
 6402                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6403
 6404            dap_store.update(cx, |dap_store, cx| {
 6405                for (_, task) in &resolved_tasks.templates {
 6406                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6407                        task.original_task().clone(),
 6408                        debug_adapter.clone().into(),
 6409                        task.display_label().to_owned().into(),
 6410                        cx,
 6411                    );
 6412                    scenarios.push(maybe_scenario);
 6413                }
 6414            });
 6415            Some(cx.background_spawn(async move {
 6416                futures::future::join_all(scenarios)
 6417                    .await
 6418                    .into_iter()
 6419                    .flatten()
 6420                    .collect::<Vec<_>>()
 6421            }))
 6422        })
 6423        .unwrap_or_else(|| Task::ready(vec![]))
 6424    }
 6425
 6426    fn code_actions(
 6427        &mut self,
 6428        buffer_row: u32,
 6429        window: &mut Window,
 6430        cx: &mut Context<Self>,
 6431    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6432        let mut task = self.code_actions_task.take();
 6433        cx.spawn_in(window, async move |editor, cx| {
 6434            while let Some(prev_task) = task {
 6435                prev_task.await.log_err();
 6436                task = editor
 6437                    .update(cx, |this, _| this.code_actions_task.take())
 6438                    .ok()?;
 6439            }
 6440
 6441            editor
 6442                .update(cx, |editor, cx| {
 6443                    editor
 6444                        .available_code_actions
 6445                        .clone()
 6446                        .and_then(|(location, code_actions)| {
 6447                            let snapshot = location.buffer.read(cx).snapshot();
 6448                            let point_range = location.range.to_point(&snapshot);
 6449                            let point_range = point_range.start.row..=point_range.end.row;
 6450                            if point_range.contains(&buffer_row) {
 6451                                Some(code_actions)
 6452                            } else {
 6453                                None
 6454                            }
 6455                        })
 6456                })
 6457                .ok()
 6458                .flatten()
 6459        })
 6460    }
 6461
 6462    pub fn confirm_code_action(
 6463        &mut self,
 6464        action: &ConfirmCodeAction,
 6465        window: &mut Window,
 6466        cx: &mut Context<Self>,
 6467    ) -> Option<Task<Result<()>>> {
 6468        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6469
 6470        let actions_menu =
 6471            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6472                menu
 6473            } else {
 6474                return None;
 6475            };
 6476
 6477        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6478        let action = actions_menu.actions.get(action_ix)?;
 6479        let title = action.label();
 6480        let buffer = actions_menu.buffer;
 6481        let workspace = self.workspace()?;
 6482
 6483        match action {
 6484            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6485                workspace.update(cx, |workspace, cx| {
 6486                    workspace.schedule_resolved_task(
 6487                        task_source_kind,
 6488                        resolved_task,
 6489                        false,
 6490                        window,
 6491                        cx,
 6492                    );
 6493
 6494                    Some(Task::ready(Ok(())))
 6495                })
 6496            }
 6497            CodeActionsItem::CodeAction {
 6498                excerpt_id,
 6499                action,
 6500                provider,
 6501            } => {
 6502                let apply_code_action =
 6503                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6504                let workspace = workspace.downgrade();
 6505                Some(cx.spawn_in(window, async move |editor, cx| {
 6506                    let project_transaction = apply_code_action.await?;
 6507                    Self::open_project_transaction(
 6508                        &editor,
 6509                        workspace,
 6510                        project_transaction,
 6511                        title,
 6512                        cx,
 6513                    )
 6514                    .await
 6515                }))
 6516            }
 6517            CodeActionsItem::DebugScenario(scenario) => {
 6518                let context = actions_menu.actions.context;
 6519
 6520                workspace.update(cx, |workspace, cx| {
 6521                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6522                    workspace.start_debug_session(
 6523                        scenario,
 6524                        context,
 6525                        Some(buffer),
 6526                        None,
 6527                        window,
 6528                        cx,
 6529                    );
 6530                });
 6531                Some(Task::ready(Ok(())))
 6532            }
 6533        }
 6534    }
 6535
 6536    pub async fn open_project_transaction(
 6537        editor: &WeakEntity<Editor>,
 6538        workspace: WeakEntity<Workspace>,
 6539        transaction: ProjectTransaction,
 6540        title: String,
 6541        cx: &mut AsyncWindowContext,
 6542    ) -> Result<()> {
 6543        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6544        cx.update(|_, cx| {
 6545            entries.sort_unstable_by_key(|(buffer, _)| {
 6546                buffer.read(cx).file().map(|f| f.path().clone())
 6547            });
 6548        })?;
 6549        if entries.is_empty() {
 6550            return Ok(());
 6551        }
 6552
 6553        // If the project transaction's edits are all contained within this editor, then
 6554        // avoid opening a new editor to display them.
 6555
 6556        if let [(buffer, transaction)] = &*entries {
 6557            let excerpt = editor.update(cx, |editor, cx| {
 6558                editor
 6559                    .buffer()
 6560                    .read(cx)
 6561                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6562            })?;
 6563            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6564                && excerpted_buffer == *buffer
 6565            {
 6566                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6567                    let excerpt_range = excerpt_range.to_offset(buffer);
 6568                    buffer
 6569                        .edited_ranges_for_transaction::<usize>(transaction)
 6570                        .all(|range| {
 6571                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6572                        })
 6573                })?;
 6574
 6575                if all_edits_within_excerpt {
 6576                    return Ok(());
 6577                }
 6578            }
 6579        }
 6580
 6581        let mut ranges_to_highlight = Vec::new();
 6582        let excerpt_buffer = cx.new(|cx| {
 6583            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6584            for (buffer_handle, transaction) in &entries {
 6585                let edited_ranges = buffer_handle
 6586                    .read(cx)
 6587                    .edited_ranges_for_transaction::<Point>(transaction)
 6588                    .collect::<Vec<_>>();
 6589                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6590                    PathKey::for_buffer(buffer_handle, cx),
 6591                    buffer_handle.clone(),
 6592                    edited_ranges,
 6593                    multibuffer_context_lines(cx),
 6594                    cx,
 6595                );
 6596
 6597                ranges_to_highlight.extend(ranges);
 6598            }
 6599            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6600            multibuffer
 6601        })?;
 6602
 6603        workspace.update_in(cx, |workspace, window, cx| {
 6604            let project = workspace.project().clone();
 6605            let editor =
 6606                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6607            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6608            editor.update(cx, |editor, cx| {
 6609                editor.highlight_background::<Self>(
 6610                    &ranges_to_highlight,
 6611                    |theme| theme.colors().editor_highlighted_line_background,
 6612                    cx,
 6613                );
 6614            });
 6615        })?;
 6616
 6617        Ok(())
 6618    }
 6619
 6620    pub fn clear_code_action_providers(&mut self) {
 6621        self.code_action_providers.clear();
 6622        self.available_code_actions.take();
 6623    }
 6624
 6625    pub fn add_code_action_provider(
 6626        &mut self,
 6627        provider: Rc<dyn CodeActionProvider>,
 6628        window: &mut Window,
 6629        cx: &mut Context<Self>,
 6630    ) {
 6631        if self
 6632            .code_action_providers
 6633            .iter()
 6634            .any(|existing_provider| existing_provider.id() == provider.id())
 6635        {
 6636            return;
 6637        }
 6638
 6639        self.code_action_providers.push(provider);
 6640        self.refresh_code_actions(window, cx);
 6641    }
 6642
 6643    pub fn remove_code_action_provider(
 6644        &mut self,
 6645        id: Arc<str>,
 6646        window: &mut Window,
 6647        cx: &mut Context<Self>,
 6648    ) {
 6649        self.code_action_providers
 6650            .retain(|provider| provider.id() != id);
 6651        self.refresh_code_actions(window, cx);
 6652    }
 6653
 6654    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6655        !self.code_action_providers.is_empty()
 6656            && EditorSettings::get_global(cx).toolbar.code_actions
 6657    }
 6658
 6659    pub fn has_available_code_actions(&self) -> bool {
 6660        self.available_code_actions
 6661            .as_ref()
 6662            .is_some_and(|(_, actions)| !actions.is_empty())
 6663    }
 6664
 6665    fn render_inline_code_actions(
 6666        &self,
 6667        icon_size: ui::IconSize,
 6668        display_row: DisplayRow,
 6669        is_active: bool,
 6670        cx: &mut Context<Self>,
 6671    ) -> AnyElement {
 6672        let show_tooltip = !self.context_menu_visible();
 6673        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6674            .icon_size(icon_size)
 6675            .shape(ui::IconButtonShape::Square)
 6676            .icon_color(ui::Color::Hidden)
 6677            .toggle_state(is_active)
 6678            .when(show_tooltip, |this| {
 6679                this.tooltip({
 6680                    let focus_handle = self.focus_handle.clone();
 6681                    move |_window, cx| {
 6682                        Tooltip::for_action_in(
 6683                            "Toggle Code Actions",
 6684                            &ToggleCodeActions {
 6685                                deployed_from: None,
 6686                                quick_launch: false,
 6687                            },
 6688                            &focus_handle,
 6689                            cx,
 6690                        )
 6691                    }
 6692                })
 6693            })
 6694            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6695                window.focus(&editor.focus_handle(cx));
 6696                editor.toggle_code_actions(
 6697                    &crate::actions::ToggleCodeActions {
 6698                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6699                            display_row,
 6700                        )),
 6701                        quick_launch: false,
 6702                    },
 6703                    window,
 6704                    cx,
 6705                );
 6706            }))
 6707            .into_any_element()
 6708    }
 6709
 6710    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6711        &self.context_menu
 6712    }
 6713
 6714    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6715        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6716            cx.background_executor()
 6717                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6718                .await;
 6719
 6720            let (start_buffer, start, _, end, newest_selection) = this
 6721                .update(cx, |this, cx| {
 6722                    let newest_selection = this.selections.newest_anchor().clone();
 6723                    if newest_selection.head().diff_base_anchor.is_some() {
 6724                        return None;
 6725                    }
 6726                    let display_snapshot = this.display_snapshot(cx);
 6727                    let newest_selection_adjusted =
 6728                        this.selections.newest_adjusted(&display_snapshot);
 6729                    let buffer = this.buffer.read(cx);
 6730
 6731                    let (start_buffer, start) =
 6732                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6733                    let (end_buffer, end) =
 6734                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6735
 6736                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6737                })?
 6738                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6739                .context(
 6740                    "Expected selection to lie in a single buffer when refreshing code actions",
 6741                )?;
 6742            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6743                let providers = this.code_action_providers.clone();
 6744                let tasks = this
 6745                    .code_action_providers
 6746                    .iter()
 6747                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6748                    .collect::<Vec<_>>();
 6749                (providers, tasks)
 6750            })?;
 6751
 6752            let mut actions = Vec::new();
 6753            for (provider, provider_actions) in
 6754                providers.into_iter().zip(future::join_all(tasks).await)
 6755            {
 6756                if let Some(provider_actions) = provider_actions.log_err() {
 6757                    actions.extend(provider_actions.into_iter().map(|action| {
 6758                        AvailableCodeAction {
 6759                            excerpt_id: newest_selection.start.excerpt_id,
 6760                            action,
 6761                            provider: provider.clone(),
 6762                        }
 6763                    }));
 6764                }
 6765            }
 6766
 6767            this.update(cx, |this, cx| {
 6768                this.available_code_actions = if actions.is_empty() {
 6769                    None
 6770                } else {
 6771                    Some((
 6772                        Location {
 6773                            buffer: start_buffer,
 6774                            range: start..end,
 6775                        },
 6776                        actions.into(),
 6777                    ))
 6778                };
 6779                cx.notify();
 6780            })
 6781        }));
 6782    }
 6783
 6784    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6785        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6786            self.show_git_blame_inline = false;
 6787
 6788            self.show_git_blame_inline_delay_task =
 6789                Some(cx.spawn_in(window, async move |this, cx| {
 6790                    cx.background_executor().timer(delay).await;
 6791
 6792                    this.update(cx, |this, cx| {
 6793                        this.show_git_blame_inline = true;
 6794                        cx.notify();
 6795                    })
 6796                    .log_err();
 6797                }));
 6798        }
 6799    }
 6800
 6801    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6802        let snapshot = self.snapshot(window, cx);
 6803        let cursor = self
 6804            .selections
 6805            .newest::<Point>(&snapshot.display_snapshot)
 6806            .head();
 6807        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6808        else {
 6809            return;
 6810        };
 6811
 6812        let Some(blame) = self.blame.as_ref() else {
 6813            return;
 6814        };
 6815
 6816        let row_info = RowInfo {
 6817            buffer_id: Some(buffer.remote_id()),
 6818            buffer_row: Some(point.row),
 6819            ..Default::default()
 6820        };
 6821        let Some((buffer, blame_entry)) = blame
 6822            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6823            .flatten()
 6824        else {
 6825            return;
 6826        };
 6827
 6828        let anchor = self.selections.newest_anchor().head();
 6829        let position = self.to_pixel_point(anchor, &snapshot, window);
 6830        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6831            self.show_blame_popover(
 6832                buffer,
 6833                &blame_entry,
 6834                position + last_bounds.origin,
 6835                true,
 6836                cx,
 6837            );
 6838        };
 6839    }
 6840
 6841    fn show_blame_popover(
 6842        &mut self,
 6843        buffer: BufferId,
 6844        blame_entry: &BlameEntry,
 6845        position: gpui::Point<Pixels>,
 6846        ignore_timeout: bool,
 6847        cx: &mut Context<Self>,
 6848    ) {
 6849        if let Some(state) = &mut self.inline_blame_popover {
 6850            state.hide_task.take();
 6851        } else {
 6852            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6853            let blame_entry = blame_entry.clone();
 6854            let show_task = cx.spawn(async move |editor, cx| {
 6855                if !ignore_timeout {
 6856                    cx.background_executor()
 6857                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6858                        .await;
 6859                }
 6860                editor
 6861                    .update(cx, |editor, cx| {
 6862                        editor.inline_blame_popover_show_task.take();
 6863                        let Some(blame) = editor.blame.as_ref() else {
 6864                            return;
 6865                        };
 6866                        let blame = blame.read(cx);
 6867                        let details = blame.details_for_entry(buffer, &blame_entry);
 6868                        let markdown = cx.new(|cx| {
 6869                            Markdown::new(
 6870                                details
 6871                                    .as_ref()
 6872                                    .map(|message| message.message.clone())
 6873                                    .unwrap_or_default(),
 6874                                None,
 6875                                None,
 6876                                cx,
 6877                            )
 6878                        });
 6879                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6880                            position,
 6881                            hide_task: None,
 6882                            popover_bounds: None,
 6883                            popover_state: InlineBlamePopoverState {
 6884                                scroll_handle: ScrollHandle::new(),
 6885                                commit_message: details,
 6886                                markdown,
 6887                            },
 6888                            keyboard_grace: ignore_timeout,
 6889                        });
 6890                        cx.notify();
 6891                    })
 6892                    .ok();
 6893            });
 6894            self.inline_blame_popover_show_task = Some(show_task);
 6895        }
 6896    }
 6897
 6898    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6899        self.inline_blame_popover_show_task.take();
 6900        if let Some(state) = &mut self.inline_blame_popover {
 6901            let hide_task = cx.spawn(async move |editor, cx| {
 6902                if !ignore_timeout {
 6903                    cx.background_executor()
 6904                        .timer(std::time::Duration::from_millis(100))
 6905                        .await;
 6906                }
 6907                editor
 6908                    .update(cx, |editor, cx| {
 6909                        editor.inline_blame_popover.take();
 6910                        cx.notify();
 6911                    })
 6912                    .ok();
 6913            });
 6914            state.hide_task = Some(hide_task);
 6915            true
 6916        } else {
 6917            false
 6918        }
 6919    }
 6920
 6921    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6922        if self.pending_rename.is_some() {
 6923            return None;
 6924        }
 6925
 6926        let provider = self.semantics_provider.clone()?;
 6927        let buffer = self.buffer.read(cx);
 6928        let newest_selection = self.selections.newest_anchor().clone();
 6929        let cursor_position = newest_selection.head();
 6930        let (cursor_buffer, cursor_buffer_position) =
 6931            buffer.text_anchor_for_position(cursor_position, cx)?;
 6932        let (tail_buffer, tail_buffer_position) =
 6933            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6934        if cursor_buffer != tail_buffer {
 6935            return None;
 6936        }
 6937
 6938        let snapshot = cursor_buffer.read(cx).snapshot();
 6939        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6940        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6941        if start_word_range != end_word_range {
 6942            self.document_highlights_task.take();
 6943            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6944            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6945            return None;
 6946        }
 6947
 6948        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6949        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6950            cx.background_executor()
 6951                .timer(Duration::from_millis(debounce))
 6952                .await;
 6953
 6954            let highlights = if let Some(highlights) = cx
 6955                .update(|cx| {
 6956                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6957                })
 6958                .ok()
 6959                .flatten()
 6960            {
 6961                highlights.await.log_err()
 6962            } else {
 6963                None
 6964            };
 6965
 6966            if let Some(highlights) = highlights {
 6967                this.update(cx, |this, cx| {
 6968                    if this.pending_rename.is_some() {
 6969                        return;
 6970                    }
 6971
 6972                    let buffer = this.buffer.read(cx);
 6973                    if buffer
 6974                        .text_anchor_for_position(cursor_position, cx)
 6975                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6976                    {
 6977                        return;
 6978                    }
 6979
 6980                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6981                    let mut write_ranges = Vec::new();
 6982                    let mut read_ranges = Vec::new();
 6983                    for highlight in highlights {
 6984                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6985                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6986                        {
 6987                            let start = highlight
 6988                                .range
 6989                                .start
 6990                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6991                            let end = highlight
 6992                                .range
 6993                                .end
 6994                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6995                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6996                                continue;
 6997                            }
 6998
 6999                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7000                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7001                                write_ranges.push(range);
 7002                            } else {
 7003                                read_ranges.push(range);
 7004                            }
 7005                        }
 7006                    }
 7007
 7008                    this.highlight_background::<DocumentHighlightRead>(
 7009                        &read_ranges,
 7010                        |theme| theme.colors().editor_document_highlight_read_background,
 7011                        cx,
 7012                    );
 7013                    this.highlight_background::<DocumentHighlightWrite>(
 7014                        &write_ranges,
 7015                        |theme| theme.colors().editor_document_highlight_write_background,
 7016                        cx,
 7017                    );
 7018                    cx.notify();
 7019                })
 7020                .log_err();
 7021            }
 7022        }));
 7023        None
 7024    }
 7025
 7026    fn prepare_highlight_query_from_selection(
 7027        &mut self,
 7028        window: &Window,
 7029        cx: &mut Context<Editor>,
 7030    ) -> Option<(String, Range<Anchor>)> {
 7031        if matches!(self.mode, EditorMode::SingleLine) {
 7032            return None;
 7033        }
 7034        if !EditorSettings::get_global(cx).selection_highlight {
 7035            return None;
 7036        }
 7037        if self.selections.count() != 1 || self.selections.line_mode() {
 7038            return None;
 7039        }
 7040        let snapshot = self.snapshot(window, cx);
 7041        let selection = self.selections.newest::<Point>(&snapshot);
 7042        // If the selection spans multiple rows OR it is empty
 7043        if selection.start.row != selection.end.row
 7044            || selection.start.column == selection.end.column
 7045        {
 7046            return None;
 7047        }
 7048        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7049        let query = snapshot
 7050            .buffer_snapshot()
 7051            .text_for_range(selection_anchor_range.clone())
 7052            .collect::<String>();
 7053        if query.trim().is_empty() {
 7054            return None;
 7055        }
 7056        Some((query, selection_anchor_range))
 7057    }
 7058
 7059    fn update_selection_occurrence_highlights(
 7060        &mut self,
 7061        query_text: String,
 7062        query_range: Range<Anchor>,
 7063        multi_buffer_range_to_query: Range<Point>,
 7064        use_debounce: bool,
 7065        window: &mut Window,
 7066        cx: &mut Context<Editor>,
 7067    ) -> Task<()> {
 7068        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7069        cx.spawn_in(window, async move |editor, cx| {
 7070            if use_debounce {
 7071                cx.background_executor()
 7072                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7073                    .await;
 7074            }
 7075            let match_task = cx.background_spawn(async move {
 7076                let buffer_ranges = multi_buffer_snapshot
 7077                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7078                    .into_iter()
 7079                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7080                let mut match_ranges = Vec::new();
 7081                let Ok(regex) = project::search::SearchQuery::text(
 7082                    query_text.clone(),
 7083                    false,
 7084                    false,
 7085                    false,
 7086                    Default::default(),
 7087                    Default::default(),
 7088                    false,
 7089                    None,
 7090                ) else {
 7091                    return Vec::default();
 7092                };
 7093                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7094                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7095                    match_ranges.extend(
 7096                        regex
 7097                            .search(
 7098                                buffer_snapshot,
 7099                                Some(search_range.start.0..search_range.end.0),
 7100                            )
 7101                            .await
 7102                            .into_iter()
 7103                            .filter_map(|match_range| {
 7104                                let match_start = buffer_snapshot
 7105                                    .anchor_after(search_range.start + match_range.start);
 7106                                let match_end = buffer_snapshot
 7107                                    .anchor_before(search_range.start + match_range.end);
 7108                                let match_anchor_range =
 7109                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7110                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7111                            }),
 7112                    );
 7113                }
 7114                match_ranges
 7115            });
 7116            let match_ranges = match_task.await;
 7117            editor
 7118                .update_in(cx, |editor, _, cx| {
 7119                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7120                    if !match_ranges.is_empty() {
 7121                        editor.highlight_background::<SelectedTextHighlight>(
 7122                            &match_ranges,
 7123                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7124                            cx,
 7125                        )
 7126                    }
 7127                })
 7128                .log_err();
 7129        })
 7130    }
 7131
 7132    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7133        struct NewlineFold;
 7134        let type_id = std::any::TypeId::of::<NewlineFold>();
 7135        if !self.mode.is_single_line() {
 7136            return;
 7137        }
 7138        let snapshot = self.snapshot(window, cx);
 7139        if snapshot.buffer_snapshot().max_point().row == 0 {
 7140            return;
 7141        }
 7142        let task = cx.background_spawn(async move {
 7143            let new_newlines = snapshot
 7144                .buffer_chars_at(MultiBufferOffset(0))
 7145                .filter_map(|(c, i)| {
 7146                    if c == '\n' {
 7147                        Some(
 7148                            snapshot.buffer_snapshot().anchor_after(i)
 7149                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7150                        )
 7151                    } else {
 7152                        None
 7153                    }
 7154                })
 7155                .collect::<Vec<_>>();
 7156            let existing_newlines = snapshot
 7157                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7158                .filter_map(|fold| {
 7159                    if fold.placeholder.type_tag == Some(type_id) {
 7160                        Some(fold.range.start..fold.range.end)
 7161                    } else {
 7162                        None
 7163                    }
 7164                })
 7165                .collect::<Vec<_>>();
 7166
 7167            (new_newlines, existing_newlines)
 7168        });
 7169        self.folding_newlines = cx.spawn(async move |this, cx| {
 7170            let (new_newlines, existing_newlines) = task.await;
 7171            if new_newlines == existing_newlines {
 7172                return;
 7173            }
 7174            let placeholder = FoldPlaceholder {
 7175                render: Arc::new(move |_, _, cx| {
 7176                    div()
 7177                        .bg(cx.theme().status().hint_background)
 7178                        .border_b_1()
 7179                        .size_full()
 7180                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7181                        .border_color(cx.theme().status().hint)
 7182                        .child("\\n")
 7183                        .into_any()
 7184                }),
 7185                constrain_width: false,
 7186                merge_adjacent: false,
 7187                type_tag: Some(type_id),
 7188            };
 7189            let creases = new_newlines
 7190                .into_iter()
 7191                .map(|range| Crease::simple(range, placeholder.clone()))
 7192                .collect();
 7193            this.update(cx, |this, cx| {
 7194                this.display_map.update(cx, |display_map, cx| {
 7195                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7196                    display_map.fold(creases, cx);
 7197                });
 7198            })
 7199            .ok();
 7200        });
 7201    }
 7202
 7203    fn refresh_selected_text_highlights(
 7204        &mut self,
 7205        on_buffer_edit: bool,
 7206        window: &mut Window,
 7207        cx: &mut Context<Editor>,
 7208    ) {
 7209        let Some((query_text, query_range)) =
 7210            self.prepare_highlight_query_from_selection(window, cx)
 7211        else {
 7212            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7213            self.quick_selection_highlight_task.take();
 7214            self.debounced_selection_highlight_task.take();
 7215            return;
 7216        };
 7217        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7218        if on_buffer_edit
 7219            || self
 7220                .quick_selection_highlight_task
 7221                .as_ref()
 7222                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7223        {
 7224            let multi_buffer_visible_start = self
 7225                .scroll_manager
 7226                .anchor()
 7227                .anchor
 7228                .to_point(&multi_buffer_snapshot);
 7229            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7230                multi_buffer_visible_start
 7231                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7232                Bias::Left,
 7233            );
 7234            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7235            self.quick_selection_highlight_task = Some((
 7236                query_range.clone(),
 7237                self.update_selection_occurrence_highlights(
 7238                    query_text.clone(),
 7239                    query_range.clone(),
 7240                    multi_buffer_visible_range,
 7241                    false,
 7242                    window,
 7243                    cx,
 7244                ),
 7245            ));
 7246        }
 7247        if on_buffer_edit
 7248            || self
 7249                .debounced_selection_highlight_task
 7250                .as_ref()
 7251                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7252        {
 7253            let multi_buffer_start = multi_buffer_snapshot
 7254                .anchor_before(MultiBufferOffset(0))
 7255                .to_point(&multi_buffer_snapshot);
 7256            let multi_buffer_end = multi_buffer_snapshot
 7257                .anchor_after(multi_buffer_snapshot.len())
 7258                .to_point(&multi_buffer_snapshot);
 7259            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7260            self.debounced_selection_highlight_task = Some((
 7261                query_range.clone(),
 7262                self.update_selection_occurrence_highlights(
 7263                    query_text,
 7264                    query_range,
 7265                    multi_buffer_full_range,
 7266                    true,
 7267                    window,
 7268                    cx,
 7269                ),
 7270            ));
 7271        }
 7272    }
 7273
 7274    pub fn refresh_edit_prediction(
 7275        &mut self,
 7276        debounce: bool,
 7277        user_requested: bool,
 7278        window: &mut Window,
 7279        cx: &mut Context<Self>,
 7280    ) -> Option<()> {
 7281        if DisableAiSettings::get_global(cx).disable_ai {
 7282            return None;
 7283        }
 7284
 7285        let provider = self.edit_prediction_provider()?;
 7286        let cursor = self.selections.newest_anchor().head();
 7287        let (buffer, cursor_buffer_position) =
 7288            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7289
 7290        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7291            self.discard_edit_prediction(false, cx);
 7292            return None;
 7293        }
 7294
 7295        self.update_visible_edit_prediction(window, cx);
 7296
 7297        if !user_requested
 7298            && (!self.should_show_edit_predictions()
 7299                || !self.is_focused(window)
 7300                || buffer.read(cx).is_empty())
 7301        {
 7302            self.discard_edit_prediction(false, cx);
 7303            return None;
 7304        }
 7305
 7306        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7307        Some(())
 7308    }
 7309
 7310    fn show_edit_predictions_in_menu(&self) -> bool {
 7311        match self.edit_prediction_settings {
 7312            EditPredictionSettings::Disabled => false,
 7313            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7314        }
 7315    }
 7316
 7317    pub fn edit_predictions_enabled(&self) -> bool {
 7318        match self.edit_prediction_settings {
 7319            EditPredictionSettings::Disabled => false,
 7320            EditPredictionSettings::Enabled { .. } => true,
 7321        }
 7322    }
 7323
 7324    fn edit_prediction_requires_modifier(&self) -> bool {
 7325        match self.edit_prediction_settings {
 7326            EditPredictionSettings::Disabled => false,
 7327            EditPredictionSettings::Enabled {
 7328                preview_requires_modifier,
 7329                ..
 7330            } => preview_requires_modifier,
 7331        }
 7332    }
 7333
 7334    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7335        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7336            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7337            self.discard_edit_prediction(false, cx);
 7338        } else {
 7339            let selection = self.selections.newest_anchor();
 7340            let cursor = selection.head();
 7341
 7342            if let Some((buffer, cursor_buffer_position)) =
 7343                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7344            {
 7345                self.edit_prediction_settings =
 7346                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7347            }
 7348        }
 7349    }
 7350
 7351    fn edit_prediction_settings_at_position(
 7352        &self,
 7353        buffer: &Entity<Buffer>,
 7354        buffer_position: language::Anchor,
 7355        cx: &App,
 7356    ) -> EditPredictionSettings {
 7357        if !self.mode.is_full()
 7358            || !self.show_edit_predictions_override.unwrap_or(true)
 7359            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7360        {
 7361            return EditPredictionSettings::Disabled;
 7362        }
 7363
 7364        let buffer = buffer.read(cx);
 7365
 7366        let file = buffer.file();
 7367
 7368        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7369            return EditPredictionSettings::Disabled;
 7370        };
 7371
 7372        let by_provider = matches!(
 7373            self.menu_edit_predictions_policy,
 7374            MenuEditPredictionsPolicy::ByProvider
 7375        );
 7376
 7377        let show_in_menu = by_provider
 7378            && self
 7379                .edit_prediction_provider
 7380                .as_ref()
 7381                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7382
 7383        let preview_requires_modifier =
 7384            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7385
 7386        EditPredictionSettings::Enabled {
 7387            show_in_menu,
 7388            preview_requires_modifier,
 7389        }
 7390    }
 7391
 7392    fn should_show_edit_predictions(&self) -> bool {
 7393        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7394    }
 7395
 7396    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7397        matches!(
 7398            self.edit_prediction_preview,
 7399            EditPredictionPreview::Active { .. }
 7400        )
 7401    }
 7402
 7403    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7404        let cursor = self.selections.newest_anchor().head();
 7405        if let Some((buffer, cursor_position)) =
 7406            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7407        {
 7408            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7409        } else {
 7410            false
 7411        }
 7412    }
 7413
 7414    pub fn supports_minimap(&self, cx: &App) -> bool {
 7415        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7416    }
 7417
 7418    fn edit_predictions_enabled_in_buffer(
 7419        &self,
 7420        buffer: &Entity<Buffer>,
 7421        buffer_position: language::Anchor,
 7422        cx: &App,
 7423    ) -> bool {
 7424        maybe!({
 7425            if self.read_only(cx) {
 7426                return Some(false);
 7427            }
 7428            let provider = self.edit_prediction_provider()?;
 7429            if !provider.is_enabled(buffer, buffer_position, cx) {
 7430                return Some(false);
 7431            }
 7432            let buffer = buffer.read(cx);
 7433            let Some(file) = buffer.file() else {
 7434                return Some(true);
 7435            };
 7436            let settings = all_language_settings(Some(file), cx);
 7437            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7438        })
 7439        .unwrap_or(false)
 7440    }
 7441
 7442    fn cycle_edit_prediction(
 7443        &mut self,
 7444        direction: Direction,
 7445        window: &mut Window,
 7446        cx: &mut Context<Self>,
 7447    ) -> Option<()> {
 7448        let provider = self.edit_prediction_provider()?;
 7449        let cursor = self.selections.newest_anchor().head();
 7450        let (buffer, cursor_buffer_position) =
 7451            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7452        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7453            return None;
 7454        }
 7455
 7456        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7457        self.update_visible_edit_prediction(window, cx);
 7458
 7459        Some(())
 7460    }
 7461
 7462    pub fn show_edit_prediction(
 7463        &mut self,
 7464        _: &ShowEditPrediction,
 7465        window: &mut Window,
 7466        cx: &mut Context<Self>,
 7467    ) {
 7468        if !self.has_active_edit_prediction() {
 7469            self.refresh_edit_prediction(false, true, window, cx);
 7470            return;
 7471        }
 7472
 7473        self.update_visible_edit_prediction(window, cx);
 7474    }
 7475
 7476    pub fn display_cursor_names(
 7477        &mut self,
 7478        _: &DisplayCursorNames,
 7479        window: &mut Window,
 7480        cx: &mut Context<Self>,
 7481    ) {
 7482        self.show_cursor_names(window, cx);
 7483    }
 7484
 7485    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7486        self.show_cursor_names = true;
 7487        cx.notify();
 7488        cx.spawn_in(window, async move |this, cx| {
 7489            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7490            this.update(cx, |this, cx| {
 7491                this.show_cursor_names = false;
 7492                cx.notify()
 7493            })
 7494            .ok()
 7495        })
 7496        .detach();
 7497    }
 7498
 7499    pub fn next_edit_prediction(
 7500        &mut self,
 7501        _: &NextEditPrediction,
 7502        window: &mut Window,
 7503        cx: &mut Context<Self>,
 7504    ) {
 7505        if self.has_active_edit_prediction() {
 7506            self.cycle_edit_prediction(Direction::Next, window, cx);
 7507        } else {
 7508            let is_copilot_disabled = self
 7509                .refresh_edit_prediction(false, true, window, cx)
 7510                .is_none();
 7511            if is_copilot_disabled {
 7512                cx.propagate();
 7513            }
 7514        }
 7515    }
 7516
 7517    pub fn previous_edit_prediction(
 7518        &mut self,
 7519        _: &PreviousEditPrediction,
 7520        window: &mut Window,
 7521        cx: &mut Context<Self>,
 7522    ) {
 7523        if self.has_active_edit_prediction() {
 7524            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7525        } else {
 7526            let is_copilot_disabled = self
 7527                .refresh_edit_prediction(false, true, window, cx)
 7528                .is_none();
 7529            if is_copilot_disabled {
 7530                cx.propagate();
 7531            }
 7532        }
 7533    }
 7534
 7535    pub fn accept_edit_prediction(
 7536        &mut self,
 7537        _: &AcceptEditPrediction,
 7538        window: &mut Window,
 7539        cx: &mut Context<Self>,
 7540    ) {
 7541        if self.show_edit_predictions_in_menu() {
 7542            self.hide_context_menu(window, cx);
 7543        }
 7544
 7545        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7546            return;
 7547        };
 7548
 7549        match &active_edit_prediction.completion {
 7550            EditPrediction::MoveWithin { target, .. } => {
 7551                let target = *target;
 7552
 7553                if let Some(position_map) = &self.last_position_map {
 7554                    if position_map
 7555                        .visible_row_range
 7556                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7557                        || !self.edit_prediction_requires_modifier()
 7558                    {
 7559                        self.unfold_ranges(&[target..target], true, false, cx);
 7560                        // Note that this is also done in vim's handler of the Tab action.
 7561                        self.change_selections(
 7562                            SelectionEffects::scroll(Autoscroll::newest()),
 7563                            window,
 7564                            cx,
 7565                            |selections| {
 7566                                selections.select_anchor_ranges([target..target]);
 7567                            },
 7568                        );
 7569                        self.clear_row_highlights::<EditPredictionPreview>();
 7570
 7571                        self.edit_prediction_preview
 7572                            .set_previous_scroll_position(None);
 7573                    } else {
 7574                        self.edit_prediction_preview
 7575                            .set_previous_scroll_position(Some(
 7576                                position_map.snapshot.scroll_anchor,
 7577                            ));
 7578
 7579                        self.highlight_rows::<EditPredictionPreview>(
 7580                            target..target,
 7581                            cx.theme().colors().editor_highlighted_line_background,
 7582                            RowHighlightOptions {
 7583                                autoscroll: true,
 7584                                ..Default::default()
 7585                            },
 7586                            cx,
 7587                        );
 7588                        self.request_autoscroll(Autoscroll::fit(), cx);
 7589                    }
 7590                }
 7591            }
 7592            EditPrediction::MoveOutside { snapshot, target } => {
 7593                if let Some(workspace) = self.workspace() {
 7594                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7595                        .detach_and_log_err(cx);
 7596                }
 7597            }
 7598            EditPrediction::Edit { edits, .. } => {
 7599                self.report_edit_prediction_event(
 7600                    active_edit_prediction.completion_id.clone(),
 7601                    true,
 7602                    cx,
 7603                );
 7604
 7605                if let Some(provider) = self.edit_prediction_provider() {
 7606                    provider.accept(cx);
 7607                }
 7608
 7609                // Store the transaction ID and selections before applying the edit
 7610                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7611
 7612                let snapshot = self.buffer.read(cx).snapshot(cx);
 7613                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7614
 7615                self.buffer.update(cx, |buffer, cx| {
 7616                    buffer.edit(edits.iter().cloned(), None, cx)
 7617                });
 7618
 7619                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7620                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7621                });
 7622
 7623                let selections = self.selections.disjoint_anchors_arc();
 7624                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7625                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7626                    if has_new_transaction {
 7627                        self.selection_history
 7628                            .insert_transaction(transaction_id_now, selections);
 7629                    }
 7630                }
 7631
 7632                self.update_visible_edit_prediction(window, cx);
 7633                if self.active_edit_prediction.is_none() {
 7634                    self.refresh_edit_prediction(true, true, window, cx);
 7635                }
 7636
 7637                cx.notify();
 7638            }
 7639        }
 7640
 7641        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7642    }
 7643
 7644    pub fn accept_partial_edit_prediction(
 7645        &mut self,
 7646        _: &AcceptPartialEditPrediction,
 7647        window: &mut Window,
 7648        cx: &mut Context<Self>,
 7649    ) {
 7650        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7651            return;
 7652        };
 7653        if self.selections.count() != 1 {
 7654            return;
 7655        }
 7656
 7657        match &active_edit_prediction.completion {
 7658            EditPrediction::MoveWithin { target, .. } => {
 7659                let target = *target;
 7660                self.change_selections(
 7661                    SelectionEffects::scroll(Autoscroll::newest()),
 7662                    window,
 7663                    cx,
 7664                    |selections| {
 7665                        selections.select_anchor_ranges([target..target]);
 7666                    },
 7667                );
 7668            }
 7669            EditPrediction::MoveOutside { snapshot, target } => {
 7670                if let Some(workspace) = self.workspace() {
 7671                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7672                        .detach_and_log_err(cx);
 7673                }
 7674            }
 7675            EditPrediction::Edit { edits, .. } => {
 7676                self.report_edit_prediction_event(
 7677                    active_edit_prediction.completion_id.clone(),
 7678                    true,
 7679                    cx,
 7680                );
 7681
 7682                // Find an insertion that starts at the cursor position.
 7683                let snapshot = self.buffer.read(cx).snapshot(cx);
 7684                let cursor_offset = self
 7685                    .selections
 7686                    .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7687                    .head();
 7688                let insertion = edits.iter().find_map(|(range, text)| {
 7689                    let range = range.to_offset(&snapshot);
 7690                    if range.is_empty() && range.start == cursor_offset {
 7691                        Some(text)
 7692                    } else {
 7693                        None
 7694                    }
 7695                });
 7696
 7697                if let Some(text) = insertion {
 7698                    let mut partial_completion = text
 7699                        .chars()
 7700                        .by_ref()
 7701                        .take_while(|c| c.is_alphabetic())
 7702                        .collect::<String>();
 7703                    if partial_completion.is_empty() {
 7704                        partial_completion = text
 7705                            .chars()
 7706                            .by_ref()
 7707                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7708                            .collect::<String>();
 7709                    }
 7710
 7711                    cx.emit(EditorEvent::InputHandled {
 7712                        utf16_range_to_replace: None,
 7713                        text: partial_completion.clone().into(),
 7714                    });
 7715
 7716                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7717
 7718                    self.refresh_edit_prediction(true, true, window, cx);
 7719                    cx.notify();
 7720                } else {
 7721                    self.accept_edit_prediction(&Default::default(), window, cx);
 7722                }
 7723            }
 7724        }
 7725    }
 7726
 7727    fn discard_edit_prediction(
 7728        &mut self,
 7729        should_report_edit_prediction_event: bool,
 7730        cx: &mut Context<Self>,
 7731    ) -> bool {
 7732        if should_report_edit_prediction_event {
 7733            let completion_id = self
 7734                .active_edit_prediction
 7735                .as_ref()
 7736                .and_then(|active_completion| active_completion.completion_id.clone());
 7737
 7738            self.report_edit_prediction_event(completion_id, false, cx);
 7739        }
 7740
 7741        if let Some(provider) = self.edit_prediction_provider() {
 7742            provider.discard(cx);
 7743        }
 7744
 7745        self.take_active_edit_prediction(cx)
 7746    }
 7747
 7748    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7749        let Some(provider) = self.edit_prediction_provider() else {
 7750            return;
 7751        };
 7752
 7753        let Some((_, buffer, _)) = self
 7754            .buffer
 7755            .read(cx)
 7756            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7757        else {
 7758            return;
 7759        };
 7760
 7761        let extension = buffer
 7762            .read(cx)
 7763            .file()
 7764            .and_then(|file| Some(file.path().extension()?.to_string()));
 7765
 7766        let event_type = match accepted {
 7767            true => "Edit Prediction Accepted",
 7768            false => "Edit Prediction Discarded",
 7769        };
 7770        telemetry::event!(
 7771            event_type,
 7772            provider = provider.name(),
 7773            prediction_id = id,
 7774            suggestion_accepted = accepted,
 7775            file_extension = extension,
 7776        );
 7777    }
 7778
 7779    fn open_editor_at_anchor(
 7780        snapshot: &language::BufferSnapshot,
 7781        target: language::Anchor,
 7782        workspace: &Entity<Workspace>,
 7783        window: &mut Window,
 7784        cx: &mut App,
 7785    ) -> Task<Result<()>> {
 7786        workspace.update(cx, |workspace, cx| {
 7787            let path = snapshot.file().map(|file| file.full_path(cx));
 7788            let Some(path) =
 7789                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7790            else {
 7791                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7792            };
 7793            let target = text::ToPoint::to_point(&target, snapshot);
 7794            let item = workspace.open_path(path, None, true, window, cx);
 7795            window.spawn(cx, async move |cx| {
 7796                let Some(editor) = item.await?.downcast::<Editor>() else {
 7797                    return Ok(());
 7798                };
 7799                editor
 7800                    .update_in(cx, |editor, window, cx| {
 7801                        editor.go_to_singleton_buffer_point(target, window, cx);
 7802                    })
 7803                    .ok();
 7804                anyhow::Ok(())
 7805            })
 7806        })
 7807    }
 7808
 7809    pub fn has_active_edit_prediction(&self) -> bool {
 7810        self.active_edit_prediction.is_some()
 7811    }
 7812
 7813    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7814        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7815            return false;
 7816        };
 7817
 7818        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7819        self.clear_highlights::<EditPredictionHighlight>(cx);
 7820        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7821        true
 7822    }
 7823
 7824    /// Returns true when we're displaying the edit prediction popover below the cursor
 7825    /// like we are not previewing and the LSP autocomplete menu is visible
 7826    /// or we are in `when_holding_modifier` mode.
 7827    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7828        if self.edit_prediction_preview_is_active()
 7829            || !self.show_edit_predictions_in_menu()
 7830            || !self.edit_predictions_enabled()
 7831        {
 7832            return false;
 7833        }
 7834
 7835        if self.has_visible_completions_menu() {
 7836            return true;
 7837        }
 7838
 7839        has_completion && self.edit_prediction_requires_modifier()
 7840    }
 7841
 7842    fn handle_modifiers_changed(
 7843        &mut self,
 7844        modifiers: Modifiers,
 7845        position_map: &PositionMap,
 7846        window: &mut Window,
 7847        cx: &mut Context<Self>,
 7848    ) {
 7849        // Ensure that the edit prediction preview is updated, even when not
 7850        // enabled, if there's an active edit prediction preview.
 7851        if self.show_edit_predictions_in_menu()
 7852            || matches!(
 7853                self.edit_prediction_preview,
 7854                EditPredictionPreview::Active { .. }
 7855            )
 7856        {
 7857            self.update_edit_prediction_preview(&modifiers, window, cx);
 7858        }
 7859
 7860        self.update_selection_mode(&modifiers, position_map, window, cx);
 7861
 7862        let mouse_position = window.mouse_position();
 7863        if !position_map.text_hitbox.is_hovered(window) {
 7864            return;
 7865        }
 7866
 7867        self.update_hovered_link(
 7868            position_map.point_for_position(mouse_position),
 7869            &position_map.snapshot,
 7870            modifiers,
 7871            window,
 7872            cx,
 7873        )
 7874    }
 7875
 7876    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7877        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7878            MultiCursorModifier::Alt => modifiers.secondary(),
 7879            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7880        }
 7881    }
 7882
 7883    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7884        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7885            MultiCursorModifier::Alt => modifiers.alt,
 7886            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7887        }
 7888    }
 7889
 7890    fn columnar_selection_mode(
 7891        modifiers: &Modifiers,
 7892        cx: &mut Context<Self>,
 7893    ) -> Option<ColumnarMode> {
 7894        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7895            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7896                Some(ColumnarMode::FromMouse)
 7897            } else if Self::is_alt_pressed(modifiers, cx) {
 7898                Some(ColumnarMode::FromSelection)
 7899            } else {
 7900                None
 7901            }
 7902        } else {
 7903            None
 7904        }
 7905    }
 7906
 7907    fn update_selection_mode(
 7908        &mut self,
 7909        modifiers: &Modifiers,
 7910        position_map: &PositionMap,
 7911        window: &mut Window,
 7912        cx: &mut Context<Self>,
 7913    ) {
 7914        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7915            return;
 7916        };
 7917        if self.selections.pending_anchor().is_none() {
 7918            return;
 7919        }
 7920
 7921        let mouse_position = window.mouse_position();
 7922        let point_for_position = position_map.point_for_position(mouse_position);
 7923        let position = point_for_position.previous_valid;
 7924
 7925        self.select(
 7926            SelectPhase::BeginColumnar {
 7927                position,
 7928                reset: false,
 7929                mode,
 7930                goal_column: point_for_position.exact_unclipped.column(),
 7931            },
 7932            window,
 7933            cx,
 7934        );
 7935    }
 7936
 7937    fn update_edit_prediction_preview(
 7938        &mut self,
 7939        modifiers: &Modifiers,
 7940        window: &mut Window,
 7941        cx: &mut Context<Self>,
 7942    ) {
 7943        let mut modifiers_held = false;
 7944        if let Some(accept_keystroke) = self
 7945            .accept_edit_prediction_keybind(false, window, cx)
 7946            .keystroke()
 7947        {
 7948            modifiers_held = modifiers_held
 7949                || (accept_keystroke.modifiers() == modifiers
 7950                    && accept_keystroke.modifiers().modified());
 7951        };
 7952        if let Some(accept_partial_keystroke) = self
 7953            .accept_edit_prediction_keybind(true, window, cx)
 7954            .keystroke()
 7955        {
 7956            modifiers_held = modifiers_held
 7957                || (accept_partial_keystroke.modifiers() == modifiers
 7958                    && accept_partial_keystroke.modifiers().modified());
 7959        }
 7960
 7961        if modifiers_held {
 7962            if matches!(
 7963                self.edit_prediction_preview,
 7964                EditPredictionPreview::Inactive { .. }
 7965            ) {
 7966                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 7967                    provider.provider.did_show(cx)
 7968                }
 7969
 7970                self.edit_prediction_preview = EditPredictionPreview::Active {
 7971                    previous_scroll_position: None,
 7972                    since: Instant::now(),
 7973                };
 7974
 7975                self.update_visible_edit_prediction(window, cx);
 7976                cx.notify();
 7977            }
 7978        } else if let EditPredictionPreview::Active {
 7979            previous_scroll_position,
 7980            since,
 7981        } = self.edit_prediction_preview
 7982        {
 7983            if let (Some(previous_scroll_position), Some(position_map)) =
 7984                (previous_scroll_position, self.last_position_map.as_ref())
 7985            {
 7986                self.set_scroll_position(
 7987                    previous_scroll_position
 7988                        .scroll_position(&position_map.snapshot.display_snapshot),
 7989                    window,
 7990                    cx,
 7991                );
 7992            }
 7993
 7994            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7995                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7996            };
 7997            self.clear_row_highlights::<EditPredictionPreview>();
 7998            self.update_visible_edit_prediction(window, cx);
 7999            cx.notify();
 8000        }
 8001    }
 8002
 8003    fn update_visible_edit_prediction(
 8004        &mut self,
 8005        _window: &mut Window,
 8006        cx: &mut Context<Self>,
 8007    ) -> Option<()> {
 8008        if DisableAiSettings::get_global(cx).disable_ai {
 8009            return None;
 8010        }
 8011
 8012        if self.ime_transaction.is_some() {
 8013            self.discard_edit_prediction(false, cx);
 8014            return None;
 8015        }
 8016
 8017        let selection = self.selections.newest_anchor();
 8018        let cursor = selection.head();
 8019        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8020        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8021        let excerpt_id = cursor.excerpt_id;
 8022
 8023        let show_in_menu = self.show_edit_predictions_in_menu();
 8024        let completions_menu_has_precedence = !show_in_menu
 8025            && (self.context_menu.borrow().is_some()
 8026                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8027
 8028        if completions_menu_has_precedence
 8029            || !offset_selection.is_empty()
 8030            || self
 8031                .active_edit_prediction
 8032                .as_ref()
 8033                .is_some_and(|completion| {
 8034                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8035                        return false;
 8036                    };
 8037                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8038                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8039                    !invalidation_range.contains(&offset_selection.head())
 8040                })
 8041        {
 8042            self.discard_edit_prediction(false, cx);
 8043            return None;
 8044        }
 8045
 8046        self.take_active_edit_prediction(cx);
 8047        let Some(provider) = self.edit_prediction_provider() else {
 8048            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8049            return None;
 8050        };
 8051
 8052        let (buffer, cursor_buffer_position) =
 8053            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8054
 8055        self.edit_prediction_settings =
 8056            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8057
 8058        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8059
 8060        if self.edit_prediction_indent_conflict {
 8061            let cursor_point = cursor.to_point(&multibuffer);
 8062
 8063            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 8064
 8065            if let Some((_, indent)) = indents.iter().next()
 8066                && indent.len == cursor_point.column
 8067            {
 8068                self.edit_prediction_indent_conflict = false;
 8069            }
 8070        }
 8071
 8072        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8073
 8074        let (completion_id, edits, edit_preview) = match edit_prediction {
 8075            edit_prediction::EditPrediction::Local {
 8076                id,
 8077                edits,
 8078                edit_preview,
 8079            } => (id, edits, edit_preview),
 8080            edit_prediction::EditPrediction::Jump {
 8081                id,
 8082                snapshot,
 8083                target,
 8084            } => {
 8085                self.stale_edit_prediction_in_menu = None;
 8086                self.active_edit_prediction = Some(EditPredictionState {
 8087                    inlay_ids: vec![],
 8088                    completion: EditPrediction::MoveOutside { snapshot, target },
 8089                    completion_id: id,
 8090                    invalidation_range: None,
 8091                });
 8092                cx.notify();
 8093                return Some(());
 8094            }
 8095        };
 8096
 8097        let edits = edits
 8098            .into_iter()
 8099            .flat_map(|(range, new_text)| {
 8100                Some((
 8101                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8102                    new_text,
 8103                ))
 8104            })
 8105            .collect::<Vec<_>>();
 8106        if edits.is_empty() {
 8107            return None;
 8108        }
 8109
 8110        let first_edit_start = edits.first().unwrap().0.start;
 8111        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8112        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8113
 8114        let last_edit_end = edits.last().unwrap().0.end;
 8115        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8116        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8117
 8118        let cursor_row = cursor.to_point(&multibuffer).row;
 8119
 8120        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8121
 8122        let mut inlay_ids = Vec::new();
 8123        let invalidation_row_range;
 8124        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8125            Some(cursor_row..edit_end_row)
 8126        } else if cursor_row > edit_end_row {
 8127            Some(edit_start_row..cursor_row)
 8128        } else {
 8129            None
 8130        };
 8131        let supports_jump = self
 8132            .edit_prediction_provider
 8133            .as_ref()
 8134            .map(|provider| provider.provider.supports_jump_to_edit())
 8135            .unwrap_or(true);
 8136
 8137        let is_move = supports_jump
 8138            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8139        let completion = if is_move {
 8140            invalidation_row_range =
 8141                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8142            let target = first_edit_start;
 8143            EditPrediction::MoveWithin { target, snapshot }
 8144        } else {
 8145            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8146                && !self.edit_predictions_hidden_for_vim_mode;
 8147
 8148            if show_completions_in_buffer {
 8149                if let Some(provider) = &self.edit_prediction_provider {
 8150                    provider.provider.did_show(cx);
 8151                }
 8152                if edits
 8153                    .iter()
 8154                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8155                {
 8156                    let mut inlays = Vec::new();
 8157                    for (range, new_text) in &edits {
 8158                        let inlay = Inlay::edit_prediction(
 8159                            post_inc(&mut self.next_inlay_id),
 8160                            range.start,
 8161                            new_text.as_ref(),
 8162                        );
 8163                        inlay_ids.push(inlay.id);
 8164                        inlays.push(inlay);
 8165                    }
 8166
 8167                    self.splice_inlays(&[], inlays, cx);
 8168                } else {
 8169                    let background_color = cx.theme().status().deleted_background;
 8170                    self.highlight_text::<EditPredictionHighlight>(
 8171                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8172                        HighlightStyle {
 8173                            background_color: Some(background_color),
 8174                            ..Default::default()
 8175                        },
 8176                        cx,
 8177                    );
 8178                }
 8179            }
 8180
 8181            invalidation_row_range = edit_start_row..edit_end_row;
 8182
 8183            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8184                if provider.show_tab_accept_marker() {
 8185                    EditDisplayMode::TabAccept
 8186                } else {
 8187                    EditDisplayMode::Inline
 8188                }
 8189            } else {
 8190                EditDisplayMode::DiffPopover
 8191            };
 8192
 8193            EditPrediction::Edit {
 8194                edits,
 8195                edit_preview,
 8196                display_mode,
 8197                snapshot,
 8198            }
 8199        };
 8200
 8201        let invalidation_range = multibuffer
 8202            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8203            ..multibuffer.anchor_after(Point::new(
 8204                invalidation_row_range.end,
 8205                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8206            ));
 8207
 8208        self.stale_edit_prediction_in_menu = None;
 8209        self.active_edit_prediction = Some(EditPredictionState {
 8210            inlay_ids,
 8211            completion,
 8212            completion_id,
 8213            invalidation_range: Some(invalidation_range),
 8214        });
 8215
 8216        cx.notify();
 8217
 8218        Some(())
 8219    }
 8220
 8221    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8222        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8223    }
 8224
 8225    fn clear_tasks(&mut self) {
 8226        self.tasks.clear()
 8227    }
 8228
 8229    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8230        if self.tasks.insert(key, value).is_some() {
 8231            // This case should hopefully be rare, but just in case...
 8232            log::error!(
 8233                "multiple different run targets found on a single line, only the last target will be rendered"
 8234            )
 8235        }
 8236    }
 8237
 8238    /// Get all display points of breakpoints that will be rendered within editor
 8239    ///
 8240    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8241    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8242    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8243    fn active_breakpoints(
 8244        &self,
 8245        range: Range<DisplayRow>,
 8246        window: &mut Window,
 8247        cx: &mut Context<Self>,
 8248    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8249        let mut breakpoint_display_points = HashMap::default();
 8250
 8251        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8252            return breakpoint_display_points;
 8253        };
 8254
 8255        let snapshot = self.snapshot(window, cx);
 8256
 8257        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8258        let Some(project) = self.project() else {
 8259            return breakpoint_display_points;
 8260        };
 8261
 8262        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8263            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8264
 8265        for (buffer_snapshot, range, excerpt_id) in
 8266            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8267        {
 8268            let Some(buffer) = project
 8269                .read(cx)
 8270                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8271            else {
 8272                continue;
 8273            };
 8274            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8275                &buffer,
 8276                Some(
 8277                    buffer_snapshot.anchor_before(range.start)
 8278                        ..buffer_snapshot.anchor_after(range.end),
 8279                ),
 8280                buffer_snapshot,
 8281                cx,
 8282            );
 8283            for (breakpoint, state) in breakpoints {
 8284                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8285                let position = multi_buffer_anchor
 8286                    .to_point(&multi_buffer_snapshot)
 8287                    .to_display_point(&snapshot);
 8288
 8289                breakpoint_display_points.insert(
 8290                    position.row(),
 8291                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8292                );
 8293            }
 8294        }
 8295
 8296        breakpoint_display_points
 8297    }
 8298
 8299    fn breakpoint_context_menu(
 8300        &self,
 8301        anchor: Anchor,
 8302        window: &mut Window,
 8303        cx: &mut Context<Self>,
 8304    ) -> Entity<ui::ContextMenu> {
 8305        let weak_editor = cx.weak_entity();
 8306        let focus_handle = self.focus_handle(cx);
 8307
 8308        let row = self
 8309            .buffer
 8310            .read(cx)
 8311            .snapshot(cx)
 8312            .summary_for_anchor::<Point>(&anchor)
 8313            .row;
 8314
 8315        let breakpoint = self
 8316            .breakpoint_at_row(row, window, cx)
 8317            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8318
 8319        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8320            "Edit Log Breakpoint"
 8321        } else {
 8322            "Set Log Breakpoint"
 8323        };
 8324
 8325        let condition_breakpoint_msg = if breakpoint
 8326            .as_ref()
 8327            .is_some_and(|bp| bp.1.condition.is_some())
 8328        {
 8329            "Edit Condition Breakpoint"
 8330        } else {
 8331            "Set Condition Breakpoint"
 8332        };
 8333
 8334        let hit_condition_breakpoint_msg = if breakpoint
 8335            .as_ref()
 8336            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8337        {
 8338            "Edit Hit Condition Breakpoint"
 8339        } else {
 8340            "Set Hit Condition Breakpoint"
 8341        };
 8342
 8343        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8344            "Unset Breakpoint"
 8345        } else {
 8346            "Set Breakpoint"
 8347        };
 8348
 8349        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8350
 8351        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8352            BreakpointState::Enabled => Some("Disable"),
 8353            BreakpointState::Disabled => Some("Enable"),
 8354        });
 8355
 8356        let (anchor, breakpoint) =
 8357            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8358
 8359        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8360            menu.on_blur_subscription(Subscription::new(|| {}))
 8361                .context(focus_handle)
 8362                .when(run_to_cursor, |this| {
 8363                    let weak_editor = weak_editor.clone();
 8364                    this.entry("Run to cursor", None, move |window, cx| {
 8365                        weak_editor
 8366                            .update(cx, |editor, cx| {
 8367                                editor.change_selections(
 8368                                    SelectionEffects::no_scroll(),
 8369                                    window,
 8370                                    cx,
 8371                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8372                                );
 8373                            })
 8374                            .ok();
 8375
 8376                        window.dispatch_action(Box::new(RunToCursor), cx);
 8377                    })
 8378                    .separator()
 8379                })
 8380                .when_some(toggle_state_msg, |this, msg| {
 8381                    this.entry(msg, None, {
 8382                        let weak_editor = weak_editor.clone();
 8383                        let breakpoint = breakpoint.clone();
 8384                        move |_window, cx| {
 8385                            weak_editor
 8386                                .update(cx, |this, cx| {
 8387                                    this.edit_breakpoint_at_anchor(
 8388                                        anchor,
 8389                                        breakpoint.as_ref().clone(),
 8390                                        BreakpointEditAction::InvertState,
 8391                                        cx,
 8392                                    );
 8393                                })
 8394                                .log_err();
 8395                        }
 8396                    })
 8397                })
 8398                .entry(set_breakpoint_msg, None, {
 8399                    let weak_editor = weak_editor.clone();
 8400                    let breakpoint = breakpoint.clone();
 8401                    move |_window, cx| {
 8402                        weak_editor
 8403                            .update(cx, |this, cx| {
 8404                                this.edit_breakpoint_at_anchor(
 8405                                    anchor,
 8406                                    breakpoint.as_ref().clone(),
 8407                                    BreakpointEditAction::Toggle,
 8408                                    cx,
 8409                                );
 8410                            })
 8411                            .log_err();
 8412                    }
 8413                })
 8414                .entry(log_breakpoint_msg, None, {
 8415                    let breakpoint = breakpoint.clone();
 8416                    let weak_editor = weak_editor.clone();
 8417                    move |window, cx| {
 8418                        weak_editor
 8419                            .update(cx, |this, cx| {
 8420                                this.add_edit_breakpoint_block(
 8421                                    anchor,
 8422                                    breakpoint.as_ref(),
 8423                                    BreakpointPromptEditAction::Log,
 8424                                    window,
 8425                                    cx,
 8426                                );
 8427                            })
 8428                            .log_err();
 8429                    }
 8430                })
 8431                .entry(condition_breakpoint_msg, None, {
 8432                    let breakpoint = breakpoint.clone();
 8433                    let weak_editor = weak_editor.clone();
 8434                    move |window, cx| {
 8435                        weak_editor
 8436                            .update(cx, |this, cx| {
 8437                                this.add_edit_breakpoint_block(
 8438                                    anchor,
 8439                                    breakpoint.as_ref(),
 8440                                    BreakpointPromptEditAction::Condition,
 8441                                    window,
 8442                                    cx,
 8443                                );
 8444                            })
 8445                            .log_err();
 8446                    }
 8447                })
 8448                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8449                    weak_editor
 8450                        .update(cx, |this, cx| {
 8451                            this.add_edit_breakpoint_block(
 8452                                anchor,
 8453                                breakpoint.as_ref(),
 8454                                BreakpointPromptEditAction::HitCondition,
 8455                                window,
 8456                                cx,
 8457                            );
 8458                        })
 8459                        .log_err();
 8460                })
 8461        })
 8462    }
 8463
 8464    fn render_breakpoint(
 8465        &self,
 8466        position: Anchor,
 8467        row: DisplayRow,
 8468        breakpoint: &Breakpoint,
 8469        state: Option<BreakpointSessionState>,
 8470        cx: &mut Context<Self>,
 8471    ) -> IconButton {
 8472        let is_rejected = state.is_some_and(|s| !s.verified);
 8473        // Is it a breakpoint that shows up when hovering over gutter?
 8474        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8475            (false, false),
 8476            |PhantomBreakpointIndicator {
 8477                 is_active,
 8478                 display_row,
 8479                 collides_with_existing_breakpoint,
 8480             }| {
 8481                (
 8482                    is_active && display_row == row,
 8483                    collides_with_existing_breakpoint,
 8484                )
 8485            },
 8486        );
 8487
 8488        let (color, icon) = {
 8489            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8490                (false, false) => ui::IconName::DebugBreakpoint,
 8491                (true, false) => ui::IconName::DebugLogBreakpoint,
 8492                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8493                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8494            };
 8495
 8496            let color = cx.theme().colors();
 8497
 8498            let color = if is_phantom {
 8499                if collides_with_existing {
 8500                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8501                } else {
 8502                    Color::Hint
 8503                }
 8504            } else if is_rejected {
 8505                Color::Disabled
 8506            } else {
 8507                Color::Debugger
 8508            };
 8509
 8510            (color, icon)
 8511        };
 8512
 8513        let breakpoint = Arc::from(breakpoint.clone());
 8514
 8515        let alt_as_text = gpui::Keystroke {
 8516            modifiers: Modifiers::secondary_key(),
 8517            ..Default::default()
 8518        };
 8519        let primary_action_text = if breakpoint.is_disabled() {
 8520            "Enable breakpoint"
 8521        } else if is_phantom && !collides_with_existing {
 8522            "Set breakpoint"
 8523        } else {
 8524            "Unset breakpoint"
 8525        };
 8526        let focus_handle = self.focus_handle.clone();
 8527
 8528        let meta = if is_rejected {
 8529            SharedString::from("No executable code is associated with this line.")
 8530        } else if collides_with_existing && !breakpoint.is_disabled() {
 8531            SharedString::from(format!(
 8532                "{alt_as_text}-click to disable,\nright-click for more options."
 8533            ))
 8534        } else {
 8535            SharedString::from("Right-click for more options.")
 8536        };
 8537        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8538            .icon_size(IconSize::XSmall)
 8539            .size(ui::ButtonSize::None)
 8540            .when(is_rejected, |this| {
 8541                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8542            })
 8543            .icon_color(color)
 8544            .style(ButtonStyle::Transparent)
 8545            .on_click(cx.listener({
 8546                move |editor, event: &ClickEvent, window, cx| {
 8547                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8548                        BreakpointEditAction::InvertState
 8549                    } else {
 8550                        BreakpointEditAction::Toggle
 8551                    };
 8552
 8553                    window.focus(&editor.focus_handle(cx));
 8554                    editor.edit_breakpoint_at_anchor(
 8555                        position,
 8556                        breakpoint.as_ref().clone(),
 8557                        edit_action,
 8558                        cx,
 8559                    );
 8560                }
 8561            }))
 8562            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8563                editor.set_breakpoint_context_menu(
 8564                    row,
 8565                    Some(position),
 8566                    event.position(),
 8567                    window,
 8568                    cx,
 8569                );
 8570            }))
 8571            .tooltip(move |_window, cx| {
 8572                Tooltip::with_meta_in(
 8573                    primary_action_text,
 8574                    Some(&ToggleBreakpoint),
 8575                    meta.clone(),
 8576                    &focus_handle,
 8577                    cx,
 8578                )
 8579            })
 8580    }
 8581
 8582    fn build_tasks_context(
 8583        project: &Entity<Project>,
 8584        buffer: &Entity<Buffer>,
 8585        buffer_row: u32,
 8586        tasks: &Arc<RunnableTasks>,
 8587        cx: &mut Context<Self>,
 8588    ) -> Task<Option<task::TaskContext>> {
 8589        let position = Point::new(buffer_row, tasks.column);
 8590        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8591        let location = Location {
 8592            buffer: buffer.clone(),
 8593            range: range_start..range_start,
 8594        };
 8595        // Fill in the environmental variables from the tree-sitter captures
 8596        let mut captured_task_variables = TaskVariables::default();
 8597        for (capture_name, value) in tasks.extra_variables.clone() {
 8598            captured_task_variables.insert(
 8599                task::VariableName::Custom(capture_name.into()),
 8600                value.clone(),
 8601            );
 8602        }
 8603        project.update(cx, |project, cx| {
 8604            project.task_store().update(cx, |task_store, cx| {
 8605                task_store.task_context_for_location(captured_task_variables, location, cx)
 8606            })
 8607        })
 8608    }
 8609
 8610    pub fn spawn_nearest_task(
 8611        &mut self,
 8612        action: &SpawnNearestTask,
 8613        window: &mut Window,
 8614        cx: &mut Context<Self>,
 8615    ) {
 8616        let Some((workspace, _)) = self.workspace.clone() else {
 8617            return;
 8618        };
 8619        let Some(project) = self.project.clone() else {
 8620            return;
 8621        };
 8622
 8623        // Try to find a closest, enclosing node using tree-sitter that has a task
 8624        let Some((buffer, buffer_row, tasks)) = self
 8625            .find_enclosing_node_task(cx)
 8626            // Or find the task that's closest in row-distance.
 8627            .or_else(|| self.find_closest_task(cx))
 8628        else {
 8629            return;
 8630        };
 8631
 8632        let reveal_strategy = action.reveal;
 8633        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8634        cx.spawn_in(window, async move |_, cx| {
 8635            let context = task_context.await?;
 8636            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8637
 8638            let resolved = &mut resolved_task.resolved;
 8639            resolved.reveal = reveal_strategy;
 8640
 8641            workspace
 8642                .update_in(cx, |workspace, window, cx| {
 8643                    workspace.schedule_resolved_task(
 8644                        task_source_kind,
 8645                        resolved_task,
 8646                        false,
 8647                        window,
 8648                        cx,
 8649                    );
 8650                })
 8651                .ok()
 8652        })
 8653        .detach();
 8654    }
 8655
 8656    fn find_closest_task(
 8657        &mut self,
 8658        cx: &mut Context<Self>,
 8659    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8660        let cursor_row = self
 8661            .selections
 8662            .newest_adjusted(&self.display_snapshot(cx))
 8663            .head()
 8664            .row;
 8665
 8666        let ((buffer_id, row), tasks) = self
 8667            .tasks
 8668            .iter()
 8669            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8670
 8671        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8672        let tasks = Arc::new(tasks.to_owned());
 8673        Some((buffer, *row, tasks))
 8674    }
 8675
 8676    fn find_enclosing_node_task(
 8677        &mut self,
 8678        cx: &mut Context<Self>,
 8679    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8680        let snapshot = self.buffer.read(cx).snapshot(cx);
 8681        let offset = self
 8682            .selections
 8683            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8684            .head();
 8685        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8686        let offset = excerpt.map_offset_to_buffer(offset);
 8687        let buffer_id = excerpt.buffer().remote_id();
 8688
 8689        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8690        let mut cursor = layer.node().walk();
 8691
 8692        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8693            if cursor.node().end_byte() == offset.0 {
 8694                cursor.goto_next_sibling();
 8695            }
 8696        }
 8697
 8698        // Ascend to the smallest ancestor that contains the range and has a task.
 8699        loop {
 8700            let node = cursor.node();
 8701            let node_range = node.byte_range();
 8702            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8703
 8704            // Check if this node contains our offset
 8705            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8706                // If it contains offset, check for task
 8707                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8708                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8709                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8710                }
 8711            }
 8712
 8713            if !cursor.goto_parent() {
 8714                break;
 8715            }
 8716        }
 8717        None
 8718    }
 8719
 8720    fn render_run_indicator(
 8721        &self,
 8722        _style: &EditorStyle,
 8723        is_active: bool,
 8724        row: DisplayRow,
 8725        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8726        cx: &mut Context<Self>,
 8727    ) -> IconButton {
 8728        let color = Color::Muted;
 8729        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8730
 8731        IconButton::new(
 8732            ("run_indicator", row.0 as usize),
 8733            ui::IconName::PlayOutlined,
 8734        )
 8735        .shape(ui::IconButtonShape::Square)
 8736        .icon_size(IconSize::XSmall)
 8737        .icon_color(color)
 8738        .toggle_state(is_active)
 8739        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8740            let quick_launch = match e {
 8741                ClickEvent::Keyboard(_) => true,
 8742                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8743            };
 8744
 8745            window.focus(&editor.focus_handle(cx));
 8746            editor.toggle_code_actions(
 8747                &ToggleCodeActions {
 8748                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8749                    quick_launch,
 8750                },
 8751                window,
 8752                cx,
 8753            );
 8754        }))
 8755        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8756            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8757        }))
 8758    }
 8759
 8760    pub fn context_menu_visible(&self) -> bool {
 8761        !self.edit_prediction_preview_is_active()
 8762            && self
 8763                .context_menu
 8764                .borrow()
 8765                .as_ref()
 8766                .is_some_and(|menu| menu.visible())
 8767    }
 8768
 8769    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8770        self.context_menu
 8771            .borrow()
 8772            .as_ref()
 8773            .map(|menu| menu.origin())
 8774    }
 8775
 8776    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8777        self.context_menu_options = Some(options);
 8778    }
 8779
 8780    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8781    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8782
 8783    fn render_edit_prediction_popover(
 8784        &mut self,
 8785        text_bounds: &Bounds<Pixels>,
 8786        content_origin: gpui::Point<Pixels>,
 8787        right_margin: Pixels,
 8788        editor_snapshot: &EditorSnapshot,
 8789        visible_row_range: Range<DisplayRow>,
 8790        scroll_top: ScrollOffset,
 8791        scroll_bottom: ScrollOffset,
 8792        line_layouts: &[LineWithInvisibles],
 8793        line_height: Pixels,
 8794        scroll_position: gpui::Point<ScrollOffset>,
 8795        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8796        newest_selection_head: Option<DisplayPoint>,
 8797        editor_width: Pixels,
 8798        style: &EditorStyle,
 8799        window: &mut Window,
 8800        cx: &mut App,
 8801    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8802        if self.mode().is_minimap() {
 8803            return None;
 8804        }
 8805        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8806
 8807        if self.edit_prediction_visible_in_cursor_popover(true) {
 8808            return None;
 8809        }
 8810
 8811        match &active_edit_prediction.completion {
 8812            EditPrediction::MoveWithin { target, .. } => {
 8813                let target_display_point = target.to_display_point(editor_snapshot);
 8814
 8815                if self.edit_prediction_requires_modifier() {
 8816                    if !self.edit_prediction_preview_is_active() {
 8817                        return None;
 8818                    }
 8819
 8820                    self.render_edit_prediction_modifier_jump_popover(
 8821                        text_bounds,
 8822                        content_origin,
 8823                        visible_row_range,
 8824                        line_layouts,
 8825                        line_height,
 8826                        scroll_pixel_position,
 8827                        newest_selection_head,
 8828                        target_display_point,
 8829                        window,
 8830                        cx,
 8831                    )
 8832                } else {
 8833                    self.render_edit_prediction_eager_jump_popover(
 8834                        text_bounds,
 8835                        content_origin,
 8836                        editor_snapshot,
 8837                        visible_row_range,
 8838                        scroll_top,
 8839                        scroll_bottom,
 8840                        line_height,
 8841                        scroll_pixel_position,
 8842                        target_display_point,
 8843                        editor_width,
 8844                        window,
 8845                        cx,
 8846                    )
 8847                }
 8848            }
 8849            EditPrediction::Edit {
 8850                display_mode: EditDisplayMode::Inline,
 8851                ..
 8852            } => None,
 8853            EditPrediction::Edit {
 8854                display_mode: EditDisplayMode::TabAccept,
 8855                edits,
 8856                ..
 8857            } => {
 8858                let range = &edits.first()?.0;
 8859                let target_display_point = range.end.to_display_point(editor_snapshot);
 8860
 8861                self.render_edit_prediction_end_of_line_popover(
 8862                    "Accept",
 8863                    editor_snapshot,
 8864                    visible_row_range,
 8865                    target_display_point,
 8866                    line_height,
 8867                    scroll_pixel_position,
 8868                    content_origin,
 8869                    editor_width,
 8870                    window,
 8871                    cx,
 8872                )
 8873            }
 8874            EditPrediction::Edit {
 8875                edits,
 8876                edit_preview,
 8877                display_mode: EditDisplayMode::DiffPopover,
 8878                snapshot,
 8879            } => self.render_edit_prediction_diff_popover(
 8880                text_bounds,
 8881                content_origin,
 8882                right_margin,
 8883                editor_snapshot,
 8884                visible_row_range,
 8885                line_layouts,
 8886                line_height,
 8887                scroll_position,
 8888                scroll_pixel_position,
 8889                newest_selection_head,
 8890                editor_width,
 8891                style,
 8892                edits,
 8893                edit_preview,
 8894                snapshot,
 8895                window,
 8896                cx,
 8897            ),
 8898            EditPrediction::MoveOutside { snapshot, .. } => {
 8899                let mut element = self
 8900                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 8901                    .into_any();
 8902
 8903                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8904                let origin_x = text_bounds.size.width - size.width - px(30.);
 8905                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 8906                element.prepaint_at(origin, window, cx);
 8907
 8908                Some((element, origin))
 8909            }
 8910        }
 8911    }
 8912
 8913    fn render_edit_prediction_modifier_jump_popover(
 8914        &mut self,
 8915        text_bounds: &Bounds<Pixels>,
 8916        content_origin: gpui::Point<Pixels>,
 8917        visible_row_range: Range<DisplayRow>,
 8918        line_layouts: &[LineWithInvisibles],
 8919        line_height: Pixels,
 8920        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8921        newest_selection_head: Option<DisplayPoint>,
 8922        target_display_point: DisplayPoint,
 8923        window: &mut Window,
 8924        cx: &mut App,
 8925    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8926        let scrolled_content_origin =
 8927            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8928
 8929        const SCROLL_PADDING_Y: Pixels = px(12.);
 8930
 8931        if target_display_point.row() < visible_row_range.start {
 8932            return self.render_edit_prediction_scroll_popover(
 8933                |_| SCROLL_PADDING_Y,
 8934                IconName::ArrowUp,
 8935                visible_row_range,
 8936                line_layouts,
 8937                newest_selection_head,
 8938                scrolled_content_origin,
 8939                window,
 8940                cx,
 8941            );
 8942        } else if target_display_point.row() >= visible_row_range.end {
 8943            return self.render_edit_prediction_scroll_popover(
 8944                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8945                IconName::ArrowDown,
 8946                visible_row_range,
 8947                line_layouts,
 8948                newest_selection_head,
 8949                scrolled_content_origin,
 8950                window,
 8951                cx,
 8952            );
 8953        }
 8954
 8955        const POLE_WIDTH: Pixels = px(2.);
 8956
 8957        let line_layout =
 8958            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8959        let target_column = target_display_point.column() as usize;
 8960
 8961        let target_x = line_layout.x_for_index(target_column);
 8962        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8963            - scroll_pixel_position.y;
 8964
 8965        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8966
 8967        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8968        border_color.l += 0.001;
 8969
 8970        let mut element = v_flex()
 8971            .items_end()
 8972            .when(flag_on_right, |el| el.items_start())
 8973            .child(if flag_on_right {
 8974                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8975                    .rounded_bl(px(0.))
 8976                    .rounded_tl(px(0.))
 8977                    .border_l_2()
 8978                    .border_color(border_color)
 8979            } else {
 8980                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8981                    .rounded_br(px(0.))
 8982                    .rounded_tr(px(0.))
 8983                    .border_r_2()
 8984                    .border_color(border_color)
 8985            })
 8986            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8987            .into_any();
 8988
 8989        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8990
 8991        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8992            - point(
 8993                if flag_on_right {
 8994                    POLE_WIDTH
 8995                } else {
 8996                    size.width - POLE_WIDTH
 8997                },
 8998                size.height - line_height,
 8999            );
 9000
 9001        origin.x = origin.x.max(content_origin.x);
 9002
 9003        element.prepaint_at(origin, window, cx);
 9004
 9005        Some((element, origin))
 9006    }
 9007
 9008    fn render_edit_prediction_scroll_popover(
 9009        &mut self,
 9010        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9011        scroll_icon: IconName,
 9012        visible_row_range: Range<DisplayRow>,
 9013        line_layouts: &[LineWithInvisibles],
 9014        newest_selection_head: Option<DisplayPoint>,
 9015        scrolled_content_origin: gpui::Point<Pixels>,
 9016        window: &mut Window,
 9017        cx: &mut App,
 9018    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9019        let mut element = self
 9020            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9021            .into_any();
 9022
 9023        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9024
 9025        let cursor = newest_selection_head?;
 9026        let cursor_row_layout =
 9027            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9028        let cursor_column = cursor.column() as usize;
 9029
 9030        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9031
 9032        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9033
 9034        element.prepaint_at(origin, window, cx);
 9035        Some((element, origin))
 9036    }
 9037
 9038    fn render_edit_prediction_eager_jump_popover(
 9039        &mut self,
 9040        text_bounds: &Bounds<Pixels>,
 9041        content_origin: gpui::Point<Pixels>,
 9042        editor_snapshot: &EditorSnapshot,
 9043        visible_row_range: Range<DisplayRow>,
 9044        scroll_top: ScrollOffset,
 9045        scroll_bottom: ScrollOffset,
 9046        line_height: Pixels,
 9047        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9048        target_display_point: DisplayPoint,
 9049        editor_width: Pixels,
 9050        window: &mut Window,
 9051        cx: &mut App,
 9052    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9053        if target_display_point.row().as_f64() < scroll_top {
 9054            let mut element = self
 9055                .render_edit_prediction_line_popover(
 9056                    "Jump to Edit",
 9057                    Some(IconName::ArrowUp),
 9058                    window,
 9059                    cx,
 9060                )
 9061                .into_any();
 9062
 9063            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9064            let offset = point(
 9065                (text_bounds.size.width - size.width) / 2.,
 9066                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9067            );
 9068
 9069            let origin = text_bounds.origin + offset;
 9070            element.prepaint_at(origin, window, cx);
 9071            Some((element, origin))
 9072        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9073            let mut element = self
 9074                .render_edit_prediction_line_popover(
 9075                    "Jump to Edit",
 9076                    Some(IconName::ArrowDown),
 9077                    window,
 9078                    cx,
 9079                )
 9080                .into_any();
 9081
 9082            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9083            let offset = point(
 9084                (text_bounds.size.width - size.width) / 2.,
 9085                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9086            );
 9087
 9088            let origin = text_bounds.origin + offset;
 9089            element.prepaint_at(origin, window, cx);
 9090            Some((element, origin))
 9091        } else {
 9092            self.render_edit_prediction_end_of_line_popover(
 9093                "Jump to Edit",
 9094                editor_snapshot,
 9095                visible_row_range,
 9096                target_display_point,
 9097                line_height,
 9098                scroll_pixel_position,
 9099                content_origin,
 9100                editor_width,
 9101                window,
 9102                cx,
 9103            )
 9104        }
 9105    }
 9106
 9107    fn render_edit_prediction_end_of_line_popover(
 9108        self: &mut Editor,
 9109        label: &'static str,
 9110        editor_snapshot: &EditorSnapshot,
 9111        visible_row_range: Range<DisplayRow>,
 9112        target_display_point: DisplayPoint,
 9113        line_height: Pixels,
 9114        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9115        content_origin: gpui::Point<Pixels>,
 9116        editor_width: Pixels,
 9117        window: &mut Window,
 9118        cx: &mut App,
 9119    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9120        let target_line_end = DisplayPoint::new(
 9121            target_display_point.row(),
 9122            editor_snapshot.line_len(target_display_point.row()),
 9123        );
 9124
 9125        let mut element = self
 9126            .render_edit_prediction_line_popover(label, None, window, cx)
 9127            .into_any();
 9128
 9129        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9130
 9131        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9132
 9133        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9134        let mut origin = start_point
 9135            + line_origin
 9136            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9137        origin.x = origin.x.max(content_origin.x);
 9138
 9139        let max_x = content_origin.x + editor_width - size.width;
 9140
 9141        if origin.x > max_x {
 9142            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9143
 9144            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9145                origin.y += offset;
 9146                IconName::ArrowUp
 9147            } else {
 9148                origin.y -= offset;
 9149                IconName::ArrowDown
 9150            };
 9151
 9152            element = self
 9153                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9154                .into_any();
 9155
 9156            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9157
 9158            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9159        }
 9160
 9161        element.prepaint_at(origin, window, cx);
 9162        Some((element, origin))
 9163    }
 9164
 9165    fn render_edit_prediction_diff_popover(
 9166        self: &Editor,
 9167        text_bounds: &Bounds<Pixels>,
 9168        content_origin: gpui::Point<Pixels>,
 9169        right_margin: Pixels,
 9170        editor_snapshot: &EditorSnapshot,
 9171        visible_row_range: Range<DisplayRow>,
 9172        line_layouts: &[LineWithInvisibles],
 9173        line_height: Pixels,
 9174        scroll_position: gpui::Point<ScrollOffset>,
 9175        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9176        newest_selection_head: Option<DisplayPoint>,
 9177        editor_width: Pixels,
 9178        style: &EditorStyle,
 9179        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9180        edit_preview: &Option<language::EditPreview>,
 9181        snapshot: &language::BufferSnapshot,
 9182        window: &mut Window,
 9183        cx: &mut App,
 9184    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9185        let edit_start = edits
 9186            .first()
 9187            .unwrap()
 9188            .0
 9189            .start
 9190            .to_display_point(editor_snapshot);
 9191        let edit_end = edits
 9192            .last()
 9193            .unwrap()
 9194            .0
 9195            .end
 9196            .to_display_point(editor_snapshot);
 9197
 9198        let is_visible = visible_row_range.contains(&edit_start.row())
 9199            || visible_row_range.contains(&edit_end.row());
 9200        if !is_visible {
 9201            return None;
 9202        }
 9203
 9204        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9205            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9206        } else {
 9207            // Fallback for providers without edit_preview
 9208            crate::edit_prediction_fallback_text(edits, cx)
 9209        };
 9210
 9211        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9212        let line_count = highlighted_edits.text.lines().count();
 9213
 9214        const BORDER_WIDTH: Pixels = px(1.);
 9215
 9216        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9217        let has_keybind = keybind.is_some();
 9218
 9219        let mut element = h_flex()
 9220            .items_start()
 9221            .child(
 9222                h_flex()
 9223                    .bg(cx.theme().colors().editor_background)
 9224                    .border(BORDER_WIDTH)
 9225                    .shadow_xs()
 9226                    .border_color(cx.theme().colors().border)
 9227                    .rounded_l_lg()
 9228                    .when(line_count > 1, |el| el.rounded_br_lg())
 9229                    .pr_1()
 9230                    .child(styled_text),
 9231            )
 9232            .child(
 9233                h_flex()
 9234                    .h(line_height + BORDER_WIDTH * 2.)
 9235                    .px_1p5()
 9236                    .gap_1()
 9237                    // Workaround: For some reason, there's a gap if we don't do this
 9238                    .ml(-BORDER_WIDTH)
 9239                    .shadow(vec![gpui::BoxShadow {
 9240                        color: gpui::black().opacity(0.05),
 9241                        offset: point(px(1.), px(1.)),
 9242                        blur_radius: px(2.),
 9243                        spread_radius: px(0.),
 9244                    }])
 9245                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9246                    .border(BORDER_WIDTH)
 9247                    .border_color(cx.theme().colors().border)
 9248                    .rounded_r_lg()
 9249                    .id("edit_prediction_diff_popover_keybind")
 9250                    .when(!has_keybind, |el| {
 9251                        let status_colors = cx.theme().status();
 9252
 9253                        el.bg(status_colors.error_background)
 9254                            .border_color(status_colors.error.opacity(0.6))
 9255                            .child(Icon::new(IconName::Info).color(Color::Error))
 9256                            .cursor_default()
 9257                            .hoverable_tooltip(move |_window, cx| {
 9258                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9259                            })
 9260                    })
 9261                    .children(keybind),
 9262            )
 9263            .into_any();
 9264
 9265        let longest_row =
 9266            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9267        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9268            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9269        } else {
 9270            layout_line(
 9271                longest_row,
 9272                editor_snapshot,
 9273                style,
 9274                editor_width,
 9275                |_| false,
 9276                window,
 9277                cx,
 9278            )
 9279            .width
 9280        };
 9281
 9282        let viewport_bounds =
 9283            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9284                right: -right_margin,
 9285                ..Default::default()
 9286            });
 9287
 9288        let x_after_longest = Pixels::from(
 9289            ScrollPixelOffset::from(
 9290                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9291            ) - scroll_pixel_position.x,
 9292        );
 9293
 9294        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9295
 9296        // Fully visible if it can be displayed within the window (allow overlapping other
 9297        // panes). However, this is only allowed if the popover starts within text_bounds.
 9298        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9299            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9300
 9301        let mut origin = if can_position_to_the_right {
 9302            point(
 9303                x_after_longest,
 9304                text_bounds.origin.y
 9305                    + Pixels::from(
 9306                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9307                            - scroll_pixel_position.y,
 9308                    ),
 9309            )
 9310        } else {
 9311            let cursor_row = newest_selection_head.map(|head| head.row());
 9312            let above_edit = edit_start
 9313                .row()
 9314                .0
 9315                .checked_sub(line_count as u32)
 9316                .map(DisplayRow);
 9317            let below_edit = Some(edit_end.row() + 1);
 9318            let above_cursor =
 9319                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9320            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9321
 9322            // Place the edit popover adjacent to the edit if there is a location
 9323            // available that is onscreen and does not obscure the cursor. Otherwise,
 9324            // place it adjacent to the cursor.
 9325            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9326                .into_iter()
 9327                .flatten()
 9328                .find(|&start_row| {
 9329                    let end_row = start_row + line_count as u32;
 9330                    visible_row_range.contains(&start_row)
 9331                        && visible_row_range.contains(&end_row)
 9332                        && cursor_row
 9333                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9334                })?;
 9335
 9336            content_origin
 9337                + point(
 9338                    Pixels::from(-scroll_pixel_position.x),
 9339                    Pixels::from(
 9340                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9341                    ),
 9342                )
 9343        };
 9344
 9345        origin.x -= BORDER_WIDTH;
 9346
 9347        window.defer_draw(element, origin, 1);
 9348
 9349        // Do not return an element, since it will already be drawn due to defer_draw.
 9350        None
 9351    }
 9352
 9353    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9354        px(30.)
 9355    }
 9356
 9357    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9358        if self.read_only(cx) {
 9359            cx.theme().players().read_only()
 9360        } else {
 9361            self.style.as_ref().unwrap().local_player
 9362        }
 9363    }
 9364
 9365    fn render_edit_prediction_accept_keybind(
 9366        &self,
 9367        window: &mut Window,
 9368        cx: &mut App,
 9369    ) -> Option<AnyElement> {
 9370        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9371        let accept_keystroke = accept_binding.keystroke()?;
 9372
 9373        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9374
 9375        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9376            Color::Accent
 9377        } else {
 9378            Color::Muted
 9379        };
 9380
 9381        h_flex()
 9382            .px_0p5()
 9383            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9384            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9385            .text_size(TextSize::XSmall.rems(cx))
 9386            .child(h_flex().children(ui::render_modifiers(
 9387                accept_keystroke.modifiers(),
 9388                PlatformStyle::platform(),
 9389                Some(modifiers_color),
 9390                Some(IconSize::XSmall.rems().into()),
 9391                true,
 9392            )))
 9393            .when(is_platform_style_mac, |parent| {
 9394                parent.child(accept_keystroke.key().to_string())
 9395            })
 9396            .when(!is_platform_style_mac, |parent| {
 9397                parent.child(
 9398                    Key::new(
 9399                        util::capitalize(accept_keystroke.key()),
 9400                        Some(Color::Default),
 9401                    )
 9402                    .size(Some(IconSize::XSmall.rems().into())),
 9403                )
 9404            })
 9405            .into_any()
 9406            .into()
 9407    }
 9408
 9409    fn render_edit_prediction_line_popover(
 9410        &self,
 9411        label: impl Into<SharedString>,
 9412        icon: Option<IconName>,
 9413        window: &mut Window,
 9414        cx: &mut App,
 9415    ) -> Stateful<Div> {
 9416        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9417
 9418        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9419        let has_keybind = keybind.is_some();
 9420
 9421        h_flex()
 9422            .id("ep-line-popover")
 9423            .py_0p5()
 9424            .pl_1()
 9425            .pr(padding_right)
 9426            .gap_1()
 9427            .rounded_md()
 9428            .border_1()
 9429            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9430            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9431            .shadow_xs()
 9432            .when(!has_keybind, |el| {
 9433                let status_colors = cx.theme().status();
 9434
 9435                el.bg(status_colors.error_background)
 9436                    .border_color(status_colors.error.opacity(0.6))
 9437                    .pl_2()
 9438                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9439                    .cursor_default()
 9440                    .hoverable_tooltip(move |_window, cx| {
 9441                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9442                    })
 9443            })
 9444            .children(keybind)
 9445            .child(
 9446                Label::new(label)
 9447                    .size(LabelSize::Small)
 9448                    .when(!has_keybind, |el| {
 9449                        el.color(cx.theme().status().error.into()).strikethrough()
 9450                    }),
 9451            )
 9452            .when(!has_keybind, |el| {
 9453                el.child(
 9454                    h_flex().ml_1().child(
 9455                        Icon::new(IconName::Info)
 9456                            .size(IconSize::Small)
 9457                            .color(cx.theme().status().error.into()),
 9458                    ),
 9459                )
 9460            })
 9461            .when_some(icon, |element, icon| {
 9462                element.child(
 9463                    div()
 9464                        .mt(px(1.5))
 9465                        .child(Icon::new(icon).size(IconSize::Small)),
 9466                )
 9467            })
 9468    }
 9469
 9470    fn render_edit_prediction_jump_outside_popover(
 9471        &self,
 9472        snapshot: &BufferSnapshot,
 9473        window: &mut Window,
 9474        cx: &mut App,
 9475    ) -> Stateful<Div> {
 9476        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9477        let has_keybind = keybind.is_some();
 9478
 9479        let file_name = snapshot
 9480            .file()
 9481            .map(|file| SharedString::new(file.file_name(cx)))
 9482            .unwrap_or(SharedString::new_static("untitled"));
 9483
 9484        h_flex()
 9485            .id("ep-jump-outside-popover")
 9486            .py_1()
 9487            .px_2()
 9488            .gap_1()
 9489            .rounded_md()
 9490            .border_1()
 9491            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9492            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9493            .shadow_xs()
 9494            .when(!has_keybind, |el| {
 9495                let status_colors = cx.theme().status();
 9496
 9497                el.bg(status_colors.error_background)
 9498                    .border_color(status_colors.error.opacity(0.6))
 9499                    .pl_2()
 9500                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9501                    .cursor_default()
 9502                    .hoverable_tooltip(move |_window, cx| {
 9503                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9504                    })
 9505            })
 9506            .children(keybind)
 9507            .child(
 9508                Label::new(file_name)
 9509                    .size(LabelSize::Small)
 9510                    .buffer_font(cx)
 9511                    .when(!has_keybind, |el| {
 9512                        el.color(cx.theme().status().error.into()).strikethrough()
 9513                    }),
 9514            )
 9515            .when(!has_keybind, |el| {
 9516                el.child(
 9517                    h_flex().ml_1().child(
 9518                        Icon::new(IconName::Info)
 9519                            .size(IconSize::Small)
 9520                            .color(cx.theme().status().error.into()),
 9521                    ),
 9522                )
 9523            })
 9524            .child(
 9525                div()
 9526                    .mt(px(1.5))
 9527                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9528            )
 9529    }
 9530
 9531    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9532        let accent_color = cx.theme().colors().text_accent;
 9533        let editor_bg_color = cx.theme().colors().editor_background;
 9534        editor_bg_color.blend(accent_color.opacity(0.1))
 9535    }
 9536
 9537    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9538        let accent_color = cx.theme().colors().text_accent;
 9539        let editor_bg_color = cx.theme().colors().editor_background;
 9540        editor_bg_color.blend(accent_color.opacity(0.6))
 9541    }
 9542    fn get_prediction_provider_icon_name(
 9543        provider: &Option<RegisteredEditPredictionProvider>,
 9544    ) -> IconName {
 9545        match provider {
 9546            Some(provider) => match provider.provider.name() {
 9547                "copilot" => IconName::Copilot,
 9548                "supermaven" => IconName::Supermaven,
 9549                _ => IconName::ZedPredict,
 9550            },
 9551            None => IconName::ZedPredict,
 9552        }
 9553    }
 9554
 9555    fn render_edit_prediction_cursor_popover(
 9556        &self,
 9557        min_width: Pixels,
 9558        max_width: Pixels,
 9559        cursor_point: Point,
 9560        style: &EditorStyle,
 9561        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9562        _window: &Window,
 9563        cx: &mut Context<Editor>,
 9564    ) -> Option<AnyElement> {
 9565        let provider = self.edit_prediction_provider.as_ref()?;
 9566        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9567
 9568        let is_refreshing = provider.provider.is_refreshing(cx);
 9569
 9570        fn pending_completion_container(icon: IconName) -> Div {
 9571            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9572        }
 9573
 9574        let completion = match &self.active_edit_prediction {
 9575            Some(prediction) => {
 9576                if !self.has_visible_completions_menu() {
 9577                    const RADIUS: Pixels = px(6.);
 9578                    const BORDER_WIDTH: Pixels = px(1.);
 9579
 9580                    return Some(
 9581                        h_flex()
 9582                            .elevation_2(cx)
 9583                            .border(BORDER_WIDTH)
 9584                            .border_color(cx.theme().colors().border)
 9585                            .when(accept_keystroke.is_none(), |el| {
 9586                                el.border_color(cx.theme().status().error)
 9587                            })
 9588                            .rounded(RADIUS)
 9589                            .rounded_tl(px(0.))
 9590                            .overflow_hidden()
 9591                            .child(div().px_1p5().child(match &prediction.completion {
 9592                                EditPrediction::MoveWithin { target, snapshot } => {
 9593                                    use text::ToPoint as _;
 9594                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9595                                    {
 9596                                        Icon::new(IconName::ZedPredictDown)
 9597                                    } else {
 9598                                        Icon::new(IconName::ZedPredictUp)
 9599                                    }
 9600                                }
 9601                                EditPrediction::MoveOutside { .. } => {
 9602                                    // TODO [zeta2] custom icon for external jump?
 9603                                    Icon::new(provider_icon)
 9604                                }
 9605                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9606                            }))
 9607                            .child(
 9608                                h_flex()
 9609                                    .gap_1()
 9610                                    .py_1()
 9611                                    .px_2()
 9612                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9613                                    .border_l_1()
 9614                                    .border_color(cx.theme().colors().border)
 9615                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9616                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9617                                        el.child(
 9618                                            Label::new("Hold")
 9619                                                .size(LabelSize::Small)
 9620                                                .when(accept_keystroke.is_none(), |el| {
 9621                                                    el.strikethrough()
 9622                                                })
 9623                                                .line_height_style(LineHeightStyle::UiLabel),
 9624                                        )
 9625                                    })
 9626                                    .id("edit_prediction_cursor_popover_keybind")
 9627                                    .when(accept_keystroke.is_none(), |el| {
 9628                                        let status_colors = cx.theme().status();
 9629
 9630                                        el.bg(status_colors.error_background)
 9631                                            .border_color(status_colors.error.opacity(0.6))
 9632                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9633                                            .cursor_default()
 9634                                            .hoverable_tooltip(move |_window, cx| {
 9635                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9636                                                    .into()
 9637                                            })
 9638                                    })
 9639                                    .when_some(
 9640                                        accept_keystroke.as_ref(),
 9641                                        |el, accept_keystroke| {
 9642                                            el.child(h_flex().children(ui::render_modifiers(
 9643                                                accept_keystroke.modifiers(),
 9644                                                PlatformStyle::platform(),
 9645                                                Some(Color::Default),
 9646                                                Some(IconSize::XSmall.rems().into()),
 9647                                                false,
 9648                                            )))
 9649                                        },
 9650                                    ),
 9651                            )
 9652                            .into_any(),
 9653                    );
 9654                }
 9655
 9656                self.render_edit_prediction_cursor_popover_preview(
 9657                    prediction,
 9658                    cursor_point,
 9659                    style,
 9660                    cx,
 9661                )?
 9662            }
 9663
 9664            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9665                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9666                    stale_completion,
 9667                    cursor_point,
 9668                    style,
 9669                    cx,
 9670                )?,
 9671
 9672                None => pending_completion_container(provider_icon)
 9673                    .child(Label::new("...").size(LabelSize::Small)),
 9674            },
 9675
 9676            None => pending_completion_container(provider_icon)
 9677                .child(Label::new("...").size(LabelSize::Small)),
 9678        };
 9679
 9680        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9681            completion
 9682                .with_animation(
 9683                    "loading-completion",
 9684                    Animation::new(Duration::from_secs(2))
 9685                        .repeat()
 9686                        .with_easing(pulsating_between(0.4, 0.8)),
 9687                    |label, delta| label.opacity(delta),
 9688                )
 9689                .into_any_element()
 9690        } else {
 9691            completion.into_any_element()
 9692        };
 9693
 9694        let has_completion = self.active_edit_prediction.is_some();
 9695
 9696        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9697        Some(
 9698            h_flex()
 9699                .min_w(min_width)
 9700                .max_w(max_width)
 9701                .flex_1()
 9702                .elevation_2(cx)
 9703                .border_color(cx.theme().colors().border)
 9704                .child(
 9705                    div()
 9706                        .flex_1()
 9707                        .py_1()
 9708                        .px_2()
 9709                        .overflow_hidden()
 9710                        .child(completion),
 9711                )
 9712                .when_some(accept_keystroke, |el, accept_keystroke| {
 9713                    if !accept_keystroke.modifiers().modified() {
 9714                        return el;
 9715                    }
 9716
 9717                    el.child(
 9718                        h_flex()
 9719                            .h_full()
 9720                            .border_l_1()
 9721                            .rounded_r_lg()
 9722                            .border_color(cx.theme().colors().border)
 9723                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9724                            .gap_1()
 9725                            .py_1()
 9726                            .px_2()
 9727                            .child(
 9728                                h_flex()
 9729                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9730                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9731                                    .child(h_flex().children(ui::render_modifiers(
 9732                                        accept_keystroke.modifiers(),
 9733                                        PlatformStyle::platform(),
 9734                                        Some(if !has_completion {
 9735                                            Color::Muted
 9736                                        } else {
 9737                                            Color::Default
 9738                                        }),
 9739                                        None,
 9740                                        false,
 9741                                    ))),
 9742                            )
 9743                            .child(Label::new("Preview").into_any_element())
 9744                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9745                    )
 9746                })
 9747                .into_any(),
 9748        )
 9749    }
 9750
 9751    fn render_edit_prediction_cursor_popover_preview(
 9752        &self,
 9753        completion: &EditPredictionState,
 9754        cursor_point: Point,
 9755        style: &EditorStyle,
 9756        cx: &mut Context<Editor>,
 9757    ) -> Option<Div> {
 9758        use text::ToPoint as _;
 9759
 9760        fn render_relative_row_jump(
 9761            prefix: impl Into<String>,
 9762            current_row: u32,
 9763            target_row: u32,
 9764        ) -> Div {
 9765            let (row_diff, arrow) = if target_row < current_row {
 9766                (current_row - target_row, IconName::ArrowUp)
 9767            } else {
 9768                (target_row - current_row, IconName::ArrowDown)
 9769            };
 9770
 9771            h_flex()
 9772                .child(
 9773                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9774                        .color(Color::Muted)
 9775                        .size(LabelSize::Small),
 9776                )
 9777                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9778        }
 9779
 9780        let supports_jump = self
 9781            .edit_prediction_provider
 9782            .as_ref()
 9783            .map(|provider| provider.provider.supports_jump_to_edit())
 9784            .unwrap_or(true);
 9785
 9786        match &completion.completion {
 9787            EditPrediction::MoveWithin {
 9788                target, snapshot, ..
 9789            } => {
 9790                if !supports_jump {
 9791                    return None;
 9792                }
 9793
 9794                Some(
 9795                    h_flex()
 9796                        .px_2()
 9797                        .gap_2()
 9798                        .flex_1()
 9799                        .child(
 9800                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9801                                Icon::new(IconName::ZedPredictDown)
 9802                            } else {
 9803                                Icon::new(IconName::ZedPredictUp)
 9804                            },
 9805                        )
 9806                        .child(Label::new("Jump to Edit")),
 9807                )
 9808            }
 9809            EditPrediction::MoveOutside { snapshot, .. } => {
 9810                let file_name = snapshot
 9811                    .file()
 9812                    .map(|file| file.file_name(cx))
 9813                    .unwrap_or("untitled");
 9814                Some(
 9815                    h_flex()
 9816                        .px_2()
 9817                        .gap_2()
 9818                        .flex_1()
 9819                        .child(Icon::new(IconName::ZedPredict))
 9820                        .child(Label::new(format!("Jump to {file_name}"))),
 9821                )
 9822            }
 9823            EditPrediction::Edit {
 9824                edits,
 9825                edit_preview,
 9826                snapshot,
 9827                display_mode: _,
 9828            } => {
 9829                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9830
 9831                let (highlighted_edits, has_more_lines) =
 9832                    if let Some(edit_preview) = edit_preview.as_ref() {
 9833                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9834                            .first_line_preview()
 9835                    } else {
 9836                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9837                    };
 9838
 9839                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9840                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9841
 9842                let preview = h_flex()
 9843                    .gap_1()
 9844                    .min_w_16()
 9845                    .child(styled_text)
 9846                    .when(has_more_lines, |parent| parent.child(""));
 9847
 9848                let left = if supports_jump && first_edit_row != cursor_point.row {
 9849                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9850                        .into_any_element()
 9851                } else {
 9852                    let icon_name =
 9853                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9854                    Icon::new(icon_name).into_any_element()
 9855                };
 9856
 9857                Some(
 9858                    h_flex()
 9859                        .h_full()
 9860                        .flex_1()
 9861                        .gap_2()
 9862                        .pr_1()
 9863                        .overflow_x_hidden()
 9864                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9865                        .child(left)
 9866                        .child(preview),
 9867                )
 9868            }
 9869        }
 9870    }
 9871
 9872    pub fn render_context_menu(
 9873        &self,
 9874        style: &EditorStyle,
 9875        max_height_in_lines: u32,
 9876        window: &mut Window,
 9877        cx: &mut Context<Editor>,
 9878    ) -> Option<AnyElement> {
 9879        let menu = self.context_menu.borrow();
 9880        let menu = menu.as_ref()?;
 9881        if !menu.visible() {
 9882            return None;
 9883        };
 9884        Some(menu.render(style, max_height_in_lines, window, cx))
 9885    }
 9886
 9887    fn render_context_menu_aside(
 9888        &mut self,
 9889        max_size: Size<Pixels>,
 9890        window: &mut Window,
 9891        cx: &mut Context<Editor>,
 9892    ) -> Option<AnyElement> {
 9893        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9894            if menu.visible() {
 9895                menu.render_aside(max_size, window, cx)
 9896            } else {
 9897                None
 9898            }
 9899        })
 9900    }
 9901
 9902    fn hide_context_menu(
 9903        &mut self,
 9904        window: &mut Window,
 9905        cx: &mut Context<Self>,
 9906    ) -> Option<CodeContextMenu> {
 9907        cx.notify();
 9908        self.completion_tasks.clear();
 9909        let context_menu = self.context_menu.borrow_mut().take();
 9910        self.stale_edit_prediction_in_menu.take();
 9911        self.update_visible_edit_prediction(window, cx);
 9912        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9913            && let Some(completion_provider) = &self.completion_provider
 9914        {
 9915            completion_provider.selection_changed(None, window, cx);
 9916        }
 9917        context_menu
 9918    }
 9919
 9920    fn show_snippet_choices(
 9921        &mut self,
 9922        choices: &Vec<String>,
 9923        selection: Range<Anchor>,
 9924        cx: &mut Context<Self>,
 9925    ) {
 9926        let Some((_, buffer, _)) = self
 9927            .buffer()
 9928            .read(cx)
 9929            .excerpt_containing(selection.start, cx)
 9930        else {
 9931            return;
 9932        };
 9933        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9934        else {
 9935            return;
 9936        };
 9937        if buffer != end_buffer {
 9938            log::error!("expected anchor range to have matching buffer IDs");
 9939            return;
 9940        }
 9941
 9942        let id = post_inc(&mut self.next_completion_id);
 9943        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9944        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9945            CompletionsMenu::new_snippet_choices(
 9946                id,
 9947                true,
 9948                choices,
 9949                selection,
 9950                buffer,
 9951                snippet_sort_order,
 9952            ),
 9953        ));
 9954    }
 9955
 9956    pub fn insert_snippet(
 9957        &mut self,
 9958        insertion_ranges: &[Range<MultiBufferOffset>],
 9959        snippet: Snippet,
 9960        window: &mut Window,
 9961        cx: &mut Context<Self>,
 9962    ) -> Result<()> {
 9963        struct Tabstop<T> {
 9964            is_end_tabstop: bool,
 9965            ranges: Vec<Range<T>>,
 9966            choices: Option<Vec<String>>,
 9967        }
 9968
 9969        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9970            let snippet_text: Arc<str> = snippet.text.clone().into();
 9971            let edits = insertion_ranges
 9972                .iter()
 9973                .cloned()
 9974                .map(|range| (range, snippet_text.clone()));
 9975            let autoindent_mode = AutoindentMode::Block {
 9976                original_indent_columns: Vec::new(),
 9977            };
 9978            buffer.edit(edits, Some(autoindent_mode), cx);
 9979
 9980            let snapshot = &*buffer.read(cx);
 9981            let snippet = &snippet;
 9982            snippet
 9983                .tabstops
 9984                .iter()
 9985                .map(|tabstop| {
 9986                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9987                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9988                    });
 9989                    let mut tabstop_ranges = tabstop
 9990                        .ranges
 9991                        .iter()
 9992                        .flat_map(|tabstop_range| {
 9993                            let mut delta = 0_isize;
 9994                            insertion_ranges.iter().map(move |insertion_range| {
 9995                                let insertion_start = insertion_range.start + delta;
 9996                                delta += snippet.text.len() as isize
 9997                                    - (insertion_range.end - insertion_range.start) as isize;
 9998
 9999                                let start =
10000                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10001                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10002                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10003                            })
10004                        })
10005                        .collect::<Vec<_>>();
10006                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10007
10008                    Tabstop {
10009                        is_end_tabstop,
10010                        ranges: tabstop_ranges,
10011                        choices: tabstop.choices.clone(),
10012                    }
10013                })
10014                .collect::<Vec<_>>()
10015        });
10016        if let Some(tabstop) = tabstops.first() {
10017            self.change_selections(Default::default(), window, cx, |s| {
10018                // Reverse order so that the first range is the newest created selection.
10019                // Completions will use it and autoscroll will prioritize it.
10020                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10021            });
10022
10023            if let Some(choices) = &tabstop.choices
10024                && let Some(selection) = tabstop.ranges.first()
10025            {
10026                self.show_snippet_choices(choices, selection.clone(), cx)
10027            }
10028
10029            // If we're already at the last tabstop and it's at the end of the snippet,
10030            // we're done, we don't need to keep the state around.
10031            if !tabstop.is_end_tabstop {
10032                let choices = tabstops
10033                    .iter()
10034                    .map(|tabstop| tabstop.choices.clone())
10035                    .collect();
10036
10037                let ranges = tabstops
10038                    .into_iter()
10039                    .map(|tabstop| tabstop.ranges)
10040                    .collect::<Vec<_>>();
10041
10042                self.snippet_stack.push(SnippetState {
10043                    active_index: 0,
10044                    ranges,
10045                    choices,
10046                });
10047            }
10048
10049            // Check whether the just-entered snippet ends with an auto-closable bracket.
10050            if self.autoclose_regions.is_empty() {
10051                let snapshot = self.buffer.read(cx).snapshot(cx);
10052                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10053                    let selection_head = selection.head();
10054                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10055                        continue;
10056                    };
10057
10058                    let mut bracket_pair = None;
10059                    let max_lookup_length = scope
10060                        .brackets()
10061                        .map(|(pair, _)| {
10062                            pair.start
10063                                .as_str()
10064                                .chars()
10065                                .count()
10066                                .max(pair.end.as_str().chars().count())
10067                        })
10068                        .max();
10069                    if let Some(max_lookup_length) = max_lookup_length {
10070                        let next_text = snapshot
10071                            .chars_at(selection_head)
10072                            .take(max_lookup_length)
10073                            .collect::<String>();
10074                        let prev_text = snapshot
10075                            .reversed_chars_at(selection_head)
10076                            .take(max_lookup_length)
10077                            .collect::<String>();
10078
10079                        for (pair, enabled) in scope.brackets() {
10080                            if enabled
10081                                && pair.close
10082                                && prev_text.starts_with(pair.start.as_str())
10083                                && next_text.starts_with(pair.end.as_str())
10084                            {
10085                                bracket_pair = Some(pair.clone());
10086                                break;
10087                            }
10088                        }
10089                    }
10090
10091                    if let Some(pair) = bracket_pair {
10092                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10093                        let autoclose_enabled =
10094                            self.use_autoclose && snapshot_settings.use_autoclose;
10095                        if autoclose_enabled {
10096                            let start = snapshot.anchor_after(selection_head);
10097                            let end = snapshot.anchor_after(selection_head);
10098                            self.autoclose_regions.push(AutocloseRegion {
10099                                selection_id: selection.id,
10100                                range: start..end,
10101                                pair,
10102                            });
10103                        }
10104                    }
10105                }
10106            }
10107        }
10108        Ok(())
10109    }
10110
10111    pub fn move_to_next_snippet_tabstop(
10112        &mut self,
10113        window: &mut Window,
10114        cx: &mut Context<Self>,
10115    ) -> bool {
10116        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10117    }
10118
10119    pub fn move_to_prev_snippet_tabstop(
10120        &mut self,
10121        window: &mut Window,
10122        cx: &mut Context<Self>,
10123    ) -> bool {
10124        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10125    }
10126
10127    pub fn move_to_snippet_tabstop(
10128        &mut self,
10129        bias: Bias,
10130        window: &mut Window,
10131        cx: &mut Context<Self>,
10132    ) -> bool {
10133        if let Some(mut snippet) = self.snippet_stack.pop() {
10134            match bias {
10135                Bias::Left => {
10136                    if snippet.active_index > 0 {
10137                        snippet.active_index -= 1;
10138                    } else {
10139                        self.snippet_stack.push(snippet);
10140                        return false;
10141                    }
10142                }
10143                Bias::Right => {
10144                    if snippet.active_index + 1 < snippet.ranges.len() {
10145                        snippet.active_index += 1;
10146                    } else {
10147                        self.snippet_stack.push(snippet);
10148                        return false;
10149                    }
10150                }
10151            }
10152            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10153                self.change_selections(Default::default(), window, cx, |s| {
10154                    // Reverse order so that the first range is the newest created selection.
10155                    // Completions will use it and autoscroll will prioritize it.
10156                    s.select_ranges(current_ranges.iter().rev().cloned())
10157                });
10158
10159                if let Some(choices) = &snippet.choices[snippet.active_index]
10160                    && let Some(selection) = current_ranges.first()
10161                {
10162                    self.show_snippet_choices(choices, selection.clone(), cx);
10163                }
10164
10165                // If snippet state is not at the last tabstop, push it back on the stack
10166                if snippet.active_index + 1 < snippet.ranges.len() {
10167                    self.snippet_stack.push(snippet);
10168                }
10169                return true;
10170            }
10171        }
10172
10173        false
10174    }
10175
10176    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10177        self.transact(window, cx, |this, window, cx| {
10178            this.select_all(&SelectAll, window, cx);
10179            this.insert("", window, cx);
10180        });
10181    }
10182
10183    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10184        if self.read_only(cx) {
10185            return;
10186        }
10187        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10188        self.transact(window, cx, |this, window, cx| {
10189            this.select_autoclose_pair(window, cx);
10190
10191            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10192
10193            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10194            if !this.linked_edit_ranges.is_empty() {
10195                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10196                let snapshot = this.buffer.read(cx).snapshot(cx);
10197
10198                for selection in selections.iter() {
10199                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10200                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10201                    if selection_start.buffer_id != selection_end.buffer_id {
10202                        continue;
10203                    }
10204                    if let Some(ranges) =
10205                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10206                    {
10207                        for (buffer, entries) in ranges {
10208                            linked_ranges.entry(buffer).or_default().extend(entries);
10209                        }
10210                    }
10211                }
10212            }
10213
10214            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10215            for selection in &mut selections {
10216                if selection.is_empty() {
10217                    let old_head = selection.head();
10218                    let mut new_head =
10219                        movement::left(&display_map, old_head.to_display_point(&display_map))
10220                            .to_point(&display_map);
10221                    if let Some((buffer, line_buffer_range)) = display_map
10222                        .buffer_snapshot()
10223                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10224                    {
10225                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10226                        let indent_len = match indent_size.kind {
10227                            IndentKind::Space => {
10228                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10229                            }
10230                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10231                        };
10232                        if old_head.column <= indent_size.len && old_head.column > 0 {
10233                            let indent_len = indent_len.get();
10234                            new_head = cmp::min(
10235                                new_head,
10236                                MultiBufferPoint::new(
10237                                    old_head.row,
10238                                    ((old_head.column - 1) / indent_len) * indent_len,
10239                                ),
10240                            );
10241                        }
10242                    }
10243
10244                    selection.set_head(new_head, SelectionGoal::None);
10245                }
10246            }
10247
10248            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10249            this.insert("", window, cx);
10250            let empty_str: Arc<str> = Arc::from("");
10251            for (buffer, edits) in linked_ranges {
10252                let snapshot = buffer.read(cx).snapshot();
10253                use text::ToPoint as TP;
10254
10255                let edits = edits
10256                    .into_iter()
10257                    .map(|range| {
10258                        let end_point = TP::to_point(&range.end, &snapshot);
10259                        let mut start_point = TP::to_point(&range.start, &snapshot);
10260
10261                        if end_point == start_point {
10262                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10263                                .saturating_sub(1);
10264                            start_point =
10265                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10266                        };
10267
10268                        (start_point..end_point, empty_str.clone())
10269                    })
10270                    .sorted_by_key(|(range, _)| range.start)
10271                    .collect::<Vec<_>>();
10272                buffer.update(cx, |this, cx| {
10273                    this.edit(edits, None, cx);
10274                })
10275            }
10276            this.refresh_edit_prediction(true, false, window, cx);
10277            refresh_linked_ranges(this, window, cx);
10278        });
10279    }
10280
10281    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10282        if self.read_only(cx) {
10283            return;
10284        }
10285        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10286        self.transact(window, cx, |this, window, cx| {
10287            this.change_selections(Default::default(), window, cx, |s| {
10288                s.move_with(|map, selection| {
10289                    if selection.is_empty() {
10290                        let cursor = movement::right(map, selection.head());
10291                        selection.end = cursor;
10292                        selection.reversed = true;
10293                        selection.goal = SelectionGoal::None;
10294                    }
10295                })
10296            });
10297            this.insert("", window, cx);
10298            this.refresh_edit_prediction(true, false, window, cx);
10299        });
10300    }
10301
10302    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10303        if self.mode.is_single_line() {
10304            cx.propagate();
10305            return;
10306        }
10307
10308        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10309        if self.move_to_prev_snippet_tabstop(window, cx) {
10310            return;
10311        }
10312        self.outdent(&Outdent, window, cx);
10313    }
10314
10315    pub fn next_snippet_tabstop(
10316        &mut self,
10317        _: &NextSnippetTabstop,
10318        window: &mut Window,
10319        cx: &mut Context<Self>,
10320    ) {
10321        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10322            cx.propagate();
10323            return;
10324        }
10325
10326        if self.move_to_next_snippet_tabstop(window, cx) {
10327            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10328            return;
10329        }
10330        cx.propagate();
10331    }
10332
10333    pub fn previous_snippet_tabstop(
10334        &mut self,
10335        _: &PreviousSnippetTabstop,
10336        window: &mut Window,
10337        cx: &mut Context<Self>,
10338    ) {
10339        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10340            cx.propagate();
10341            return;
10342        }
10343
10344        if self.move_to_prev_snippet_tabstop(window, cx) {
10345            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10346            return;
10347        }
10348        cx.propagate();
10349    }
10350
10351    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10352        if self.mode.is_single_line() {
10353            cx.propagate();
10354            return;
10355        }
10356
10357        if self.move_to_next_snippet_tabstop(window, cx) {
10358            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10359            return;
10360        }
10361        if self.read_only(cx) {
10362            return;
10363        }
10364        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10365        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10366        let buffer = self.buffer.read(cx);
10367        let snapshot = buffer.snapshot(cx);
10368        let rows_iter = selections.iter().map(|s| s.head().row);
10369        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10370
10371        let has_some_cursor_in_whitespace = selections
10372            .iter()
10373            .filter(|selection| selection.is_empty())
10374            .any(|selection| {
10375                let cursor = selection.head();
10376                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10377                cursor.column < current_indent.len
10378            });
10379
10380        let mut edits = Vec::new();
10381        let mut prev_edited_row = 0;
10382        let mut row_delta = 0;
10383        for selection in &mut selections {
10384            if selection.start.row != prev_edited_row {
10385                row_delta = 0;
10386            }
10387            prev_edited_row = selection.end.row;
10388
10389            // If the selection is non-empty, then increase the indentation of the selected lines.
10390            if !selection.is_empty() {
10391                row_delta =
10392                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10393                continue;
10394            }
10395
10396            let cursor = selection.head();
10397            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10398            if let Some(suggested_indent) =
10399                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10400            {
10401                // Don't do anything if already at suggested indent
10402                // and there is any other cursor which is not
10403                if has_some_cursor_in_whitespace
10404                    && cursor.column == current_indent.len
10405                    && current_indent.len == suggested_indent.len
10406                {
10407                    continue;
10408                }
10409
10410                // Adjust line and move cursor to suggested indent
10411                // if cursor is not at suggested indent
10412                if cursor.column < suggested_indent.len
10413                    && cursor.column <= current_indent.len
10414                    && current_indent.len <= suggested_indent.len
10415                {
10416                    selection.start = Point::new(cursor.row, suggested_indent.len);
10417                    selection.end = selection.start;
10418                    if row_delta == 0 {
10419                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10420                            cursor.row,
10421                            current_indent,
10422                            suggested_indent,
10423                        ));
10424                        row_delta = suggested_indent.len - current_indent.len;
10425                    }
10426                    continue;
10427                }
10428
10429                // If current indent is more than suggested indent
10430                // only move cursor to current indent and skip indent
10431                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10432                    selection.start = Point::new(cursor.row, current_indent.len);
10433                    selection.end = selection.start;
10434                    continue;
10435                }
10436            }
10437
10438            // Otherwise, insert a hard or soft tab.
10439            let settings = buffer.language_settings_at(cursor, cx);
10440            let tab_size = if settings.hard_tabs {
10441                IndentSize::tab()
10442            } else {
10443                let tab_size = settings.tab_size.get();
10444                let indent_remainder = snapshot
10445                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10446                    .flat_map(str::chars)
10447                    .fold(row_delta % tab_size, |counter: u32, c| {
10448                        if c == '\t' {
10449                            0
10450                        } else {
10451                            (counter + 1) % tab_size
10452                        }
10453                    });
10454
10455                let chars_to_next_tab_stop = tab_size - indent_remainder;
10456                IndentSize::spaces(chars_to_next_tab_stop)
10457            };
10458            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10459            selection.end = selection.start;
10460            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10461            row_delta += tab_size.len;
10462        }
10463
10464        self.transact(window, cx, |this, window, cx| {
10465            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10466            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10467            this.refresh_edit_prediction(true, false, window, cx);
10468        });
10469    }
10470
10471    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10472        if self.read_only(cx) {
10473            return;
10474        }
10475        if self.mode.is_single_line() {
10476            cx.propagate();
10477            return;
10478        }
10479
10480        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10481        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10482        let mut prev_edited_row = 0;
10483        let mut row_delta = 0;
10484        let mut edits = Vec::new();
10485        let buffer = self.buffer.read(cx);
10486        let snapshot = buffer.snapshot(cx);
10487        for selection in &mut selections {
10488            if selection.start.row != prev_edited_row {
10489                row_delta = 0;
10490            }
10491            prev_edited_row = selection.end.row;
10492
10493            row_delta =
10494                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10495        }
10496
10497        self.transact(window, cx, |this, window, cx| {
10498            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10499            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10500        });
10501    }
10502
10503    fn indent_selection(
10504        buffer: &MultiBuffer,
10505        snapshot: &MultiBufferSnapshot,
10506        selection: &mut Selection<Point>,
10507        edits: &mut Vec<(Range<Point>, String)>,
10508        delta_for_start_row: u32,
10509        cx: &App,
10510    ) -> u32 {
10511        let settings = buffer.language_settings_at(selection.start, cx);
10512        let tab_size = settings.tab_size.get();
10513        let indent_kind = if settings.hard_tabs {
10514            IndentKind::Tab
10515        } else {
10516            IndentKind::Space
10517        };
10518        let mut start_row = selection.start.row;
10519        let mut end_row = selection.end.row + 1;
10520
10521        // If a selection ends at the beginning of a line, don't indent
10522        // that last line.
10523        if selection.end.column == 0 && selection.end.row > selection.start.row {
10524            end_row -= 1;
10525        }
10526
10527        // Avoid re-indenting a row that has already been indented by a
10528        // previous selection, but still update this selection's column
10529        // to reflect that indentation.
10530        if delta_for_start_row > 0 {
10531            start_row += 1;
10532            selection.start.column += delta_for_start_row;
10533            if selection.end.row == selection.start.row {
10534                selection.end.column += delta_for_start_row;
10535            }
10536        }
10537
10538        let mut delta_for_end_row = 0;
10539        let has_multiple_rows = start_row + 1 != end_row;
10540        for row in start_row..end_row {
10541            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10542            let indent_delta = match (current_indent.kind, indent_kind) {
10543                (IndentKind::Space, IndentKind::Space) => {
10544                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10545                    IndentSize::spaces(columns_to_next_tab_stop)
10546                }
10547                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10548                (_, IndentKind::Tab) => IndentSize::tab(),
10549            };
10550
10551            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10552                0
10553            } else {
10554                selection.start.column
10555            };
10556            let row_start = Point::new(row, start);
10557            edits.push((
10558                row_start..row_start,
10559                indent_delta.chars().collect::<String>(),
10560            ));
10561
10562            // Update this selection's endpoints to reflect the indentation.
10563            if row == selection.start.row {
10564                selection.start.column += indent_delta.len;
10565            }
10566            if row == selection.end.row {
10567                selection.end.column += indent_delta.len;
10568                delta_for_end_row = indent_delta.len;
10569            }
10570        }
10571
10572        if selection.start.row == selection.end.row {
10573            delta_for_start_row + delta_for_end_row
10574        } else {
10575            delta_for_end_row
10576        }
10577    }
10578
10579    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10580        if self.read_only(cx) {
10581            return;
10582        }
10583        if self.mode.is_single_line() {
10584            cx.propagate();
10585            return;
10586        }
10587
10588        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10589        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10590        let selections = self.selections.all::<Point>(&display_map);
10591        let mut deletion_ranges = Vec::new();
10592        let mut last_outdent = None;
10593        {
10594            let buffer = self.buffer.read(cx);
10595            let snapshot = buffer.snapshot(cx);
10596            for selection in &selections {
10597                let settings = buffer.language_settings_at(selection.start, cx);
10598                let tab_size = settings.tab_size.get();
10599                let mut rows = selection.spanned_rows(false, &display_map);
10600
10601                // Avoid re-outdenting a row that has already been outdented by a
10602                // previous selection.
10603                if let Some(last_row) = last_outdent
10604                    && last_row == rows.start
10605                {
10606                    rows.start = rows.start.next_row();
10607                }
10608                let has_multiple_rows = rows.len() > 1;
10609                for row in rows.iter_rows() {
10610                    let indent_size = snapshot.indent_size_for_line(row);
10611                    if indent_size.len > 0 {
10612                        let deletion_len = match indent_size.kind {
10613                            IndentKind::Space => {
10614                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10615                                if columns_to_prev_tab_stop == 0 {
10616                                    tab_size
10617                                } else {
10618                                    columns_to_prev_tab_stop
10619                                }
10620                            }
10621                            IndentKind::Tab => 1,
10622                        };
10623                        let start = if has_multiple_rows
10624                            || deletion_len > selection.start.column
10625                            || indent_size.len < selection.start.column
10626                        {
10627                            0
10628                        } else {
10629                            selection.start.column - deletion_len
10630                        };
10631                        deletion_ranges.push(
10632                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10633                        );
10634                        last_outdent = Some(row);
10635                    }
10636                }
10637            }
10638        }
10639
10640        self.transact(window, cx, |this, window, cx| {
10641            this.buffer.update(cx, |buffer, cx| {
10642                let empty_str: Arc<str> = Arc::default();
10643                buffer.edit(
10644                    deletion_ranges
10645                        .into_iter()
10646                        .map(|range| (range, empty_str.clone())),
10647                    None,
10648                    cx,
10649                );
10650            });
10651            let selections = this
10652                .selections
10653                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10654            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10655        });
10656    }
10657
10658    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10659        if self.read_only(cx) {
10660            return;
10661        }
10662        if self.mode.is_single_line() {
10663            cx.propagate();
10664            return;
10665        }
10666
10667        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10668        let selections = self
10669            .selections
10670            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10671            .into_iter()
10672            .map(|s| s.range());
10673
10674        self.transact(window, cx, |this, window, cx| {
10675            this.buffer.update(cx, |buffer, cx| {
10676                buffer.autoindent_ranges(selections, cx);
10677            });
10678            let selections = this
10679                .selections
10680                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10681            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10682        });
10683    }
10684
10685    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10686        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10687        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10688        let selections = self.selections.all::<Point>(&display_map);
10689
10690        let mut new_cursors = Vec::new();
10691        let mut edit_ranges = Vec::new();
10692        let mut selections = selections.iter().peekable();
10693        while let Some(selection) = selections.next() {
10694            let mut rows = selection.spanned_rows(false, &display_map);
10695
10696            // Accumulate contiguous regions of rows that we want to delete.
10697            while let Some(next_selection) = selections.peek() {
10698                let next_rows = next_selection.spanned_rows(false, &display_map);
10699                if next_rows.start <= rows.end {
10700                    rows.end = next_rows.end;
10701                    selections.next().unwrap();
10702                } else {
10703                    break;
10704                }
10705            }
10706
10707            let buffer = display_map.buffer_snapshot();
10708            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10709            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10710                // If there's a line after the range, delete the \n from the end of the row range
10711                (
10712                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10713                    rows.end,
10714                )
10715            } else {
10716                // If there isn't a line after the range, delete the \n from the line before the
10717                // start of the row range
10718                edit_start = edit_start.saturating_sub_usize(1);
10719                (buffer.len(), rows.start.previous_row())
10720            };
10721
10722            let text_layout_details = self.text_layout_details(window);
10723            let x = display_map.x_for_display_point(
10724                selection.head().to_display_point(&display_map),
10725                &text_layout_details,
10726            );
10727            let row = Point::new(target_row.0, 0)
10728                .to_display_point(&display_map)
10729                .row();
10730            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10731
10732            new_cursors.push((
10733                selection.id,
10734                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10735                SelectionGoal::None,
10736            ));
10737            edit_ranges.push(edit_start..edit_end);
10738        }
10739
10740        self.transact(window, cx, |this, window, cx| {
10741            let buffer = this.buffer.update(cx, |buffer, cx| {
10742                let empty_str: Arc<str> = Arc::default();
10743                buffer.edit(
10744                    edit_ranges
10745                        .into_iter()
10746                        .map(|range| (range, empty_str.clone())),
10747                    None,
10748                    cx,
10749                );
10750                buffer.snapshot(cx)
10751            });
10752            let new_selections = new_cursors
10753                .into_iter()
10754                .map(|(id, cursor, goal)| {
10755                    let cursor = cursor.to_point(&buffer);
10756                    Selection {
10757                        id,
10758                        start: cursor,
10759                        end: cursor,
10760                        reversed: false,
10761                        goal,
10762                    }
10763                })
10764                .collect();
10765
10766            this.change_selections(Default::default(), window, cx, |s| {
10767                s.select(new_selections);
10768            });
10769        });
10770    }
10771
10772    pub fn join_lines_impl(
10773        &mut self,
10774        insert_whitespace: bool,
10775        window: &mut Window,
10776        cx: &mut Context<Self>,
10777    ) {
10778        if self.read_only(cx) {
10779            return;
10780        }
10781        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10782        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10783            let start = MultiBufferRow(selection.start.row);
10784            // Treat single line selections as if they include the next line. Otherwise this action
10785            // would do nothing for single line selections individual cursors.
10786            let end = if selection.start.row == selection.end.row {
10787                MultiBufferRow(selection.start.row + 1)
10788            } else {
10789                MultiBufferRow(selection.end.row)
10790            };
10791
10792            if let Some(last_row_range) = row_ranges.last_mut()
10793                && start <= last_row_range.end
10794            {
10795                last_row_range.end = end;
10796                continue;
10797            }
10798            row_ranges.push(start..end);
10799        }
10800
10801        let snapshot = self.buffer.read(cx).snapshot(cx);
10802        let mut cursor_positions = Vec::new();
10803        for row_range in &row_ranges {
10804            let anchor = snapshot.anchor_before(Point::new(
10805                row_range.end.previous_row().0,
10806                snapshot.line_len(row_range.end.previous_row()),
10807            ));
10808            cursor_positions.push(anchor..anchor);
10809        }
10810
10811        self.transact(window, cx, |this, window, cx| {
10812            for row_range in row_ranges.into_iter().rev() {
10813                for row in row_range.iter_rows().rev() {
10814                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10815                    let next_line_row = row.next_row();
10816                    let indent = snapshot.indent_size_for_line(next_line_row);
10817                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10818
10819                    let replace =
10820                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10821                            " "
10822                        } else {
10823                            ""
10824                        };
10825
10826                    this.buffer.update(cx, |buffer, cx| {
10827                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10828                    });
10829                }
10830            }
10831
10832            this.change_selections(Default::default(), window, cx, |s| {
10833                s.select_anchor_ranges(cursor_positions)
10834            });
10835        });
10836    }
10837
10838    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10839        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10840        self.join_lines_impl(true, window, cx);
10841    }
10842
10843    pub fn sort_lines_case_sensitive(
10844        &mut self,
10845        _: &SortLinesCaseSensitive,
10846        window: &mut Window,
10847        cx: &mut Context<Self>,
10848    ) {
10849        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10850    }
10851
10852    pub fn sort_lines_by_length(
10853        &mut self,
10854        _: &SortLinesByLength,
10855        window: &mut Window,
10856        cx: &mut Context<Self>,
10857    ) {
10858        self.manipulate_immutable_lines(window, cx, |lines| {
10859            lines.sort_by_key(|&line| line.chars().count())
10860        })
10861    }
10862
10863    pub fn sort_lines_case_insensitive(
10864        &mut self,
10865        _: &SortLinesCaseInsensitive,
10866        window: &mut Window,
10867        cx: &mut Context<Self>,
10868    ) {
10869        self.manipulate_immutable_lines(window, cx, |lines| {
10870            lines.sort_by_key(|line| line.to_lowercase())
10871        })
10872    }
10873
10874    pub fn unique_lines_case_insensitive(
10875        &mut self,
10876        _: &UniqueLinesCaseInsensitive,
10877        window: &mut Window,
10878        cx: &mut Context<Self>,
10879    ) {
10880        self.manipulate_immutable_lines(window, cx, |lines| {
10881            let mut seen = HashSet::default();
10882            lines.retain(|line| seen.insert(line.to_lowercase()));
10883        })
10884    }
10885
10886    pub fn unique_lines_case_sensitive(
10887        &mut self,
10888        _: &UniqueLinesCaseSensitive,
10889        window: &mut Window,
10890        cx: &mut Context<Self>,
10891    ) {
10892        self.manipulate_immutable_lines(window, cx, |lines| {
10893            let mut seen = HashSet::default();
10894            lines.retain(|line| seen.insert(*line));
10895        })
10896    }
10897
10898    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10899        let snapshot = self.buffer.read(cx).snapshot(cx);
10900        for selection in self.selections.disjoint_anchors_arc().iter() {
10901            if snapshot
10902                .language_at(selection.start)
10903                .and_then(|lang| lang.config().wrap_characters.as_ref())
10904                .is_some()
10905            {
10906                return true;
10907            }
10908        }
10909        false
10910    }
10911
10912    fn wrap_selections_in_tag(
10913        &mut self,
10914        _: &WrapSelectionsInTag,
10915        window: &mut Window,
10916        cx: &mut Context<Self>,
10917    ) {
10918        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10919
10920        let snapshot = self.buffer.read(cx).snapshot(cx);
10921
10922        let mut edits = Vec::new();
10923        let mut boundaries = Vec::new();
10924
10925        for selection in self
10926            .selections
10927            .all_adjusted(&self.display_snapshot(cx))
10928            .iter()
10929        {
10930            let Some(wrap_config) = snapshot
10931                .language_at(selection.start)
10932                .and_then(|lang| lang.config().wrap_characters.clone())
10933            else {
10934                continue;
10935            };
10936
10937            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10938            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10939
10940            let start_before = snapshot.anchor_before(selection.start);
10941            let end_after = snapshot.anchor_after(selection.end);
10942
10943            edits.push((start_before..start_before, open_tag));
10944            edits.push((end_after..end_after, close_tag));
10945
10946            boundaries.push((
10947                start_before,
10948                end_after,
10949                wrap_config.start_prefix.len(),
10950                wrap_config.end_suffix.len(),
10951            ));
10952        }
10953
10954        if edits.is_empty() {
10955            return;
10956        }
10957
10958        self.transact(window, cx, |this, window, cx| {
10959            let buffer = this.buffer.update(cx, |buffer, cx| {
10960                buffer.edit(edits, None, cx);
10961                buffer.snapshot(cx)
10962            });
10963
10964            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10965            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10966                boundaries.into_iter()
10967            {
10968                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10969                let close_offset = end_after
10970                    .to_offset(&buffer)
10971                    .saturating_sub_usize(end_suffix_len);
10972                new_selections.push(open_offset..open_offset);
10973                new_selections.push(close_offset..close_offset);
10974            }
10975
10976            this.change_selections(Default::default(), window, cx, |s| {
10977                s.select_ranges(new_selections);
10978            });
10979
10980            this.request_autoscroll(Autoscroll::fit(), cx);
10981        });
10982    }
10983
10984    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10985        let Some(project) = self.project.clone() else {
10986            return;
10987        };
10988        self.reload(project, window, cx)
10989            .detach_and_notify_err(window, cx);
10990    }
10991
10992    pub fn restore_file(
10993        &mut self,
10994        _: &::git::RestoreFile,
10995        window: &mut Window,
10996        cx: &mut Context<Self>,
10997    ) {
10998        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10999        let mut buffer_ids = HashSet::default();
11000        let snapshot = self.buffer().read(cx).snapshot(cx);
11001        for selection in self
11002            .selections
11003            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11004        {
11005            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11006        }
11007
11008        let buffer = self.buffer().read(cx);
11009        let ranges = buffer_ids
11010            .into_iter()
11011            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11012            .collect::<Vec<_>>();
11013
11014        self.restore_hunks_in_ranges(ranges, window, cx);
11015    }
11016
11017    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11018        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11019        let selections = self
11020            .selections
11021            .all(&self.display_snapshot(cx))
11022            .into_iter()
11023            .map(|s| s.range())
11024            .collect();
11025        self.restore_hunks_in_ranges(selections, window, cx);
11026    }
11027
11028    pub fn restore_hunks_in_ranges(
11029        &mut self,
11030        ranges: Vec<Range<Point>>,
11031        window: &mut Window,
11032        cx: &mut Context<Editor>,
11033    ) {
11034        let mut revert_changes = HashMap::default();
11035        let chunk_by = self
11036            .snapshot(window, cx)
11037            .hunks_for_ranges(ranges)
11038            .into_iter()
11039            .chunk_by(|hunk| hunk.buffer_id);
11040        for (buffer_id, hunks) in &chunk_by {
11041            let hunks = hunks.collect::<Vec<_>>();
11042            for hunk in &hunks {
11043                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11044            }
11045            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11046        }
11047        drop(chunk_by);
11048        if !revert_changes.is_empty() {
11049            self.transact(window, cx, |editor, window, cx| {
11050                editor.restore(revert_changes, window, cx);
11051            });
11052        }
11053    }
11054
11055    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11056        if let Some(status) = self
11057            .addons
11058            .iter()
11059            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11060        {
11061            return Some(status);
11062        }
11063        self.project
11064            .as_ref()?
11065            .read(cx)
11066            .status_for_buffer_id(buffer_id, cx)
11067    }
11068
11069    pub fn open_active_item_in_terminal(
11070        &mut self,
11071        _: &OpenInTerminal,
11072        window: &mut Window,
11073        cx: &mut Context<Self>,
11074    ) {
11075        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11076            let project_path = buffer.read(cx).project_path(cx)?;
11077            let project = self.project()?.read(cx);
11078            let entry = project.entry_for_path(&project_path, cx)?;
11079            let parent = match &entry.canonical_path {
11080                Some(canonical_path) => canonical_path.to_path_buf(),
11081                None => project.absolute_path(&project_path, cx)?,
11082            }
11083            .parent()?
11084            .to_path_buf();
11085            Some(parent)
11086        }) {
11087            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11088        }
11089    }
11090
11091    fn set_breakpoint_context_menu(
11092        &mut self,
11093        display_row: DisplayRow,
11094        position: Option<Anchor>,
11095        clicked_point: gpui::Point<Pixels>,
11096        window: &mut Window,
11097        cx: &mut Context<Self>,
11098    ) {
11099        let source = self
11100            .buffer
11101            .read(cx)
11102            .snapshot(cx)
11103            .anchor_before(Point::new(display_row.0, 0u32));
11104
11105        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11106
11107        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11108            self,
11109            source,
11110            clicked_point,
11111            context_menu,
11112            window,
11113            cx,
11114        );
11115    }
11116
11117    fn add_edit_breakpoint_block(
11118        &mut self,
11119        anchor: Anchor,
11120        breakpoint: &Breakpoint,
11121        edit_action: BreakpointPromptEditAction,
11122        window: &mut Window,
11123        cx: &mut Context<Self>,
11124    ) {
11125        let weak_editor = cx.weak_entity();
11126        let bp_prompt = cx.new(|cx| {
11127            BreakpointPromptEditor::new(
11128                weak_editor,
11129                anchor,
11130                breakpoint.clone(),
11131                edit_action,
11132                window,
11133                cx,
11134            )
11135        });
11136
11137        let height = bp_prompt.update(cx, |this, cx| {
11138            this.prompt
11139                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11140        });
11141        let cloned_prompt = bp_prompt.clone();
11142        let blocks = vec![BlockProperties {
11143            style: BlockStyle::Sticky,
11144            placement: BlockPlacement::Above(anchor),
11145            height: Some(height),
11146            render: Arc::new(move |cx| {
11147                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11148                cloned_prompt.clone().into_any_element()
11149            }),
11150            priority: 0,
11151        }];
11152
11153        let focus_handle = bp_prompt.focus_handle(cx);
11154        window.focus(&focus_handle);
11155
11156        let block_ids = self.insert_blocks(blocks, None, cx);
11157        bp_prompt.update(cx, |prompt, _| {
11158            prompt.add_block_ids(block_ids);
11159        });
11160    }
11161
11162    pub(crate) fn breakpoint_at_row(
11163        &self,
11164        row: u32,
11165        window: &mut Window,
11166        cx: &mut Context<Self>,
11167    ) -> Option<(Anchor, Breakpoint)> {
11168        let snapshot = self.snapshot(window, cx);
11169        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11170
11171        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11172    }
11173
11174    pub(crate) fn breakpoint_at_anchor(
11175        &self,
11176        breakpoint_position: Anchor,
11177        snapshot: &EditorSnapshot,
11178        cx: &mut Context<Self>,
11179    ) -> Option<(Anchor, Breakpoint)> {
11180        let buffer = self
11181            .buffer
11182            .read(cx)
11183            .buffer_for_anchor(breakpoint_position, cx)?;
11184
11185        let enclosing_excerpt = breakpoint_position.excerpt_id;
11186        let buffer_snapshot = buffer.read(cx).snapshot();
11187
11188        let row = buffer_snapshot
11189            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11190            .row;
11191
11192        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11193        let anchor_end = snapshot
11194            .buffer_snapshot()
11195            .anchor_after(Point::new(row, line_len));
11196
11197        self.breakpoint_store
11198            .as_ref()?
11199            .read_with(cx, |breakpoint_store, cx| {
11200                breakpoint_store
11201                    .breakpoints(
11202                        &buffer,
11203                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11204                        &buffer_snapshot,
11205                        cx,
11206                    )
11207                    .next()
11208                    .and_then(|(bp, _)| {
11209                        let breakpoint_row = buffer_snapshot
11210                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11211                            .row;
11212
11213                        if breakpoint_row == row {
11214                            snapshot
11215                                .buffer_snapshot()
11216                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11217                                .map(|position| (position, bp.bp.clone()))
11218                        } else {
11219                            None
11220                        }
11221                    })
11222            })
11223    }
11224
11225    pub fn edit_log_breakpoint(
11226        &mut self,
11227        _: &EditLogBreakpoint,
11228        window: &mut Window,
11229        cx: &mut Context<Self>,
11230    ) {
11231        if self.breakpoint_store.is_none() {
11232            return;
11233        }
11234
11235        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11236            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11237                message: None,
11238                state: BreakpointState::Enabled,
11239                condition: None,
11240                hit_condition: None,
11241            });
11242
11243            self.add_edit_breakpoint_block(
11244                anchor,
11245                &breakpoint,
11246                BreakpointPromptEditAction::Log,
11247                window,
11248                cx,
11249            );
11250        }
11251    }
11252
11253    fn breakpoints_at_cursors(
11254        &self,
11255        window: &mut Window,
11256        cx: &mut Context<Self>,
11257    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11258        let snapshot = self.snapshot(window, cx);
11259        let cursors = self
11260            .selections
11261            .disjoint_anchors_arc()
11262            .iter()
11263            .map(|selection| {
11264                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11265
11266                let breakpoint_position = self
11267                    .breakpoint_at_row(cursor_position.row, window, cx)
11268                    .map(|bp| bp.0)
11269                    .unwrap_or_else(|| {
11270                        snapshot
11271                            .display_snapshot
11272                            .buffer_snapshot()
11273                            .anchor_after(Point::new(cursor_position.row, 0))
11274                    });
11275
11276                let breakpoint = self
11277                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11278                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11279
11280                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11281            })
11282            // 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.
11283            .collect::<HashMap<Anchor, _>>();
11284
11285        cursors.into_iter().collect()
11286    }
11287
11288    pub fn enable_breakpoint(
11289        &mut self,
11290        _: &crate::actions::EnableBreakpoint,
11291        window: &mut Window,
11292        cx: &mut Context<Self>,
11293    ) {
11294        if self.breakpoint_store.is_none() {
11295            return;
11296        }
11297
11298        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11299            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11300                continue;
11301            };
11302            self.edit_breakpoint_at_anchor(
11303                anchor,
11304                breakpoint,
11305                BreakpointEditAction::InvertState,
11306                cx,
11307            );
11308        }
11309    }
11310
11311    pub fn disable_breakpoint(
11312        &mut self,
11313        _: &crate::actions::DisableBreakpoint,
11314        window: &mut Window,
11315        cx: &mut Context<Self>,
11316    ) {
11317        if self.breakpoint_store.is_none() {
11318            return;
11319        }
11320
11321        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11322            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11323                continue;
11324            };
11325            self.edit_breakpoint_at_anchor(
11326                anchor,
11327                breakpoint,
11328                BreakpointEditAction::InvertState,
11329                cx,
11330            );
11331        }
11332    }
11333
11334    pub fn toggle_breakpoint(
11335        &mut self,
11336        _: &crate::actions::ToggleBreakpoint,
11337        window: &mut Window,
11338        cx: &mut Context<Self>,
11339    ) {
11340        if self.breakpoint_store.is_none() {
11341            return;
11342        }
11343
11344        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11345            if let Some(breakpoint) = breakpoint {
11346                self.edit_breakpoint_at_anchor(
11347                    anchor,
11348                    breakpoint,
11349                    BreakpointEditAction::Toggle,
11350                    cx,
11351                );
11352            } else {
11353                self.edit_breakpoint_at_anchor(
11354                    anchor,
11355                    Breakpoint::new_standard(),
11356                    BreakpointEditAction::Toggle,
11357                    cx,
11358                );
11359            }
11360        }
11361    }
11362
11363    pub fn edit_breakpoint_at_anchor(
11364        &mut self,
11365        breakpoint_position: Anchor,
11366        breakpoint: Breakpoint,
11367        edit_action: BreakpointEditAction,
11368        cx: &mut Context<Self>,
11369    ) {
11370        let Some(breakpoint_store) = &self.breakpoint_store else {
11371            return;
11372        };
11373
11374        let Some(buffer) = self
11375            .buffer
11376            .read(cx)
11377            .buffer_for_anchor(breakpoint_position, cx)
11378        else {
11379            return;
11380        };
11381
11382        breakpoint_store.update(cx, |breakpoint_store, cx| {
11383            breakpoint_store.toggle_breakpoint(
11384                buffer,
11385                BreakpointWithPosition {
11386                    position: breakpoint_position.text_anchor,
11387                    bp: breakpoint,
11388                },
11389                edit_action,
11390                cx,
11391            );
11392        });
11393
11394        cx.notify();
11395    }
11396
11397    #[cfg(any(test, feature = "test-support"))]
11398    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11399        self.breakpoint_store.clone()
11400    }
11401
11402    pub fn prepare_restore_change(
11403        &self,
11404        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11405        hunk: &MultiBufferDiffHunk,
11406        cx: &mut App,
11407    ) -> Option<()> {
11408        if hunk.is_created_file() {
11409            return None;
11410        }
11411        let buffer = self.buffer.read(cx);
11412        let diff = buffer.diff_for(hunk.buffer_id)?;
11413        let buffer = buffer.buffer(hunk.buffer_id)?;
11414        let buffer = buffer.read(cx);
11415        let original_text = diff
11416            .read(cx)
11417            .base_text()
11418            .as_rope()
11419            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11420        let buffer_snapshot = buffer.snapshot();
11421        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11422        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11423            probe
11424                .0
11425                .start
11426                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11427                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11428        }) {
11429            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11430            Some(())
11431        } else {
11432            None
11433        }
11434    }
11435
11436    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11437        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11438    }
11439
11440    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11441        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11442    }
11443
11444    fn manipulate_lines<M>(
11445        &mut self,
11446        window: &mut Window,
11447        cx: &mut Context<Self>,
11448        mut manipulate: M,
11449    ) where
11450        M: FnMut(&str) -> LineManipulationResult,
11451    {
11452        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11453
11454        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11455        let buffer = self.buffer.read(cx).snapshot(cx);
11456
11457        let mut edits = Vec::new();
11458
11459        let selections = self.selections.all::<Point>(&display_map);
11460        let mut selections = selections.iter().peekable();
11461        let mut contiguous_row_selections = Vec::new();
11462        let mut new_selections = Vec::new();
11463        let mut added_lines = 0;
11464        let mut removed_lines = 0;
11465
11466        while let Some(selection) = selections.next() {
11467            let (start_row, end_row) = consume_contiguous_rows(
11468                &mut contiguous_row_selections,
11469                selection,
11470                &display_map,
11471                &mut selections,
11472            );
11473
11474            let start_point = Point::new(start_row.0, 0);
11475            let end_point = Point::new(
11476                end_row.previous_row().0,
11477                buffer.line_len(end_row.previous_row()),
11478            );
11479            let text = buffer
11480                .text_for_range(start_point..end_point)
11481                .collect::<String>();
11482
11483            let LineManipulationResult {
11484                new_text,
11485                line_count_before,
11486                line_count_after,
11487            } = manipulate(&text);
11488
11489            edits.push((start_point..end_point, new_text));
11490
11491            // Selections must change based on added and removed line count
11492            let start_row =
11493                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11494            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11495            new_selections.push(Selection {
11496                id: selection.id,
11497                start: start_row,
11498                end: end_row,
11499                goal: SelectionGoal::None,
11500                reversed: selection.reversed,
11501            });
11502
11503            if line_count_after > line_count_before {
11504                added_lines += line_count_after - line_count_before;
11505            } else if line_count_before > line_count_after {
11506                removed_lines += line_count_before - line_count_after;
11507            }
11508        }
11509
11510        self.transact(window, cx, |this, window, cx| {
11511            let buffer = this.buffer.update(cx, |buffer, cx| {
11512                buffer.edit(edits, None, cx);
11513                buffer.snapshot(cx)
11514            });
11515
11516            // Recalculate offsets on newly edited buffer
11517            let new_selections = new_selections
11518                .iter()
11519                .map(|s| {
11520                    let start_point = Point::new(s.start.0, 0);
11521                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11522                    Selection {
11523                        id: s.id,
11524                        start: buffer.point_to_offset(start_point),
11525                        end: buffer.point_to_offset(end_point),
11526                        goal: s.goal,
11527                        reversed: s.reversed,
11528                    }
11529                })
11530                .collect();
11531
11532            this.change_selections(Default::default(), window, cx, |s| {
11533                s.select(new_selections);
11534            });
11535
11536            this.request_autoscroll(Autoscroll::fit(), cx);
11537        });
11538    }
11539
11540    fn manipulate_immutable_lines<Fn>(
11541        &mut self,
11542        window: &mut Window,
11543        cx: &mut Context<Self>,
11544        mut callback: Fn,
11545    ) where
11546        Fn: FnMut(&mut Vec<&str>),
11547    {
11548        self.manipulate_lines(window, cx, |text| {
11549            let mut lines: Vec<&str> = text.split('\n').collect();
11550            let line_count_before = lines.len();
11551
11552            callback(&mut lines);
11553
11554            LineManipulationResult {
11555                new_text: lines.join("\n"),
11556                line_count_before,
11557                line_count_after: lines.len(),
11558            }
11559        });
11560    }
11561
11562    fn manipulate_mutable_lines<Fn>(
11563        &mut self,
11564        window: &mut Window,
11565        cx: &mut Context<Self>,
11566        mut callback: Fn,
11567    ) where
11568        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11569    {
11570        self.manipulate_lines(window, cx, |text| {
11571            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11572            let line_count_before = lines.len();
11573
11574            callback(&mut lines);
11575
11576            LineManipulationResult {
11577                new_text: lines.join("\n"),
11578                line_count_before,
11579                line_count_after: lines.len(),
11580            }
11581        });
11582    }
11583
11584    pub fn convert_indentation_to_spaces(
11585        &mut self,
11586        _: &ConvertIndentationToSpaces,
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 scratch 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.as_ref().chars();
11603                let mut col = 0;
11604                let mut changed = false;
11605
11606                for ch in chars.by_ref() {
11607                    match ch {
11608                        ' ' => {
11609                            reindented_line.push(' ');
11610                            col += 1;
11611                        }
11612                        '\t' => {
11613                            // \t are converted to spaces depending on the current column
11614                            let spaces_len = tab_size - (col % tab_size);
11615                            reindented_line.extend(&space_cache[spaces_len - 1]);
11616                            col += spaces_len;
11617                            changed = true;
11618                        }
11619                        _ => {
11620                            // If we dont append before break, the character is consumed
11621                            reindented_line.push(ch);
11622                            break;
11623                        }
11624                    }
11625                }
11626
11627                if !changed {
11628                    reindented_line.clear();
11629                    continue;
11630                }
11631                // Append the rest of the line and replace old reference with new one
11632                reindented_line.extend(chars);
11633                *line = Cow::Owned(reindented_line.clone());
11634                reindented_line.clear();
11635            }
11636        });
11637    }
11638
11639    pub fn convert_indentation_to_tabs(
11640        &mut self,
11641        _: &ConvertIndentationToTabs,
11642        window: &mut Window,
11643        cx: &mut Context<Self>,
11644    ) {
11645        let settings = self.buffer.read(cx).language_settings(cx);
11646        let tab_size = settings.tab_size.get() as usize;
11647
11648        self.manipulate_mutable_lines(window, cx, |lines| {
11649            // Allocates a reasonably sized buffer once for the whole loop
11650            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11651            // Avoids recomputing spaces that could be inserted many times
11652            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11653                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11654                .collect();
11655
11656            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11657                let mut chars = line.chars();
11658                let mut spaces_count = 0;
11659                let mut first_non_indent_char = None;
11660                let mut changed = false;
11661
11662                for ch in chars.by_ref() {
11663                    match ch {
11664                        ' ' => {
11665                            // Keep track of spaces. Append \t when we reach tab_size
11666                            spaces_count += 1;
11667                            changed = true;
11668                            if spaces_count == tab_size {
11669                                reindented_line.push('\t');
11670                                spaces_count = 0;
11671                            }
11672                        }
11673                        '\t' => {
11674                            reindented_line.push('\t');
11675                            spaces_count = 0;
11676                        }
11677                        _ => {
11678                            // Dont append it yet, we might have remaining spaces
11679                            first_non_indent_char = Some(ch);
11680                            break;
11681                        }
11682                    }
11683                }
11684
11685                if !changed {
11686                    reindented_line.clear();
11687                    continue;
11688                }
11689                // Remaining spaces that didn't make a full tab stop
11690                if spaces_count > 0 {
11691                    reindented_line.extend(&space_cache[spaces_count - 1]);
11692                }
11693                // If we consume an extra character that was not indentation, add it back
11694                if let Some(extra_char) = first_non_indent_char {
11695                    reindented_line.push(extra_char);
11696                }
11697                // Append the rest of the line and replace old reference with new one
11698                reindented_line.extend(chars);
11699                *line = Cow::Owned(reindented_line.clone());
11700                reindented_line.clear();
11701            }
11702        });
11703    }
11704
11705    pub fn convert_to_upper_case(
11706        &mut self,
11707        _: &ConvertToUpperCase,
11708        window: &mut Window,
11709        cx: &mut Context<Self>,
11710    ) {
11711        self.manipulate_text(window, cx, |text| text.to_uppercase())
11712    }
11713
11714    pub fn convert_to_lower_case(
11715        &mut self,
11716        _: &ConvertToLowerCase,
11717        window: &mut Window,
11718        cx: &mut Context<Self>,
11719    ) {
11720        self.manipulate_text(window, cx, |text| text.to_lowercase())
11721    }
11722
11723    pub fn convert_to_title_case(
11724        &mut self,
11725        _: &ConvertToTitleCase,
11726        window: &mut Window,
11727        cx: &mut Context<Self>,
11728    ) {
11729        self.manipulate_text(window, cx, |text| {
11730            text.split('\n')
11731                .map(|line| line.to_case(Case::Title))
11732                .join("\n")
11733        })
11734    }
11735
11736    pub fn convert_to_snake_case(
11737        &mut self,
11738        _: &ConvertToSnakeCase,
11739        window: &mut Window,
11740        cx: &mut Context<Self>,
11741    ) {
11742        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11743    }
11744
11745    pub fn convert_to_kebab_case(
11746        &mut self,
11747        _: &ConvertToKebabCase,
11748        window: &mut Window,
11749        cx: &mut Context<Self>,
11750    ) {
11751        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11752    }
11753
11754    pub fn convert_to_upper_camel_case(
11755        &mut self,
11756        _: &ConvertToUpperCamelCase,
11757        window: &mut Window,
11758        cx: &mut Context<Self>,
11759    ) {
11760        self.manipulate_text(window, cx, |text| {
11761            text.split('\n')
11762                .map(|line| line.to_case(Case::UpperCamel))
11763                .join("\n")
11764        })
11765    }
11766
11767    pub fn convert_to_lower_camel_case(
11768        &mut self,
11769        _: &ConvertToLowerCamelCase,
11770        window: &mut Window,
11771        cx: &mut Context<Self>,
11772    ) {
11773        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11774    }
11775
11776    pub fn convert_to_opposite_case(
11777        &mut self,
11778        _: &ConvertToOppositeCase,
11779        window: &mut Window,
11780        cx: &mut Context<Self>,
11781    ) {
11782        self.manipulate_text(window, cx, |text| {
11783            text.chars()
11784                .fold(String::with_capacity(text.len()), |mut t, c| {
11785                    if c.is_uppercase() {
11786                        t.extend(c.to_lowercase());
11787                    } else {
11788                        t.extend(c.to_uppercase());
11789                    }
11790                    t
11791                })
11792        })
11793    }
11794
11795    pub fn convert_to_sentence_case(
11796        &mut self,
11797        _: &ConvertToSentenceCase,
11798        window: &mut Window,
11799        cx: &mut Context<Self>,
11800    ) {
11801        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11802    }
11803
11804    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11805        self.manipulate_text(window, cx, |text| {
11806            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11807            if has_upper_case_characters {
11808                text.to_lowercase()
11809            } else {
11810                text.to_uppercase()
11811            }
11812        })
11813    }
11814
11815    pub fn convert_to_rot13(
11816        &mut self,
11817        _: &ConvertToRot13,
11818        window: &mut Window,
11819        cx: &mut Context<Self>,
11820    ) {
11821        self.manipulate_text(window, cx, |text| {
11822            text.chars()
11823                .map(|c| match c {
11824                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11825                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11826                    _ => c,
11827                })
11828                .collect()
11829        })
11830    }
11831
11832    pub fn convert_to_rot47(
11833        &mut self,
11834        _: &ConvertToRot47,
11835        window: &mut Window,
11836        cx: &mut Context<Self>,
11837    ) {
11838        self.manipulate_text(window, cx, |text| {
11839            text.chars()
11840                .map(|c| {
11841                    let code_point = c as u32;
11842                    if code_point >= 33 && code_point <= 126 {
11843                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11844                    }
11845                    c
11846                })
11847                .collect()
11848        })
11849    }
11850
11851    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11852    where
11853        Fn: FnMut(&str) -> String,
11854    {
11855        let buffer = self.buffer.read(cx).snapshot(cx);
11856
11857        let mut new_selections = Vec::new();
11858        let mut edits = Vec::new();
11859        let mut selection_adjustment = 0isize;
11860
11861        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11862            let selection_is_empty = selection.is_empty();
11863
11864            let (start, end) = if selection_is_empty {
11865                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11866                (word_range.start, word_range.end)
11867            } else {
11868                (
11869                    buffer.point_to_offset(selection.start),
11870                    buffer.point_to_offset(selection.end),
11871                )
11872            };
11873
11874            let text = buffer.text_for_range(start..end).collect::<String>();
11875            let old_length = text.len() as isize;
11876            let text = callback(&text);
11877
11878            new_selections.push(Selection {
11879                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
11880                end: MultiBufferOffset(
11881                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
11882                ),
11883                goal: SelectionGoal::None,
11884                id: selection.id,
11885                reversed: selection.reversed,
11886            });
11887
11888            selection_adjustment += old_length - text.len() as isize;
11889
11890            edits.push((start..end, text));
11891        }
11892
11893        self.transact(window, cx, |this, window, cx| {
11894            this.buffer.update(cx, |buffer, cx| {
11895                buffer.edit(edits, None, cx);
11896            });
11897
11898            this.change_selections(Default::default(), window, cx, |s| {
11899                s.select(new_selections);
11900            });
11901
11902            this.request_autoscroll(Autoscroll::fit(), cx);
11903        });
11904    }
11905
11906    pub fn move_selection_on_drop(
11907        &mut self,
11908        selection: &Selection<Anchor>,
11909        target: DisplayPoint,
11910        is_cut: bool,
11911        window: &mut Window,
11912        cx: &mut Context<Self>,
11913    ) {
11914        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11915        let buffer = display_map.buffer_snapshot();
11916        let mut edits = Vec::new();
11917        let insert_point = display_map
11918            .clip_point(target, Bias::Left)
11919            .to_point(&display_map);
11920        let text = buffer
11921            .text_for_range(selection.start..selection.end)
11922            .collect::<String>();
11923        if is_cut {
11924            edits.push(((selection.start..selection.end), String::new()));
11925        }
11926        let insert_anchor = buffer.anchor_before(insert_point);
11927        edits.push(((insert_anchor..insert_anchor), text));
11928        let last_edit_start = insert_anchor.bias_left(buffer);
11929        let last_edit_end = insert_anchor.bias_right(buffer);
11930        self.transact(window, cx, |this, window, cx| {
11931            this.buffer.update(cx, |buffer, cx| {
11932                buffer.edit(edits, None, cx);
11933            });
11934            this.change_selections(Default::default(), window, cx, |s| {
11935                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11936            });
11937        });
11938    }
11939
11940    pub fn clear_selection_drag_state(&mut self) {
11941        self.selection_drag_state = SelectionDragState::None;
11942    }
11943
11944    pub fn duplicate(
11945        &mut self,
11946        upwards: bool,
11947        whole_lines: bool,
11948        window: &mut Window,
11949        cx: &mut Context<Self>,
11950    ) {
11951        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11952
11953        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11954        let buffer = display_map.buffer_snapshot();
11955        let selections = self.selections.all::<Point>(&display_map);
11956
11957        let mut edits = Vec::new();
11958        let mut selections_iter = selections.iter().peekable();
11959        while let Some(selection) = selections_iter.next() {
11960            let mut rows = selection.spanned_rows(false, &display_map);
11961            // duplicate line-wise
11962            if whole_lines || selection.start == selection.end {
11963                // Avoid duplicating the same lines twice.
11964                while let Some(next_selection) = selections_iter.peek() {
11965                    let next_rows = next_selection.spanned_rows(false, &display_map);
11966                    if next_rows.start < rows.end {
11967                        rows.end = next_rows.end;
11968                        selections_iter.next().unwrap();
11969                    } else {
11970                        break;
11971                    }
11972                }
11973
11974                // Copy the text from the selected row region and splice it either at the start
11975                // or end of the region.
11976                let start = Point::new(rows.start.0, 0);
11977                let end = Point::new(
11978                    rows.end.previous_row().0,
11979                    buffer.line_len(rows.end.previous_row()),
11980                );
11981
11982                let mut text = buffer.text_for_range(start..end).collect::<String>();
11983
11984                let insert_location = if upwards {
11985                    // When duplicating upward, we need to insert before the current line.
11986                    // If we're on the last line and it doesn't end with a newline,
11987                    // we need to add a newline before the duplicated content.
11988                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11989                        && buffer.max_point().column > 0
11990                        && !text.ends_with('\n');
11991
11992                    if needs_leading_newline {
11993                        text.insert(0, '\n');
11994                        end
11995                    } else {
11996                        text.push('\n');
11997                        Point::new(rows.start.0, 0)
11998                    }
11999                } else {
12000                    text.push('\n');
12001                    start
12002                };
12003                edits.push((insert_location..insert_location, text));
12004            } else {
12005                // duplicate character-wise
12006                let start = selection.start;
12007                let end = selection.end;
12008                let text = buffer.text_for_range(start..end).collect::<String>();
12009                edits.push((selection.end..selection.end, text));
12010            }
12011        }
12012
12013        self.transact(window, cx, |this, window, cx| {
12014            this.buffer.update(cx, |buffer, cx| {
12015                buffer.edit(edits, None, cx);
12016            });
12017
12018            // When duplicating upward with whole lines, move the cursor to the duplicated line
12019            if upwards && whole_lines {
12020                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12021
12022                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12023                    let mut new_ranges = Vec::new();
12024                    let selections = s.all::<Point>(&display_map);
12025                    let mut selections_iter = selections.iter().peekable();
12026
12027                    while let Some(first_selection) = selections_iter.next() {
12028                        // Group contiguous selections together to find the total row span
12029                        let mut group_selections = vec![first_selection];
12030                        let mut rows = first_selection.spanned_rows(false, &display_map);
12031
12032                        while let Some(next_selection) = selections_iter.peek() {
12033                            let next_rows = next_selection.spanned_rows(false, &display_map);
12034                            if next_rows.start < rows.end {
12035                                rows.end = next_rows.end;
12036                                group_selections.push(selections_iter.next().unwrap());
12037                            } else {
12038                                break;
12039                            }
12040                        }
12041
12042                        let row_count = rows.end.0 - rows.start.0;
12043
12044                        // Move all selections in this group up by the total number of duplicated rows
12045                        for selection in group_selections {
12046                            let new_start = Point::new(
12047                                selection.start.row.saturating_sub(row_count),
12048                                selection.start.column,
12049                            );
12050
12051                            let new_end = Point::new(
12052                                selection.end.row.saturating_sub(row_count),
12053                                selection.end.column,
12054                            );
12055
12056                            new_ranges.push(new_start..new_end);
12057                        }
12058                    }
12059
12060                    s.select_ranges(new_ranges);
12061                });
12062            }
12063
12064            this.request_autoscroll(Autoscroll::fit(), cx);
12065        });
12066    }
12067
12068    pub fn duplicate_line_up(
12069        &mut self,
12070        _: &DuplicateLineUp,
12071        window: &mut Window,
12072        cx: &mut Context<Self>,
12073    ) {
12074        self.duplicate(true, true, window, cx);
12075    }
12076
12077    pub fn duplicate_line_down(
12078        &mut self,
12079        _: &DuplicateLineDown,
12080        window: &mut Window,
12081        cx: &mut Context<Self>,
12082    ) {
12083        self.duplicate(false, true, window, cx);
12084    }
12085
12086    pub fn duplicate_selection(
12087        &mut self,
12088        _: &DuplicateSelection,
12089        window: &mut Window,
12090        cx: &mut Context<Self>,
12091    ) {
12092        self.duplicate(false, false, window, cx);
12093    }
12094
12095    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12096        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12097        if self.mode.is_single_line() {
12098            cx.propagate();
12099            return;
12100        }
12101
12102        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12103        let buffer = self.buffer.read(cx).snapshot(cx);
12104
12105        let mut edits = Vec::new();
12106        let mut unfold_ranges = Vec::new();
12107        let mut refold_creases = Vec::new();
12108
12109        let selections = self.selections.all::<Point>(&display_map);
12110        let mut selections = selections.iter().peekable();
12111        let mut contiguous_row_selections = Vec::new();
12112        let mut new_selections = Vec::new();
12113
12114        while let Some(selection) = selections.next() {
12115            // Find all the selections that span a contiguous row range
12116            let (start_row, end_row) = consume_contiguous_rows(
12117                &mut contiguous_row_selections,
12118                selection,
12119                &display_map,
12120                &mut selections,
12121            );
12122
12123            // Move the text spanned by the row range to be before the line preceding the row range
12124            if start_row.0 > 0 {
12125                let range_to_move = Point::new(
12126                    start_row.previous_row().0,
12127                    buffer.line_len(start_row.previous_row()),
12128                )
12129                    ..Point::new(
12130                        end_row.previous_row().0,
12131                        buffer.line_len(end_row.previous_row()),
12132                    );
12133                let insertion_point = display_map
12134                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12135                    .0;
12136
12137                // Don't move lines across excerpts
12138                if buffer
12139                    .excerpt_containing(insertion_point..range_to_move.end)
12140                    .is_some()
12141                {
12142                    let text = buffer
12143                        .text_for_range(range_to_move.clone())
12144                        .flat_map(|s| s.chars())
12145                        .skip(1)
12146                        .chain(['\n'])
12147                        .collect::<String>();
12148
12149                    edits.push((
12150                        buffer.anchor_after(range_to_move.start)
12151                            ..buffer.anchor_before(range_to_move.end),
12152                        String::new(),
12153                    ));
12154                    let insertion_anchor = buffer.anchor_after(insertion_point);
12155                    edits.push((insertion_anchor..insertion_anchor, text));
12156
12157                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12158
12159                    // Move selections up
12160                    new_selections.extend(contiguous_row_selections.drain(..).map(
12161                        |mut selection| {
12162                            selection.start.row -= row_delta;
12163                            selection.end.row -= row_delta;
12164                            selection
12165                        },
12166                    ));
12167
12168                    // Move folds up
12169                    unfold_ranges.push(range_to_move.clone());
12170                    for fold in display_map.folds_in_range(
12171                        buffer.anchor_before(range_to_move.start)
12172                            ..buffer.anchor_after(range_to_move.end),
12173                    ) {
12174                        let mut start = fold.range.start.to_point(&buffer);
12175                        let mut end = fold.range.end.to_point(&buffer);
12176                        start.row -= row_delta;
12177                        end.row -= row_delta;
12178                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12179                    }
12180                }
12181            }
12182
12183            // If we didn't move line(s), preserve the existing selections
12184            new_selections.append(&mut contiguous_row_selections);
12185        }
12186
12187        self.transact(window, cx, |this, window, cx| {
12188            this.unfold_ranges(&unfold_ranges, true, true, cx);
12189            this.buffer.update(cx, |buffer, cx| {
12190                for (range, text) in edits {
12191                    buffer.edit([(range, text)], None, cx);
12192                }
12193            });
12194            this.fold_creases(refold_creases, true, window, cx);
12195            this.change_selections(Default::default(), window, cx, |s| {
12196                s.select(new_selections);
12197            })
12198        });
12199    }
12200
12201    pub fn move_line_down(
12202        &mut self,
12203        _: &MoveLineDown,
12204        window: &mut Window,
12205        cx: &mut Context<Self>,
12206    ) {
12207        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12208        if self.mode.is_single_line() {
12209            cx.propagate();
12210            return;
12211        }
12212
12213        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12214        let buffer = self.buffer.read(cx).snapshot(cx);
12215
12216        let mut edits = Vec::new();
12217        let mut unfold_ranges = Vec::new();
12218        let mut refold_creases = Vec::new();
12219
12220        let selections = self.selections.all::<Point>(&display_map);
12221        let mut selections = selections.iter().peekable();
12222        let mut contiguous_row_selections = Vec::new();
12223        let mut new_selections = Vec::new();
12224
12225        while let Some(selection) = selections.next() {
12226            // Find all the selections that span a contiguous row range
12227            let (start_row, end_row) = consume_contiguous_rows(
12228                &mut contiguous_row_selections,
12229                selection,
12230                &display_map,
12231                &mut selections,
12232            );
12233
12234            // Move the text spanned by the row range to be after the last line of the row range
12235            if end_row.0 <= buffer.max_point().row {
12236                let range_to_move =
12237                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12238                let insertion_point = display_map
12239                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12240                    .0;
12241
12242                // Don't move lines across excerpt boundaries
12243                if buffer
12244                    .excerpt_containing(range_to_move.start..insertion_point)
12245                    .is_some()
12246                {
12247                    let mut text = String::from("\n");
12248                    text.extend(buffer.text_for_range(range_to_move.clone()));
12249                    text.pop(); // Drop trailing newline
12250                    edits.push((
12251                        buffer.anchor_after(range_to_move.start)
12252                            ..buffer.anchor_before(range_to_move.end),
12253                        String::new(),
12254                    ));
12255                    let insertion_anchor = buffer.anchor_after(insertion_point);
12256                    edits.push((insertion_anchor..insertion_anchor, text));
12257
12258                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12259
12260                    // Move selections down
12261                    new_selections.extend(contiguous_row_selections.drain(..).map(
12262                        |mut selection| {
12263                            selection.start.row += row_delta;
12264                            selection.end.row += row_delta;
12265                            selection
12266                        },
12267                    ));
12268
12269                    // Move folds down
12270                    unfold_ranges.push(range_to_move.clone());
12271                    for fold in display_map.folds_in_range(
12272                        buffer.anchor_before(range_to_move.start)
12273                            ..buffer.anchor_after(range_to_move.end),
12274                    ) {
12275                        let mut start = fold.range.start.to_point(&buffer);
12276                        let mut end = fold.range.end.to_point(&buffer);
12277                        start.row += row_delta;
12278                        end.row += row_delta;
12279                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12280                    }
12281                }
12282            }
12283
12284            // If we didn't move line(s), preserve the existing selections
12285            new_selections.append(&mut contiguous_row_selections);
12286        }
12287
12288        self.transact(window, cx, |this, window, cx| {
12289            this.unfold_ranges(&unfold_ranges, true, true, cx);
12290            this.buffer.update(cx, |buffer, cx| {
12291                for (range, text) in edits {
12292                    buffer.edit([(range, text)], None, cx);
12293                }
12294            });
12295            this.fold_creases(refold_creases, true, window, cx);
12296            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12297        });
12298    }
12299
12300    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12301        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12302        let text_layout_details = &self.text_layout_details(window);
12303        self.transact(window, cx, |this, window, cx| {
12304            let edits = this.change_selections(Default::default(), window, cx, |s| {
12305                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12306                s.move_with(|display_map, selection| {
12307                    if !selection.is_empty() {
12308                        return;
12309                    }
12310
12311                    let mut head = selection.head();
12312                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12313                    if head.column() == display_map.line_len(head.row()) {
12314                        transpose_offset = display_map
12315                            .buffer_snapshot()
12316                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12317                    }
12318
12319                    if transpose_offset == MultiBufferOffset(0) {
12320                        return;
12321                    }
12322
12323                    *head.column_mut() += 1;
12324                    head = display_map.clip_point(head, Bias::Right);
12325                    let goal = SelectionGoal::HorizontalPosition(
12326                        display_map
12327                            .x_for_display_point(head, text_layout_details)
12328                            .into(),
12329                    );
12330                    selection.collapse_to(head, goal);
12331
12332                    let transpose_start = display_map
12333                        .buffer_snapshot()
12334                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12335                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12336                        let transpose_end = display_map
12337                            .buffer_snapshot()
12338                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12339                        if let Some(ch) = display_map
12340                            .buffer_snapshot()
12341                            .chars_at(transpose_start)
12342                            .next()
12343                        {
12344                            edits.push((transpose_start..transpose_offset, String::new()));
12345                            edits.push((transpose_end..transpose_end, ch.to_string()));
12346                        }
12347                    }
12348                });
12349                edits
12350            });
12351            this.buffer
12352                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12353            let selections = this
12354                .selections
12355                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12356            this.change_selections(Default::default(), window, cx, |s| {
12357                s.select(selections);
12358            });
12359        });
12360    }
12361
12362    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12363        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12364        if self.mode.is_single_line() {
12365            cx.propagate();
12366            return;
12367        }
12368
12369        self.rewrap_impl(RewrapOptions::default(), cx)
12370    }
12371
12372    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12373        let buffer = self.buffer.read(cx).snapshot(cx);
12374        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12375
12376        #[derive(Clone, Debug, PartialEq)]
12377        enum CommentFormat {
12378            /// single line comment, with prefix for line
12379            Line(String),
12380            /// single line within a block comment, with prefix for line
12381            BlockLine(String),
12382            /// a single line of a block comment that includes the initial delimiter
12383            BlockCommentWithStart(BlockCommentConfig),
12384            /// a single line of a block comment that includes the ending delimiter
12385            BlockCommentWithEnd(BlockCommentConfig),
12386        }
12387
12388        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12389        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12390            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12391                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12392                .peekable();
12393
12394            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12395                row
12396            } else {
12397                return Vec::new();
12398            };
12399
12400            let language_settings = buffer.language_settings_at(selection.head(), cx);
12401            let language_scope = buffer.language_scope_at(selection.head());
12402
12403            let indent_and_prefix_for_row =
12404                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12405                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12406                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12407                        &language_scope
12408                    {
12409                        let indent_end = Point::new(row, indent.len);
12410                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12411                        let line_text_after_indent = buffer
12412                            .text_for_range(indent_end..line_end)
12413                            .collect::<String>();
12414
12415                        let is_within_comment_override = buffer
12416                            .language_scope_at(indent_end)
12417                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12418                        let comment_delimiters = if is_within_comment_override {
12419                            // we are within a comment syntax node, but we don't
12420                            // yet know what kind of comment: block, doc or line
12421                            match (
12422                                language_scope.documentation_comment(),
12423                                language_scope.block_comment(),
12424                            ) {
12425                                (Some(config), _) | (_, Some(config))
12426                                    if buffer.contains_str_at(indent_end, &config.start) =>
12427                                {
12428                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12429                                }
12430                                (Some(config), _) | (_, Some(config))
12431                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12432                                {
12433                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12434                                }
12435                                (Some(config), _) | (_, Some(config))
12436                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12437                                {
12438                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12439                                }
12440                                (_, _) => language_scope
12441                                    .line_comment_prefixes()
12442                                    .iter()
12443                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12444                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12445                            }
12446                        } else {
12447                            // we not in an overridden comment node, but we may
12448                            // be within a non-overridden line comment node
12449                            language_scope
12450                                .line_comment_prefixes()
12451                                .iter()
12452                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12453                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12454                        };
12455
12456                        let rewrap_prefix = language_scope
12457                            .rewrap_prefixes()
12458                            .iter()
12459                            .find_map(|prefix_regex| {
12460                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12461                                    if mat.start() == 0 {
12462                                        Some(mat.as_str().to_string())
12463                                    } else {
12464                                        None
12465                                    }
12466                                })
12467                            })
12468                            .flatten();
12469                        (comment_delimiters, rewrap_prefix)
12470                    } else {
12471                        (None, None)
12472                    };
12473                    (indent, comment_prefix, rewrap_prefix)
12474                };
12475
12476            let mut ranges = Vec::new();
12477            let from_empty_selection = selection.is_empty();
12478
12479            let mut current_range_start = first_row;
12480            let mut prev_row = first_row;
12481            let (
12482                mut current_range_indent,
12483                mut current_range_comment_delimiters,
12484                mut current_range_rewrap_prefix,
12485            ) = indent_and_prefix_for_row(first_row);
12486
12487            for row in non_blank_rows_iter.skip(1) {
12488                let has_paragraph_break = row > prev_row + 1;
12489
12490                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12491                    indent_and_prefix_for_row(row);
12492
12493                let has_indent_change = row_indent != current_range_indent;
12494                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12495
12496                let has_boundary_change = has_comment_change
12497                    || row_rewrap_prefix.is_some()
12498                    || (has_indent_change && current_range_comment_delimiters.is_some());
12499
12500                if has_paragraph_break || has_boundary_change {
12501                    ranges.push((
12502                        language_settings.clone(),
12503                        Point::new(current_range_start, 0)
12504                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12505                        current_range_indent,
12506                        current_range_comment_delimiters.clone(),
12507                        current_range_rewrap_prefix.clone(),
12508                        from_empty_selection,
12509                    ));
12510                    current_range_start = row;
12511                    current_range_indent = row_indent;
12512                    current_range_comment_delimiters = row_comment_delimiters;
12513                    current_range_rewrap_prefix = row_rewrap_prefix;
12514                }
12515                prev_row = row;
12516            }
12517
12518            ranges.push((
12519                language_settings.clone(),
12520                Point::new(current_range_start, 0)
12521                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12522                current_range_indent,
12523                current_range_comment_delimiters,
12524                current_range_rewrap_prefix,
12525                from_empty_selection,
12526            ));
12527
12528            ranges
12529        });
12530
12531        let mut edits = Vec::new();
12532        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12533
12534        for (
12535            language_settings,
12536            wrap_range,
12537            mut indent_size,
12538            comment_prefix,
12539            rewrap_prefix,
12540            from_empty_selection,
12541        ) in wrap_ranges
12542        {
12543            let mut start_row = wrap_range.start.row;
12544            let mut end_row = wrap_range.end.row;
12545
12546            // Skip selections that overlap with a range that has already been rewrapped.
12547            let selection_range = start_row..end_row;
12548            if rewrapped_row_ranges
12549                .iter()
12550                .any(|range| range.overlaps(&selection_range))
12551            {
12552                continue;
12553            }
12554
12555            let tab_size = language_settings.tab_size;
12556
12557            let (line_prefix, inside_comment) = match &comment_prefix {
12558                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12559                    (Some(prefix.as_str()), true)
12560                }
12561                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12562                    (Some(prefix.as_ref()), true)
12563                }
12564                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12565                    start: _,
12566                    end: _,
12567                    prefix,
12568                    tab_size,
12569                })) => {
12570                    indent_size.len += tab_size;
12571                    (Some(prefix.as_ref()), true)
12572                }
12573                None => (None, false),
12574            };
12575            let indent_prefix = indent_size.chars().collect::<String>();
12576            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12577
12578            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12579                RewrapBehavior::InComments => inside_comment,
12580                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12581                RewrapBehavior::Anywhere => true,
12582            };
12583
12584            let should_rewrap = options.override_language_settings
12585                || allow_rewrap_based_on_language
12586                || self.hard_wrap.is_some();
12587            if !should_rewrap {
12588                continue;
12589            }
12590
12591            if from_empty_selection {
12592                'expand_upwards: while start_row > 0 {
12593                    let prev_row = start_row - 1;
12594                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12595                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12596                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12597                    {
12598                        start_row = prev_row;
12599                    } else {
12600                        break 'expand_upwards;
12601                    }
12602                }
12603
12604                'expand_downwards: while end_row < buffer.max_point().row {
12605                    let next_row = end_row + 1;
12606                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12607                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12608                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12609                    {
12610                        end_row = next_row;
12611                    } else {
12612                        break 'expand_downwards;
12613                    }
12614                }
12615            }
12616
12617            let start = Point::new(start_row, 0);
12618            let start_offset = ToOffset::to_offset(&start, &buffer);
12619            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12620            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12621            let mut first_line_delimiter = None;
12622            let mut last_line_delimiter = None;
12623            let Some(lines_without_prefixes) = selection_text
12624                .lines()
12625                .enumerate()
12626                .map(|(ix, line)| {
12627                    let line_trimmed = line.trim_start();
12628                    if rewrap_prefix.is_some() && ix > 0 {
12629                        Ok(line_trimmed)
12630                    } else if let Some(
12631                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12632                            start,
12633                            prefix,
12634                            end,
12635                            tab_size,
12636                        })
12637                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12638                            start,
12639                            prefix,
12640                            end,
12641                            tab_size,
12642                        }),
12643                    ) = &comment_prefix
12644                    {
12645                        let line_trimmed = line_trimmed
12646                            .strip_prefix(start.as_ref())
12647                            .map(|s| {
12648                                let mut indent_size = indent_size;
12649                                indent_size.len -= tab_size;
12650                                let indent_prefix: String = indent_size.chars().collect();
12651                                first_line_delimiter = Some((indent_prefix, start));
12652                                s.trim_start()
12653                            })
12654                            .unwrap_or(line_trimmed);
12655                        let line_trimmed = line_trimmed
12656                            .strip_suffix(end.as_ref())
12657                            .map(|s| {
12658                                last_line_delimiter = Some(end);
12659                                s.trim_end()
12660                            })
12661                            .unwrap_or(line_trimmed);
12662                        let line_trimmed = line_trimmed
12663                            .strip_prefix(prefix.as_ref())
12664                            .unwrap_or(line_trimmed);
12665                        Ok(line_trimmed)
12666                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12667                        line_trimmed.strip_prefix(prefix).with_context(|| {
12668                            format!("line did not start with prefix {prefix:?}: {line:?}")
12669                        })
12670                    } else {
12671                        line_trimmed
12672                            .strip_prefix(&line_prefix.trim_start())
12673                            .with_context(|| {
12674                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12675                            })
12676                    }
12677                })
12678                .collect::<Result<Vec<_>, _>>()
12679                .log_err()
12680            else {
12681                continue;
12682            };
12683
12684            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12685                buffer
12686                    .language_settings_at(Point::new(start_row, 0), cx)
12687                    .preferred_line_length as usize
12688            });
12689
12690            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12691                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12692            } else {
12693                line_prefix.clone()
12694            };
12695
12696            let wrapped_text = {
12697                let mut wrapped_text = wrap_with_prefix(
12698                    line_prefix,
12699                    subsequent_lines_prefix,
12700                    lines_without_prefixes.join("\n"),
12701                    wrap_column,
12702                    tab_size,
12703                    options.preserve_existing_whitespace,
12704                );
12705
12706                if let Some((indent, delimiter)) = first_line_delimiter {
12707                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12708                }
12709                if let Some(last_line) = last_line_delimiter {
12710                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12711                }
12712
12713                wrapped_text
12714            };
12715
12716            // TODO: should always use char-based diff while still supporting cursor behavior that
12717            // matches vim.
12718            let mut diff_options = DiffOptions::default();
12719            if options.override_language_settings {
12720                diff_options.max_word_diff_len = 0;
12721                diff_options.max_word_diff_line_count = 0;
12722            } else {
12723                diff_options.max_word_diff_len = usize::MAX;
12724                diff_options.max_word_diff_line_count = usize::MAX;
12725            }
12726
12727            for (old_range, new_text) in
12728                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12729            {
12730                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12731                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12732                edits.push((edit_start..edit_end, new_text));
12733            }
12734
12735            rewrapped_row_ranges.push(start_row..=end_row);
12736        }
12737
12738        self.buffer
12739            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12740    }
12741
12742    pub fn cut_common(
12743        &mut self,
12744        cut_no_selection_line: bool,
12745        window: &mut Window,
12746        cx: &mut Context<Self>,
12747    ) -> ClipboardItem {
12748        let mut text = String::new();
12749        let buffer = self.buffer.read(cx).snapshot(cx);
12750        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12751        let mut clipboard_selections = Vec::with_capacity(selections.len());
12752        {
12753            let max_point = buffer.max_point();
12754            let mut is_first = true;
12755            let mut prev_selection_was_entire_line = false;
12756            for selection in &mut selections {
12757                let is_entire_line =
12758                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12759                if is_entire_line {
12760                    selection.start = Point::new(selection.start.row, 0);
12761                    if !selection.is_empty() && selection.end.column == 0 {
12762                        selection.end = cmp::min(max_point, selection.end);
12763                    } else {
12764                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12765                    }
12766                    selection.goal = SelectionGoal::None;
12767                }
12768                if is_first {
12769                    is_first = false;
12770                } else if !prev_selection_was_entire_line {
12771                    text += "\n";
12772                }
12773                prev_selection_was_entire_line = is_entire_line;
12774                let mut len = 0;
12775                for chunk in buffer.text_for_range(selection.start..selection.end) {
12776                    text.push_str(chunk);
12777                    len += chunk.len();
12778                }
12779                clipboard_selections.push(ClipboardSelection {
12780                    len,
12781                    is_entire_line,
12782                    first_line_indent: buffer
12783                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12784                        .len,
12785                });
12786            }
12787        }
12788
12789        self.transact(window, cx, |this, window, cx| {
12790            this.change_selections(Default::default(), window, cx, |s| {
12791                s.select(selections);
12792            });
12793            this.insert("", window, cx);
12794        });
12795        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12796    }
12797
12798    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12799        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12800        let item = self.cut_common(true, window, cx);
12801        cx.write_to_clipboard(item);
12802    }
12803
12804    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12805        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12806        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12807            s.move_with(|snapshot, sel| {
12808                if sel.is_empty() {
12809                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12810                }
12811                if sel.is_empty() {
12812                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12813                }
12814            });
12815        });
12816        let item = self.cut_common(false, window, cx);
12817        cx.set_global(KillRing(item))
12818    }
12819
12820    pub fn kill_ring_yank(
12821        &mut self,
12822        _: &KillRingYank,
12823        window: &mut Window,
12824        cx: &mut Context<Self>,
12825    ) {
12826        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12827        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12828            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12829                (kill_ring.text().to_string(), kill_ring.metadata_json())
12830            } else {
12831                return;
12832            }
12833        } else {
12834            return;
12835        };
12836        self.do_paste(&text, metadata, false, window, cx);
12837    }
12838
12839    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12840        self.do_copy(true, cx);
12841    }
12842
12843    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12844        self.do_copy(false, cx);
12845    }
12846
12847    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12848        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12849        let buffer = self.buffer.read(cx).read(cx);
12850        let mut text = String::new();
12851
12852        let mut clipboard_selections = Vec::with_capacity(selections.len());
12853        {
12854            let max_point = buffer.max_point();
12855            let mut is_first = true;
12856            let mut prev_selection_was_entire_line = false;
12857            for selection in &selections {
12858                let mut start = selection.start;
12859                let mut end = selection.end;
12860                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12861                let mut add_trailing_newline = false;
12862                if is_entire_line {
12863                    start = Point::new(start.row, 0);
12864                    let next_line_start = Point::new(end.row + 1, 0);
12865                    if next_line_start <= max_point {
12866                        end = next_line_start;
12867                    } else {
12868                        // We're on the last line without a trailing newline.
12869                        // Copy to the end of the line and add a newline afterwards.
12870                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12871                        add_trailing_newline = true;
12872                    }
12873                }
12874
12875                let mut trimmed_selections = Vec::new();
12876                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12877                    let row = MultiBufferRow(start.row);
12878                    let first_indent = buffer.indent_size_for_line(row);
12879                    if first_indent.len == 0 || start.column > first_indent.len {
12880                        trimmed_selections.push(start..end);
12881                    } else {
12882                        trimmed_selections.push(
12883                            Point::new(row.0, first_indent.len)
12884                                ..Point::new(row.0, buffer.line_len(row)),
12885                        );
12886                        for row in start.row + 1..=end.row {
12887                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12888                            if row == end.row {
12889                                line_len = end.column;
12890                            }
12891                            if line_len == 0 {
12892                                trimmed_selections
12893                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12894                                continue;
12895                            }
12896                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12897                            if row_indent_size.len >= first_indent.len {
12898                                trimmed_selections.push(
12899                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12900                                );
12901                            } else {
12902                                trimmed_selections.clear();
12903                                trimmed_selections.push(start..end);
12904                                break;
12905                            }
12906                        }
12907                    }
12908                } else {
12909                    trimmed_selections.push(start..end);
12910                }
12911
12912                for trimmed_range in trimmed_selections {
12913                    if is_first {
12914                        is_first = false;
12915                    } else if !prev_selection_was_entire_line {
12916                        text += "\n";
12917                    }
12918                    prev_selection_was_entire_line = is_entire_line;
12919                    let mut len = 0;
12920                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12921                        text.push_str(chunk);
12922                        len += chunk.len();
12923                    }
12924                    if add_trailing_newline {
12925                        text.push('\n');
12926                        len += 1;
12927                    }
12928                    clipboard_selections.push(ClipboardSelection {
12929                        len,
12930                        is_entire_line,
12931                        first_line_indent: buffer
12932                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12933                            .len,
12934                    });
12935                }
12936            }
12937        }
12938
12939        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12940            text,
12941            clipboard_selections,
12942        ));
12943    }
12944
12945    pub fn do_paste(
12946        &mut self,
12947        text: &String,
12948        clipboard_selections: Option<Vec<ClipboardSelection>>,
12949        handle_entire_lines: bool,
12950        window: &mut Window,
12951        cx: &mut Context<Self>,
12952    ) {
12953        if self.read_only(cx) {
12954            return;
12955        }
12956
12957        let clipboard_text = Cow::Borrowed(text.as_str());
12958
12959        self.transact(window, cx, |this, window, cx| {
12960            let had_active_edit_prediction = this.has_active_edit_prediction();
12961            let display_map = this.display_snapshot(cx);
12962            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
12963            let cursor_offset = this
12964                .selections
12965                .last::<MultiBufferOffset>(&display_map)
12966                .head();
12967
12968            if let Some(mut clipboard_selections) = clipboard_selections {
12969                let all_selections_were_entire_line =
12970                    clipboard_selections.iter().all(|s| s.is_entire_line);
12971                let first_selection_indent_column =
12972                    clipboard_selections.first().map(|s| s.first_line_indent);
12973                if clipboard_selections.len() != old_selections.len() {
12974                    clipboard_selections.drain(..);
12975                }
12976                let mut auto_indent_on_paste = true;
12977
12978                this.buffer.update(cx, |buffer, cx| {
12979                    let snapshot = buffer.read(cx);
12980                    auto_indent_on_paste = snapshot
12981                        .language_settings_at(cursor_offset, cx)
12982                        .auto_indent_on_paste;
12983
12984                    let mut start_offset = 0;
12985                    let mut edits = Vec::new();
12986                    let mut original_indent_columns = Vec::new();
12987                    for (ix, selection) in old_selections.iter().enumerate() {
12988                        let to_insert;
12989                        let entire_line;
12990                        let original_indent_column;
12991                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12992                            let end_offset = start_offset + clipboard_selection.len;
12993                            to_insert = &clipboard_text[start_offset..end_offset];
12994                            entire_line = clipboard_selection.is_entire_line;
12995                            start_offset = if entire_line {
12996                                end_offset
12997                            } else {
12998                                end_offset + 1
12999                            };
13000                            original_indent_column = Some(clipboard_selection.first_line_indent);
13001                        } else {
13002                            to_insert = &*clipboard_text;
13003                            entire_line = all_selections_were_entire_line;
13004                            original_indent_column = first_selection_indent_column
13005                        }
13006
13007                        let (range, to_insert) =
13008                            if selection.is_empty() && handle_entire_lines && entire_line {
13009                                // If the corresponding selection was empty when this slice of the
13010                                // clipboard text was written, then the entire line containing the
13011                                // selection was copied. If this selection is also currently empty,
13012                                // then paste the line before the current line of the buffer.
13013                                let column = selection.start.to_point(&snapshot).column as usize;
13014                                let line_start = selection.start - column;
13015                                (line_start..line_start, Cow::Borrowed(to_insert))
13016                            } else {
13017                                let language = snapshot.language_at(selection.head());
13018                                let range = selection.range();
13019                                if let Some(language) = language
13020                                    && language.name() == "Markdown".into()
13021                                {
13022                                    edit_for_markdown_paste(
13023                                        &snapshot,
13024                                        range,
13025                                        to_insert,
13026                                        url::Url::parse(to_insert).ok(),
13027                                    )
13028                                } else {
13029                                    (range, Cow::Borrowed(to_insert))
13030                                }
13031                            };
13032
13033                        edits.push((range, to_insert));
13034                        original_indent_columns.push(original_indent_column);
13035                    }
13036                    drop(snapshot);
13037
13038                    buffer.edit(
13039                        edits,
13040                        if auto_indent_on_paste {
13041                            Some(AutoindentMode::Block {
13042                                original_indent_columns,
13043                            })
13044                        } else {
13045                            None
13046                        },
13047                        cx,
13048                    );
13049                });
13050
13051                let selections = this
13052                    .selections
13053                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13054                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13055            } else {
13056                let url = url::Url::parse(&clipboard_text).ok();
13057
13058                let auto_indent_mode = if !clipboard_text.is_empty() {
13059                    Some(AutoindentMode::Block {
13060                        original_indent_columns: Vec::new(),
13061                    })
13062                } else {
13063                    None
13064                };
13065
13066                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13067                    let snapshot = buffer.snapshot(cx);
13068
13069                    let anchors = old_selections
13070                        .iter()
13071                        .map(|s| {
13072                            let anchor = snapshot.anchor_after(s.head());
13073                            s.map(|_| anchor)
13074                        })
13075                        .collect::<Vec<_>>();
13076
13077                    let mut edits = Vec::new();
13078
13079                    for selection in old_selections.iter() {
13080                        let language = snapshot.language_at(selection.head());
13081                        let range = selection.range();
13082
13083                        let (edit_range, edit_text) = if let Some(language) = language
13084                            && language.name() == "Markdown".into()
13085                        {
13086                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13087                        } else {
13088                            (range, clipboard_text.clone())
13089                        };
13090
13091                        edits.push((edit_range, edit_text));
13092                    }
13093
13094                    drop(snapshot);
13095                    buffer.edit(edits, auto_indent_mode, cx);
13096
13097                    anchors
13098                });
13099
13100                this.change_selections(Default::default(), window, cx, |s| {
13101                    s.select_anchors(selection_anchors);
13102                });
13103            }
13104
13105            //   🤔                 |    ..     | show_in_menu |
13106            // | ..                  |   true        true
13107            // | had_edit_prediction |   false       true
13108
13109            let trigger_in_words =
13110                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13111
13112            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13113        });
13114    }
13115
13116    pub fn diff_clipboard_with_selection(
13117        &mut self,
13118        _: &DiffClipboardWithSelection,
13119        window: &mut Window,
13120        cx: &mut Context<Self>,
13121    ) {
13122        let selections = self
13123            .selections
13124            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13125
13126        if selections.is_empty() {
13127            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13128            return;
13129        };
13130
13131        let clipboard_text = match cx.read_from_clipboard() {
13132            Some(item) => match item.entries().first() {
13133                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13134                _ => None,
13135            },
13136            None => None,
13137        };
13138
13139        let Some(clipboard_text) = clipboard_text else {
13140            log::warn!("Clipboard doesn't contain text.");
13141            return;
13142        };
13143
13144        window.dispatch_action(
13145            Box::new(DiffClipboardWithSelectionData {
13146                clipboard_text,
13147                editor: cx.entity(),
13148            }),
13149            cx,
13150        );
13151    }
13152
13153    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13154        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13155        if let Some(item) = cx.read_from_clipboard() {
13156            let entries = item.entries();
13157
13158            match entries.first() {
13159                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13160                // of all the pasted entries.
13161                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13162                    .do_paste(
13163                        clipboard_string.text(),
13164                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13165                        true,
13166                        window,
13167                        cx,
13168                    ),
13169                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13170            }
13171        }
13172    }
13173
13174    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13175        if self.read_only(cx) {
13176            return;
13177        }
13178
13179        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13180
13181        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13182            if let Some((selections, _)) =
13183                self.selection_history.transaction(transaction_id).cloned()
13184            {
13185                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13186                    s.select_anchors(selections.to_vec());
13187                });
13188            } else {
13189                log::error!(
13190                    "No entry in selection_history found for undo. \
13191                     This may correspond to a bug where undo does not update the selection. \
13192                     If this is occurring, please add details to \
13193                     https://github.com/zed-industries/zed/issues/22692"
13194                );
13195            }
13196            self.request_autoscroll(Autoscroll::fit(), cx);
13197            self.unmark_text(window, cx);
13198            self.refresh_edit_prediction(true, false, window, cx);
13199            cx.emit(EditorEvent::Edited { transaction_id });
13200            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13201        }
13202    }
13203
13204    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13205        if self.read_only(cx) {
13206            return;
13207        }
13208
13209        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13210
13211        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13212            if let Some((_, Some(selections))) =
13213                self.selection_history.transaction(transaction_id).cloned()
13214            {
13215                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13216                    s.select_anchors(selections.to_vec());
13217                });
13218            } else {
13219                log::error!(
13220                    "No entry in selection_history found for redo. \
13221                     This may correspond to a bug where undo does not update the selection. \
13222                     If this is occurring, please add details to \
13223                     https://github.com/zed-industries/zed/issues/22692"
13224                );
13225            }
13226            self.request_autoscroll(Autoscroll::fit(), cx);
13227            self.unmark_text(window, cx);
13228            self.refresh_edit_prediction(true, false, window, cx);
13229            cx.emit(EditorEvent::Edited { transaction_id });
13230        }
13231    }
13232
13233    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13234        self.buffer
13235            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13236    }
13237
13238    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13239        self.buffer
13240            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13241    }
13242
13243    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13244        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13245        self.change_selections(Default::default(), window, cx, |s| {
13246            s.move_with(|map, selection| {
13247                let cursor = if selection.is_empty() {
13248                    movement::left(map, selection.start)
13249                } else {
13250                    selection.start
13251                };
13252                selection.collapse_to(cursor, SelectionGoal::None);
13253            });
13254        })
13255    }
13256
13257    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13258        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13259        self.change_selections(Default::default(), window, cx, |s| {
13260            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13261        })
13262    }
13263
13264    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13265        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13266        self.change_selections(Default::default(), window, cx, |s| {
13267            s.move_with(|map, selection| {
13268                let cursor = if selection.is_empty() {
13269                    movement::right(map, selection.end)
13270                } else {
13271                    selection.end
13272                };
13273                selection.collapse_to(cursor, SelectionGoal::None)
13274            });
13275        })
13276    }
13277
13278    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13279        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13280        self.change_selections(Default::default(), window, cx, |s| {
13281            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13282        });
13283    }
13284
13285    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13286        if self.take_rename(true, window, cx).is_some() {
13287            return;
13288        }
13289
13290        if self.mode.is_single_line() {
13291            cx.propagate();
13292            return;
13293        }
13294
13295        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13296
13297        let text_layout_details = &self.text_layout_details(window);
13298        let selection_count = self.selections.count();
13299        let first_selection = self.selections.first_anchor();
13300
13301        self.change_selections(Default::default(), window, cx, |s| {
13302            s.move_with(|map, selection| {
13303                if !selection.is_empty() {
13304                    selection.goal = SelectionGoal::None;
13305                }
13306                let (cursor, goal) = movement::up(
13307                    map,
13308                    selection.start,
13309                    selection.goal,
13310                    false,
13311                    text_layout_details,
13312                );
13313                selection.collapse_to(cursor, goal);
13314            });
13315        });
13316
13317        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13318        {
13319            cx.propagate();
13320        }
13321    }
13322
13323    pub fn move_up_by_lines(
13324        &mut self,
13325        action: &MoveUpByLines,
13326        window: &mut Window,
13327        cx: &mut Context<Self>,
13328    ) {
13329        if self.take_rename(true, window, cx).is_some() {
13330            return;
13331        }
13332
13333        if self.mode.is_single_line() {
13334            cx.propagate();
13335            return;
13336        }
13337
13338        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13339
13340        let text_layout_details = &self.text_layout_details(window);
13341
13342        self.change_selections(Default::default(), window, cx, |s| {
13343            s.move_with(|map, selection| {
13344                if !selection.is_empty() {
13345                    selection.goal = SelectionGoal::None;
13346                }
13347                let (cursor, goal) = movement::up_by_rows(
13348                    map,
13349                    selection.start,
13350                    action.lines,
13351                    selection.goal,
13352                    false,
13353                    text_layout_details,
13354                );
13355                selection.collapse_to(cursor, goal);
13356            });
13357        })
13358    }
13359
13360    pub fn move_down_by_lines(
13361        &mut self,
13362        action: &MoveDownByLines,
13363        window: &mut Window,
13364        cx: &mut Context<Self>,
13365    ) {
13366        if self.take_rename(true, window, cx).is_some() {
13367            return;
13368        }
13369
13370        if self.mode.is_single_line() {
13371            cx.propagate();
13372            return;
13373        }
13374
13375        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13376
13377        let text_layout_details = &self.text_layout_details(window);
13378
13379        self.change_selections(Default::default(), window, cx, |s| {
13380            s.move_with(|map, selection| {
13381                if !selection.is_empty() {
13382                    selection.goal = SelectionGoal::None;
13383                }
13384                let (cursor, goal) = movement::down_by_rows(
13385                    map,
13386                    selection.start,
13387                    action.lines,
13388                    selection.goal,
13389                    false,
13390                    text_layout_details,
13391                );
13392                selection.collapse_to(cursor, goal);
13393            });
13394        })
13395    }
13396
13397    pub fn select_down_by_lines(
13398        &mut self,
13399        action: &SelectDownByLines,
13400        window: &mut Window,
13401        cx: &mut Context<Self>,
13402    ) {
13403        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13404        let text_layout_details = &self.text_layout_details(window);
13405        self.change_selections(Default::default(), window, cx, |s| {
13406            s.move_heads_with(|map, head, goal| {
13407                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13408            })
13409        })
13410    }
13411
13412    pub fn select_up_by_lines(
13413        &mut self,
13414        action: &SelectUpByLines,
13415        window: &mut Window,
13416        cx: &mut Context<Self>,
13417    ) {
13418        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13419        let text_layout_details = &self.text_layout_details(window);
13420        self.change_selections(Default::default(), window, cx, |s| {
13421            s.move_heads_with(|map, head, goal| {
13422                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13423            })
13424        })
13425    }
13426
13427    pub fn select_page_up(
13428        &mut self,
13429        _: &SelectPageUp,
13430        window: &mut Window,
13431        cx: &mut Context<Self>,
13432    ) {
13433        let Some(row_count) = self.visible_row_count() else {
13434            return;
13435        };
13436
13437        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13438
13439        let text_layout_details = &self.text_layout_details(window);
13440
13441        self.change_selections(Default::default(), window, cx, |s| {
13442            s.move_heads_with(|map, head, goal| {
13443                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13444            })
13445        })
13446    }
13447
13448    pub fn move_page_up(
13449        &mut self,
13450        action: &MovePageUp,
13451        window: &mut Window,
13452        cx: &mut Context<Self>,
13453    ) {
13454        if self.take_rename(true, window, cx).is_some() {
13455            return;
13456        }
13457
13458        if self
13459            .context_menu
13460            .borrow_mut()
13461            .as_mut()
13462            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13463            .unwrap_or(false)
13464        {
13465            return;
13466        }
13467
13468        if matches!(self.mode, EditorMode::SingleLine) {
13469            cx.propagate();
13470            return;
13471        }
13472
13473        let Some(row_count) = self.visible_row_count() else {
13474            return;
13475        };
13476
13477        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13478
13479        let effects = if action.center_cursor {
13480            SelectionEffects::scroll(Autoscroll::center())
13481        } else {
13482            SelectionEffects::default()
13483        };
13484
13485        let text_layout_details = &self.text_layout_details(window);
13486
13487        self.change_selections(effects, window, cx, |s| {
13488            s.move_with(|map, selection| {
13489                if !selection.is_empty() {
13490                    selection.goal = SelectionGoal::None;
13491                }
13492                let (cursor, goal) = movement::up_by_rows(
13493                    map,
13494                    selection.end,
13495                    row_count,
13496                    selection.goal,
13497                    false,
13498                    text_layout_details,
13499                );
13500                selection.collapse_to(cursor, goal);
13501            });
13502        });
13503    }
13504
13505    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13506        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13507        let text_layout_details = &self.text_layout_details(window);
13508        self.change_selections(Default::default(), window, cx, |s| {
13509            s.move_heads_with(|map, head, goal| {
13510                movement::up(map, head, goal, false, text_layout_details)
13511            })
13512        })
13513    }
13514
13515    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13516        self.take_rename(true, window, cx);
13517
13518        if self.mode.is_single_line() {
13519            cx.propagate();
13520            return;
13521        }
13522
13523        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13524
13525        let text_layout_details = &self.text_layout_details(window);
13526        let selection_count = self.selections.count();
13527        let first_selection = self.selections.first_anchor();
13528
13529        self.change_selections(Default::default(), window, cx, |s| {
13530            s.move_with(|map, selection| {
13531                if !selection.is_empty() {
13532                    selection.goal = SelectionGoal::None;
13533                }
13534                let (cursor, goal) = movement::down(
13535                    map,
13536                    selection.end,
13537                    selection.goal,
13538                    false,
13539                    text_layout_details,
13540                );
13541                selection.collapse_to(cursor, goal);
13542            });
13543        });
13544
13545        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13546        {
13547            cx.propagate();
13548        }
13549    }
13550
13551    pub fn select_page_down(
13552        &mut self,
13553        _: &SelectPageDown,
13554        window: &mut Window,
13555        cx: &mut Context<Self>,
13556    ) {
13557        let Some(row_count) = self.visible_row_count() else {
13558            return;
13559        };
13560
13561        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13562
13563        let text_layout_details = &self.text_layout_details(window);
13564
13565        self.change_selections(Default::default(), window, cx, |s| {
13566            s.move_heads_with(|map, head, goal| {
13567                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13568            })
13569        })
13570    }
13571
13572    pub fn move_page_down(
13573        &mut self,
13574        action: &MovePageDown,
13575        window: &mut Window,
13576        cx: &mut Context<Self>,
13577    ) {
13578        if self.take_rename(true, window, cx).is_some() {
13579            return;
13580        }
13581
13582        if self
13583            .context_menu
13584            .borrow_mut()
13585            .as_mut()
13586            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13587            .unwrap_or(false)
13588        {
13589            return;
13590        }
13591
13592        if matches!(self.mode, EditorMode::SingleLine) {
13593            cx.propagate();
13594            return;
13595        }
13596
13597        let Some(row_count) = self.visible_row_count() else {
13598            return;
13599        };
13600
13601        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13602
13603        let effects = if action.center_cursor {
13604            SelectionEffects::scroll(Autoscroll::center())
13605        } else {
13606            SelectionEffects::default()
13607        };
13608
13609        let text_layout_details = &self.text_layout_details(window);
13610        self.change_selections(effects, window, cx, |s| {
13611            s.move_with(|map, selection| {
13612                if !selection.is_empty() {
13613                    selection.goal = SelectionGoal::None;
13614                }
13615                let (cursor, goal) = movement::down_by_rows(
13616                    map,
13617                    selection.end,
13618                    row_count,
13619                    selection.goal,
13620                    false,
13621                    text_layout_details,
13622                );
13623                selection.collapse_to(cursor, goal);
13624            });
13625        });
13626    }
13627
13628    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13629        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13630        let text_layout_details = &self.text_layout_details(window);
13631        self.change_selections(Default::default(), window, cx, |s| {
13632            s.move_heads_with(|map, head, goal| {
13633                movement::down(map, head, goal, false, text_layout_details)
13634            })
13635        });
13636    }
13637
13638    pub fn context_menu_first(
13639        &mut self,
13640        _: &ContextMenuFirst,
13641        window: &mut Window,
13642        cx: &mut Context<Self>,
13643    ) {
13644        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13645            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13646        }
13647    }
13648
13649    pub fn context_menu_prev(
13650        &mut self,
13651        _: &ContextMenuPrevious,
13652        window: &mut Window,
13653        cx: &mut Context<Self>,
13654    ) {
13655        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13656            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13657        }
13658    }
13659
13660    pub fn context_menu_next(
13661        &mut self,
13662        _: &ContextMenuNext,
13663        window: &mut Window,
13664        cx: &mut Context<Self>,
13665    ) {
13666        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13667            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13668        }
13669    }
13670
13671    pub fn context_menu_last(
13672        &mut self,
13673        _: &ContextMenuLast,
13674        window: &mut Window,
13675        cx: &mut Context<Self>,
13676    ) {
13677        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13678            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13679        }
13680    }
13681
13682    pub fn signature_help_prev(
13683        &mut self,
13684        _: &SignatureHelpPrevious,
13685        _: &mut Window,
13686        cx: &mut Context<Self>,
13687    ) {
13688        if let Some(popover) = self.signature_help_state.popover_mut() {
13689            if popover.current_signature == 0 {
13690                popover.current_signature = popover.signatures.len() - 1;
13691            } else {
13692                popover.current_signature -= 1;
13693            }
13694            cx.notify();
13695        }
13696    }
13697
13698    pub fn signature_help_next(
13699        &mut self,
13700        _: &SignatureHelpNext,
13701        _: &mut Window,
13702        cx: &mut Context<Self>,
13703    ) {
13704        if let Some(popover) = self.signature_help_state.popover_mut() {
13705            if popover.current_signature + 1 == popover.signatures.len() {
13706                popover.current_signature = 0;
13707            } else {
13708                popover.current_signature += 1;
13709            }
13710            cx.notify();
13711        }
13712    }
13713
13714    pub fn move_to_previous_word_start(
13715        &mut self,
13716        _: &MoveToPreviousWordStart,
13717        window: &mut Window,
13718        cx: &mut Context<Self>,
13719    ) {
13720        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13721        self.change_selections(Default::default(), window, cx, |s| {
13722            s.move_cursors_with(|map, head, _| {
13723                (
13724                    movement::previous_word_start(map, head),
13725                    SelectionGoal::None,
13726                )
13727            });
13728        })
13729    }
13730
13731    pub fn move_to_previous_subword_start(
13732        &mut self,
13733        _: &MoveToPreviousSubwordStart,
13734        window: &mut Window,
13735        cx: &mut Context<Self>,
13736    ) {
13737        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13738        self.change_selections(Default::default(), window, cx, |s| {
13739            s.move_cursors_with(|map, head, _| {
13740                (
13741                    movement::previous_subword_start(map, head),
13742                    SelectionGoal::None,
13743                )
13744            });
13745        })
13746    }
13747
13748    pub fn select_to_previous_word_start(
13749        &mut self,
13750        _: &SelectToPreviousWordStart,
13751        window: &mut Window,
13752        cx: &mut Context<Self>,
13753    ) {
13754        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13755        self.change_selections(Default::default(), window, cx, |s| {
13756            s.move_heads_with(|map, head, _| {
13757                (
13758                    movement::previous_word_start(map, head),
13759                    SelectionGoal::None,
13760                )
13761            });
13762        })
13763    }
13764
13765    pub fn select_to_previous_subword_start(
13766        &mut self,
13767        _: &SelectToPreviousSubwordStart,
13768        window: &mut Window,
13769        cx: &mut Context<Self>,
13770    ) {
13771        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13772        self.change_selections(Default::default(), window, cx, |s| {
13773            s.move_heads_with(|map, head, _| {
13774                (
13775                    movement::previous_subword_start(map, head),
13776                    SelectionGoal::None,
13777                )
13778            });
13779        })
13780    }
13781
13782    pub fn delete_to_previous_word_start(
13783        &mut self,
13784        action: &DeleteToPreviousWordStart,
13785        window: &mut Window,
13786        cx: &mut Context<Self>,
13787    ) {
13788        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13789        self.transact(window, cx, |this, window, cx| {
13790            this.select_autoclose_pair(window, cx);
13791            this.change_selections(Default::default(), window, cx, |s| {
13792                s.move_with(|map, selection| {
13793                    if selection.is_empty() {
13794                        let mut cursor = if action.ignore_newlines {
13795                            movement::previous_word_start(map, selection.head())
13796                        } else {
13797                            movement::previous_word_start_or_newline(map, selection.head())
13798                        };
13799                        cursor = movement::adjust_greedy_deletion(
13800                            map,
13801                            selection.head(),
13802                            cursor,
13803                            action.ignore_brackets,
13804                        );
13805                        selection.set_head(cursor, SelectionGoal::None);
13806                    }
13807                });
13808            });
13809            this.insert("", window, cx);
13810        });
13811    }
13812
13813    pub fn delete_to_previous_subword_start(
13814        &mut self,
13815        _: &DeleteToPreviousSubwordStart,
13816        window: &mut Window,
13817        cx: &mut Context<Self>,
13818    ) {
13819        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13820        self.transact(window, cx, |this, window, cx| {
13821            this.select_autoclose_pair(window, cx);
13822            this.change_selections(Default::default(), window, cx, |s| {
13823                s.move_with(|map, selection| {
13824                    if selection.is_empty() {
13825                        let mut cursor = movement::previous_subword_start(map, selection.head());
13826                        cursor =
13827                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13828                        selection.set_head(cursor, SelectionGoal::None);
13829                    }
13830                });
13831            });
13832            this.insert("", window, cx);
13833        });
13834    }
13835
13836    pub fn move_to_next_word_end(
13837        &mut self,
13838        _: &MoveToNextWordEnd,
13839        window: &mut Window,
13840        cx: &mut Context<Self>,
13841    ) {
13842        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13843        self.change_selections(Default::default(), window, cx, |s| {
13844            s.move_cursors_with(|map, head, _| {
13845                (movement::next_word_end(map, head), SelectionGoal::None)
13846            });
13847        })
13848    }
13849
13850    pub fn move_to_next_subword_end(
13851        &mut self,
13852        _: &MoveToNextSubwordEnd,
13853        window: &mut Window,
13854        cx: &mut Context<Self>,
13855    ) {
13856        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13857        self.change_selections(Default::default(), window, cx, |s| {
13858            s.move_cursors_with(|map, head, _| {
13859                (movement::next_subword_end(map, head), SelectionGoal::None)
13860            });
13861        })
13862    }
13863
13864    pub fn select_to_next_word_end(
13865        &mut self,
13866        _: &SelectToNextWordEnd,
13867        window: &mut Window,
13868        cx: &mut Context<Self>,
13869    ) {
13870        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13871        self.change_selections(Default::default(), window, cx, |s| {
13872            s.move_heads_with(|map, head, _| {
13873                (movement::next_word_end(map, head), SelectionGoal::None)
13874            });
13875        })
13876    }
13877
13878    pub fn select_to_next_subword_end(
13879        &mut self,
13880        _: &SelectToNextSubwordEnd,
13881        window: &mut Window,
13882        cx: &mut Context<Self>,
13883    ) {
13884        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13885        self.change_selections(Default::default(), window, cx, |s| {
13886            s.move_heads_with(|map, head, _| {
13887                (movement::next_subword_end(map, head), SelectionGoal::None)
13888            });
13889        })
13890    }
13891
13892    pub fn delete_to_next_word_end(
13893        &mut self,
13894        action: &DeleteToNextWordEnd,
13895        window: &mut Window,
13896        cx: &mut Context<Self>,
13897    ) {
13898        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13899        self.transact(window, cx, |this, window, cx| {
13900            this.change_selections(Default::default(), window, cx, |s| {
13901                s.move_with(|map, selection| {
13902                    if selection.is_empty() {
13903                        let mut cursor = if action.ignore_newlines {
13904                            movement::next_word_end(map, selection.head())
13905                        } else {
13906                            movement::next_word_end_or_newline(map, selection.head())
13907                        };
13908                        cursor = movement::adjust_greedy_deletion(
13909                            map,
13910                            selection.head(),
13911                            cursor,
13912                            action.ignore_brackets,
13913                        );
13914                        selection.set_head(cursor, SelectionGoal::None);
13915                    }
13916                });
13917            });
13918            this.insert("", window, cx);
13919        });
13920    }
13921
13922    pub fn delete_to_next_subword_end(
13923        &mut self,
13924        _: &DeleteToNextSubwordEnd,
13925        window: &mut Window,
13926        cx: &mut Context<Self>,
13927    ) {
13928        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13929        self.transact(window, cx, |this, window, cx| {
13930            this.change_selections(Default::default(), window, cx, |s| {
13931                s.move_with(|map, selection| {
13932                    if selection.is_empty() {
13933                        let mut cursor = movement::next_subword_end(map, selection.head());
13934                        cursor =
13935                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13936                        selection.set_head(cursor, SelectionGoal::None);
13937                    }
13938                });
13939            });
13940            this.insert("", window, cx);
13941        });
13942    }
13943
13944    pub fn move_to_beginning_of_line(
13945        &mut self,
13946        action: &MoveToBeginningOfLine,
13947        window: &mut Window,
13948        cx: &mut Context<Self>,
13949    ) {
13950        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13951        self.change_selections(Default::default(), window, cx, |s| {
13952            s.move_cursors_with(|map, head, _| {
13953                (
13954                    movement::indented_line_beginning(
13955                        map,
13956                        head,
13957                        action.stop_at_soft_wraps,
13958                        action.stop_at_indent,
13959                    ),
13960                    SelectionGoal::None,
13961                )
13962            });
13963        })
13964    }
13965
13966    pub fn select_to_beginning_of_line(
13967        &mut self,
13968        action: &SelectToBeginningOfLine,
13969        window: &mut Window,
13970        cx: &mut Context<Self>,
13971    ) {
13972        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13973        self.change_selections(Default::default(), window, cx, |s| {
13974            s.move_heads_with(|map, head, _| {
13975                (
13976                    movement::indented_line_beginning(
13977                        map,
13978                        head,
13979                        action.stop_at_soft_wraps,
13980                        action.stop_at_indent,
13981                    ),
13982                    SelectionGoal::None,
13983                )
13984            });
13985        });
13986    }
13987
13988    pub fn delete_to_beginning_of_line(
13989        &mut self,
13990        action: &DeleteToBeginningOfLine,
13991        window: &mut Window,
13992        cx: &mut Context<Self>,
13993    ) {
13994        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13995        self.transact(window, cx, |this, window, cx| {
13996            this.change_selections(Default::default(), window, cx, |s| {
13997                s.move_with(|_, selection| {
13998                    selection.reversed = true;
13999                });
14000            });
14001
14002            this.select_to_beginning_of_line(
14003                &SelectToBeginningOfLine {
14004                    stop_at_soft_wraps: false,
14005                    stop_at_indent: action.stop_at_indent,
14006                },
14007                window,
14008                cx,
14009            );
14010            this.backspace(&Backspace, window, cx);
14011        });
14012    }
14013
14014    pub fn move_to_end_of_line(
14015        &mut self,
14016        action: &MoveToEndOfLine,
14017        window: &mut Window,
14018        cx: &mut Context<Self>,
14019    ) {
14020        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14021        self.change_selections(Default::default(), window, cx, |s| {
14022            s.move_cursors_with(|map, head, _| {
14023                (
14024                    movement::line_end(map, head, action.stop_at_soft_wraps),
14025                    SelectionGoal::None,
14026                )
14027            });
14028        })
14029    }
14030
14031    pub fn select_to_end_of_line(
14032        &mut self,
14033        action: &SelectToEndOfLine,
14034        window: &mut Window,
14035        cx: &mut Context<Self>,
14036    ) {
14037        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14038        self.change_selections(Default::default(), window, cx, |s| {
14039            s.move_heads_with(|map, head, _| {
14040                (
14041                    movement::line_end(map, head, action.stop_at_soft_wraps),
14042                    SelectionGoal::None,
14043                )
14044            });
14045        })
14046    }
14047
14048    pub fn delete_to_end_of_line(
14049        &mut self,
14050        _: &DeleteToEndOfLine,
14051        window: &mut Window,
14052        cx: &mut Context<Self>,
14053    ) {
14054        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14055        self.transact(window, cx, |this, window, cx| {
14056            this.select_to_end_of_line(
14057                &SelectToEndOfLine {
14058                    stop_at_soft_wraps: false,
14059                },
14060                window,
14061                cx,
14062            );
14063            this.delete(&Delete, window, cx);
14064        });
14065    }
14066
14067    pub fn cut_to_end_of_line(
14068        &mut self,
14069        action: &CutToEndOfLine,
14070        window: &mut Window,
14071        cx: &mut Context<Self>,
14072    ) {
14073        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14074        self.transact(window, cx, |this, window, cx| {
14075            this.select_to_end_of_line(
14076                &SelectToEndOfLine {
14077                    stop_at_soft_wraps: false,
14078                },
14079                window,
14080                cx,
14081            );
14082            if !action.stop_at_newlines {
14083                this.change_selections(Default::default(), window, cx, |s| {
14084                    s.move_with(|_, sel| {
14085                        if sel.is_empty() {
14086                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14087                        }
14088                    });
14089                });
14090            }
14091            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14092            let item = this.cut_common(false, window, cx);
14093            cx.write_to_clipboard(item);
14094        });
14095    }
14096
14097    pub fn move_to_start_of_paragraph(
14098        &mut self,
14099        _: &MoveToStartOfParagraph,
14100        window: &mut Window,
14101        cx: &mut Context<Self>,
14102    ) {
14103        if matches!(self.mode, EditorMode::SingleLine) {
14104            cx.propagate();
14105            return;
14106        }
14107        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14108        self.change_selections(Default::default(), window, cx, |s| {
14109            s.move_with(|map, selection| {
14110                selection.collapse_to(
14111                    movement::start_of_paragraph(map, selection.head(), 1),
14112                    SelectionGoal::None,
14113                )
14114            });
14115        })
14116    }
14117
14118    pub fn move_to_end_of_paragraph(
14119        &mut self,
14120        _: &MoveToEndOfParagraph,
14121        window: &mut Window,
14122        cx: &mut Context<Self>,
14123    ) {
14124        if matches!(self.mode, EditorMode::SingleLine) {
14125            cx.propagate();
14126            return;
14127        }
14128        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14129        self.change_selections(Default::default(), window, cx, |s| {
14130            s.move_with(|map, selection| {
14131                selection.collapse_to(
14132                    movement::end_of_paragraph(map, selection.head(), 1),
14133                    SelectionGoal::None,
14134                )
14135            });
14136        })
14137    }
14138
14139    pub fn select_to_start_of_paragraph(
14140        &mut self,
14141        _: &SelectToStartOfParagraph,
14142        window: &mut Window,
14143        cx: &mut Context<Self>,
14144    ) {
14145        if matches!(self.mode, EditorMode::SingleLine) {
14146            cx.propagate();
14147            return;
14148        }
14149        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14150        self.change_selections(Default::default(), window, cx, |s| {
14151            s.move_heads_with(|map, head, _| {
14152                (
14153                    movement::start_of_paragraph(map, head, 1),
14154                    SelectionGoal::None,
14155                )
14156            });
14157        })
14158    }
14159
14160    pub fn select_to_end_of_paragraph(
14161        &mut self,
14162        _: &SelectToEndOfParagraph,
14163        window: &mut Window,
14164        cx: &mut Context<Self>,
14165    ) {
14166        if matches!(self.mode, EditorMode::SingleLine) {
14167            cx.propagate();
14168            return;
14169        }
14170        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14171        self.change_selections(Default::default(), window, cx, |s| {
14172            s.move_heads_with(|map, head, _| {
14173                (
14174                    movement::end_of_paragraph(map, head, 1),
14175                    SelectionGoal::None,
14176                )
14177            });
14178        })
14179    }
14180
14181    pub fn move_to_start_of_excerpt(
14182        &mut self,
14183        _: &MoveToStartOfExcerpt,
14184        window: &mut Window,
14185        cx: &mut Context<Self>,
14186    ) {
14187        if matches!(self.mode, EditorMode::SingleLine) {
14188            cx.propagate();
14189            return;
14190        }
14191        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14192        self.change_selections(Default::default(), window, cx, |s| {
14193            s.move_with(|map, selection| {
14194                selection.collapse_to(
14195                    movement::start_of_excerpt(
14196                        map,
14197                        selection.head(),
14198                        workspace::searchable::Direction::Prev,
14199                    ),
14200                    SelectionGoal::None,
14201                )
14202            });
14203        })
14204    }
14205
14206    pub fn move_to_start_of_next_excerpt(
14207        &mut self,
14208        _: &MoveToStartOfNextExcerpt,
14209        window: &mut Window,
14210        cx: &mut Context<Self>,
14211    ) {
14212        if matches!(self.mode, EditorMode::SingleLine) {
14213            cx.propagate();
14214            return;
14215        }
14216
14217        self.change_selections(Default::default(), window, cx, |s| {
14218            s.move_with(|map, selection| {
14219                selection.collapse_to(
14220                    movement::start_of_excerpt(
14221                        map,
14222                        selection.head(),
14223                        workspace::searchable::Direction::Next,
14224                    ),
14225                    SelectionGoal::None,
14226                )
14227            });
14228        })
14229    }
14230
14231    pub fn move_to_end_of_excerpt(
14232        &mut self,
14233        _: &MoveToEndOfExcerpt,
14234        window: &mut Window,
14235        cx: &mut Context<Self>,
14236    ) {
14237        if matches!(self.mode, EditorMode::SingleLine) {
14238            cx.propagate();
14239            return;
14240        }
14241        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14242        self.change_selections(Default::default(), window, cx, |s| {
14243            s.move_with(|map, selection| {
14244                selection.collapse_to(
14245                    movement::end_of_excerpt(
14246                        map,
14247                        selection.head(),
14248                        workspace::searchable::Direction::Next,
14249                    ),
14250                    SelectionGoal::None,
14251                )
14252            });
14253        })
14254    }
14255
14256    pub fn move_to_end_of_previous_excerpt(
14257        &mut self,
14258        _: &MoveToEndOfPreviousExcerpt,
14259        window: &mut Window,
14260        cx: &mut Context<Self>,
14261    ) {
14262        if matches!(self.mode, EditorMode::SingleLine) {
14263            cx.propagate();
14264            return;
14265        }
14266        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14267        self.change_selections(Default::default(), window, cx, |s| {
14268            s.move_with(|map, selection| {
14269                selection.collapse_to(
14270                    movement::end_of_excerpt(
14271                        map,
14272                        selection.head(),
14273                        workspace::searchable::Direction::Prev,
14274                    ),
14275                    SelectionGoal::None,
14276                )
14277            });
14278        })
14279    }
14280
14281    pub fn select_to_start_of_excerpt(
14282        &mut self,
14283        _: &SelectToStartOfExcerpt,
14284        window: &mut Window,
14285        cx: &mut Context<Self>,
14286    ) {
14287        if matches!(self.mode, EditorMode::SingleLine) {
14288            cx.propagate();
14289            return;
14290        }
14291        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14292        self.change_selections(Default::default(), window, cx, |s| {
14293            s.move_heads_with(|map, head, _| {
14294                (
14295                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14296                    SelectionGoal::None,
14297                )
14298            });
14299        })
14300    }
14301
14302    pub fn select_to_start_of_next_excerpt(
14303        &mut self,
14304        _: &SelectToStartOfNextExcerpt,
14305        window: &mut Window,
14306        cx: &mut Context<Self>,
14307    ) {
14308        if matches!(self.mode, EditorMode::SingleLine) {
14309            cx.propagate();
14310            return;
14311        }
14312        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14313        self.change_selections(Default::default(), window, cx, |s| {
14314            s.move_heads_with(|map, head, _| {
14315                (
14316                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14317                    SelectionGoal::None,
14318                )
14319            });
14320        })
14321    }
14322
14323    pub fn select_to_end_of_excerpt(
14324        &mut self,
14325        _: &SelectToEndOfExcerpt,
14326        window: &mut Window,
14327        cx: &mut Context<Self>,
14328    ) {
14329        if matches!(self.mode, EditorMode::SingleLine) {
14330            cx.propagate();
14331            return;
14332        }
14333        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14334        self.change_selections(Default::default(), window, cx, |s| {
14335            s.move_heads_with(|map, head, _| {
14336                (
14337                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14338                    SelectionGoal::None,
14339                )
14340            });
14341        })
14342    }
14343
14344    pub fn select_to_end_of_previous_excerpt(
14345        &mut self,
14346        _: &SelectToEndOfPreviousExcerpt,
14347        window: &mut Window,
14348        cx: &mut Context<Self>,
14349    ) {
14350        if matches!(self.mode, EditorMode::SingleLine) {
14351            cx.propagate();
14352            return;
14353        }
14354        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14355        self.change_selections(Default::default(), window, cx, |s| {
14356            s.move_heads_with(|map, head, _| {
14357                (
14358                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14359                    SelectionGoal::None,
14360                )
14361            });
14362        })
14363    }
14364
14365    pub fn move_to_beginning(
14366        &mut self,
14367        _: &MoveToBeginning,
14368        window: &mut Window,
14369        cx: &mut Context<Self>,
14370    ) {
14371        if matches!(self.mode, EditorMode::SingleLine) {
14372            cx.propagate();
14373            return;
14374        }
14375        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14376        self.change_selections(Default::default(), window, cx, |s| {
14377            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14378        });
14379    }
14380
14381    pub fn select_to_beginning(
14382        &mut self,
14383        _: &SelectToBeginning,
14384        window: &mut Window,
14385        cx: &mut Context<Self>,
14386    ) {
14387        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14388        selection.set_head(Point::zero(), SelectionGoal::None);
14389        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14390        self.change_selections(Default::default(), window, cx, |s| {
14391            s.select(vec![selection]);
14392        });
14393    }
14394
14395    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14396        if matches!(self.mode, EditorMode::SingleLine) {
14397            cx.propagate();
14398            return;
14399        }
14400        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14401        let cursor = self.buffer.read(cx).read(cx).len();
14402        self.change_selections(Default::default(), window, cx, |s| {
14403            s.select_ranges(vec![cursor..cursor])
14404        });
14405    }
14406
14407    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14408        self.nav_history = nav_history;
14409    }
14410
14411    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14412        self.nav_history.as_ref()
14413    }
14414
14415    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14416        self.push_to_nav_history(
14417            self.selections.newest_anchor().head(),
14418            None,
14419            false,
14420            true,
14421            cx,
14422        );
14423    }
14424
14425    fn push_to_nav_history(
14426        &mut self,
14427        cursor_anchor: Anchor,
14428        new_position: Option<Point>,
14429        is_deactivate: bool,
14430        always: bool,
14431        cx: &mut Context<Self>,
14432    ) {
14433        if let Some(nav_history) = self.nav_history.as_mut() {
14434            let buffer = self.buffer.read(cx).read(cx);
14435            let cursor_position = cursor_anchor.to_point(&buffer);
14436            let scroll_state = self.scroll_manager.anchor();
14437            let scroll_top_row = scroll_state.top_row(&buffer);
14438            drop(buffer);
14439
14440            if let Some(new_position) = new_position {
14441                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14442                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14443                    return;
14444                }
14445            }
14446
14447            nav_history.push(
14448                Some(NavigationData {
14449                    cursor_anchor,
14450                    cursor_position,
14451                    scroll_anchor: scroll_state,
14452                    scroll_top_row,
14453                }),
14454                cx,
14455            );
14456            cx.emit(EditorEvent::PushedToNavHistory {
14457                anchor: cursor_anchor,
14458                is_deactivate,
14459            })
14460        }
14461    }
14462
14463    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14464        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14465        let buffer = self.buffer.read(cx).snapshot(cx);
14466        let mut selection = self
14467            .selections
14468            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14469        selection.set_head(buffer.len(), SelectionGoal::None);
14470        self.change_selections(Default::default(), window, cx, |s| {
14471            s.select(vec![selection]);
14472        });
14473    }
14474
14475    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14476        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14477        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14478            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14479        });
14480    }
14481
14482    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14483        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14484        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14485        let mut selections = self.selections.all::<Point>(&display_map);
14486        let max_point = display_map.buffer_snapshot().max_point();
14487        for selection in &mut selections {
14488            let rows = selection.spanned_rows(true, &display_map);
14489            selection.start = Point::new(rows.start.0, 0);
14490            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14491            selection.reversed = false;
14492        }
14493        self.change_selections(Default::default(), window, cx, |s| {
14494            s.select(selections);
14495        });
14496    }
14497
14498    pub fn split_selection_into_lines(
14499        &mut self,
14500        action: &SplitSelectionIntoLines,
14501        window: &mut Window,
14502        cx: &mut Context<Self>,
14503    ) {
14504        let selections = self
14505            .selections
14506            .all::<Point>(&self.display_snapshot(cx))
14507            .into_iter()
14508            .map(|selection| selection.start..selection.end)
14509            .collect::<Vec<_>>();
14510        self.unfold_ranges(&selections, true, true, cx);
14511
14512        let mut new_selection_ranges = Vec::new();
14513        {
14514            let buffer = self.buffer.read(cx).read(cx);
14515            for selection in selections {
14516                for row in selection.start.row..selection.end.row {
14517                    let line_start = Point::new(row, 0);
14518                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14519
14520                    if action.keep_selections {
14521                        // Keep the selection range for each line
14522                        let selection_start = if row == selection.start.row {
14523                            selection.start
14524                        } else {
14525                            line_start
14526                        };
14527                        new_selection_ranges.push(selection_start..line_end);
14528                    } else {
14529                        // Collapse to cursor at end of line
14530                        new_selection_ranges.push(line_end..line_end);
14531                    }
14532                }
14533
14534                let is_multiline_selection = selection.start.row != selection.end.row;
14535                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14536                // so this action feels more ergonomic when paired with other selection operations
14537                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14538                if !should_skip_last {
14539                    if action.keep_selections {
14540                        if is_multiline_selection {
14541                            let line_start = Point::new(selection.end.row, 0);
14542                            new_selection_ranges.push(line_start..selection.end);
14543                        } else {
14544                            new_selection_ranges.push(selection.start..selection.end);
14545                        }
14546                    } else {
14547                        new_selection_ranges.push(selection.end..selection.end);
14548                    }
14549                }
14550            }
14551        }
14552        self.change_selections(Default::default(), window, cx, |s| {
14553            s.select_ranges(new_selection_ranges);
14554        });
14555    }
14556
14557    pub fn add_selection_above(
14558        &mut self,
14559        action: &AddSelectionAbove,
14560        window: &mut Window,
14561        cx: &mut Context<Self>,
14562    ) {
14563        self.add_selection(true, action.skip_soft_wrap, window, cx);
14564    }
14565
14566    pub fn add_selection_below(
14567        &mut self,
14568        action: &AddSelectionBelow,
14569        window: &mut Window,
14570        cx: &mut Context<Self>,
14571    ) {
14572        self.add_selection(false, action.skip_soft_wrap, window, cx);
14573    }
14574
14575    fn add_selection(
14576        &mut self,
14577        above: bool,
14578        skip_soft_wrap: bool,
14579        window: &mut Window,
14580        cx: &mut Context<Self>,
14581    ) {
14582        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14583
14584        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14585        let all_selections = self.selections.all::<Point>(&display_map);
14586        let text_layout_details = self.text_layout_details(window);
14587
14588        let (mut columnar_selections, new_selections_to_columnarize) = {
14589            if let Some(state) = self.add_selections_state.as_ref() {
14590                let columnar_selection_ids: HashSet<_> = state
14591                    .groups
14592                    .iter()
14593                    .flat_map(|group| group.stack.iter())
14594                    .copied()
14595                    .collect();
14596
14597                all_selections
14598                    .into_iter()
14599                    .partition(|s| columnar_selection_ids.contains(&s.id))
14600            } else {
14601                (Vec::new(), all_selections)
14602            }
14603        };
14604
14605        let mut state = self
14606            .add_selections_state
14607            .take()
14608            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14609
14610        for selection in new_selections_to_columnarize {
14611            let range = selection.display_range(&display_map).sorted();
14612            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14613            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14614            let positions = start_x.min(end_x)..start_x.max(end_x);
14615            let mut stack = Vec::new();
14616            for row in range.start.row().0..=range.end.row().0 {
14617                if let Some(selection) = self.selections.build_columnar_selection(
14618                    &display_map,
14619                    DisplayRow(row),
14620                    &positions,
14621                    selection.reversed,
14622                    &text_layout_details,
14623                ) {
14624                    stack.push(selection.id);
14625                    columnar_selections.push(selection);
14626                }
14627            }
14628            if !stack.is_empty() {
14629                if above {
14630                    stack.reverse();
14631                }
14632                state.groups.push(AddSelectionsGroup { above, stack });
14633            }
14634        }
14635
14636        let mut final_selections = Vec::new();
14637        let end_row = if above {
14638            DisplayRow(0)
14639        } else {
14640            display_map.max_point().row()
14641        };
14642
14643        let mut last_added_item_per_group = HashMap::default();
14644        for group in state.groups.iter_mut() {
14645            if let Some(last_id) = group.stack.last() {
14646                last_added_item_per_group.insert(*last_id, group);
14647            }
14648        }
14649
14650        for selection in columnar_selections {
14651            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14652                if above == group.above {
14653                    let range = selection.display_range(&display_map).sorted();
14654                    debug_assert_eq!(range.start.row(), range.end.row());
14655                    let mut row = range.start.row();
14656                    let positions =
14657                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14658                            Pixels::from(start)..Pixels::from(end)
14659                        } else {
14660                            let start_x =
14661                                display_map.x_for_display_point(range.start, &text_layout_details);
14662                            let end_x =
14663                                display_map.x_for_display_point(range.end, &text_layout_details);
14664                            start_x.min(end_x)..start_x.max(end_x)
14665                        };
14666
14667                    let mut maybe_new_selection = None;
14668                    let direction = if above { -1 } else { 1 };
14669
14670                    while row != end_row {
14671                        if skip_soft_wrap {
14672                            row = display_map
14673                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14674                                .row();
14675                        } else if above {
14676                            row.0 -= 1;
14677                        } else {
14678                            row.0 += 1;
14679                        }
14680
14681                        if let Some(new_selection) = self.selections.build_columnar_selection(
14682                            &display_map,
14683                            row,
14684                            &positions,
14685                            selection.reversed,
14686                            &text_layout_details,
14687                        ) {
14688                            maybe_new_selection = Some(new_selection);
14689                            break;
14690                        }
14691                    }
14692
14693                    if let Some(new_selection) = maybe_new_selection {
14694                        group.stack.push(new_selection.id);
14695                        if above {
14696                            final_selections.push(new_selection);
14697                            final_selections.push(selection);
14698                        } else {
14699                            final_selections.push(selection);
14700                            final_selections.push(new_selection);
14701                        }
14702                    } else {
14703                        final_selections.push(selection);
14704                    }
14705                } else {
14706                    group.stack.pop();
14707                }
14708            } else {
14709                final_selections.push(selection);
14710            }
14711        }
14712
14713        self.change_selections(Default::default(), window, cx, |s| {
14714            s.select(final_selections);
14715        });
14716
14717        let final_selection_ids: HashSet<_> = self
14718            .selections
14719            .all::<Point>(&display_map)
14720            .iter()
14721            .map(|s| s.id)
14722            .collect();
14723        state.groups.retain_mut(|group| {
14724            // selections might get merged above so we remove invalid items from stacks
14725            group.stack.retain(|id| final_selection_ids.contains(id));
14726
14727            // single selection in stack can be treated as initial state
14728            group.stack.len() > 1
14729        });
14730
14731        if !state.groups.is_empty() {
14732            self.add_selections_state = Some(state);
14733        }
14734    }
14735
14736    fn select_match_ranges(
14737        &mut self,
14738        range: Range<MultiBufferOffset>,
14739        reversed: bool,
14740        replace_newest: bool,
14741        auto_scroll: Option<Autoscroll>,
14742        window: &mut Window,
14743        cx: &mut Context<Editor>,
14744    ) {
14745        self.unfold_ranges(
14746            std::slice::from_ref(&range),
14747            false,
14748            auto_scroll.is_some(),
14749            cx,
14750        );
14751        let effects = if let Some(scroll) = auto_scroll {
14752            SelectionEffects::scroll(scroll)
14753        } else {
14754            SelectionEffects::no_scroll()
14755        };
14756        self.change_selections(effects, window, cx, |s| {
14757            if replace_newest {
14758                s.delete(s.newest_anchor().id);
14759            }
14760            if reversed {
14761                s.insert_range(range.end..range.start);
14762            } else {
14763                s.insert_range(range);
14764            }
14765        });
14766    }
14767
14768    pub fn select_next_match_internal(
14769        &mut self,
14770        display_map: &DisplaySnapshot,
14771        replace_newest: bool,
14772        autoscroll: Option<Autoscroll>,
14773        window: &mut Window,
14774        cx: &mut Context<Self>,
14775    ) -> Result<()> {
14776        let buffer = display_map.buffer_snapshot();
14777        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14778        if let Some(mut select_next_state) = self.select_next_state.take() {
14779            let query = &select_next_state.query;
14780            if !select_next_state.done {
14781                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14782                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14783                let mut next_selected_range = None;
14784
14785                let bytes_after_last_selection =
14786                    buffer.bytes_in_range(last_selection.end..buffer.len());
14787                let bytes_before_first_selection =
14788                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
14789                let query_matches = query
14790                    .stream_find_iter(bytes_after_last_selection)
14791                    .map(|result| (last_selection.end, result))
14792                    .chain(
14793                        query
14794                            .stream_find_iter(bytes_before_first_selection)
14795                            .map(|result| (MultiBufferOffset(0), result)),
14796                    );
14797
14798                for (start_offset, query_match) in query_matches {
14799                    let query_match = query_match.unwrap(); // can only fail due to I/O
14800                    let offset_range =
14801                        start_offset + query_match.start()..start_offset + query_match.end();
14802
14803                    if !select_next_state.wordwise
14804                        || (!buffer.is_inside_word(offset_range.start, None)
14805                            && !buffer.is_inside_word(offset_range.end, None))
14806                    {
14807                        let idx = selections
14808                            .partition_point(|selection| selection.end <= offset_range.start);
14809                        let overlaps = selections
14810                            .get(idx)
14811                            .map_or(false, |selection| selection.start < offset_range.end);
14812
14813                        if !overlaps {
14814                            next_selected_range = Some(offset_range);
14815                            break;
14816                        }
14817                    }
14818                }
14819
14820                if let Some(next_selected_range) = next_selected_range {
14821                    self.select_match_ranges(
14822                        next_selected_range,
14823                        last_selection.reversed,
14824                        replace_newest,
14825                        autoscroll,
14826                        window,
14827                        cx,
14828                    );
14829                } else {
14830                    select_next_state.done = true;
14831                }
14832            }
14833
14834            self.select_next_state = Some(select_next_state);
14835        } else {
14836            let mut only_carets = true;
14837            let mut same_text_selected = true;
14838            let mut selected_text = None;
14839
14840            let mut selections_iter = selections.iter().peekable();
14841            while let Some(selection) = selections_iter.next() {
14842                if selection.start != selection.end {
14843                    only_carets = false;
14844                }
14845
14846                if same_text_selected {
14847                    if selected_text.is_none() {
14848                        selected_text =
14849                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14850                    }
14851
14852                    if let Some(next_selection) = selections_iter.peek() {
14853                        if next_selection.len() == selection.len() {
14854                            let next_selected_text = buffer
14855                                .text_for_range(next_selection.range())
14856                                .collect::<String>();
14857                            if Some(next_selected_text) != selected_text {
14858                                same_text_selected = false;
14859                                selected_text = None;
14860                            }
14861                        } else {
14862                            same_text_selected = false;
14863                            selected_text = None;
14864                        }
14865                    }
14866                }
14867            }
14868
14869            if only_carets {
14870                for selection in &mut selections {
14871                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14872                    selection.start = word_range.start;
14873                    selection.end = word_range.end;
14874                    selection.goal = SelectionGoal::None;
14875                    selection.reversed = false;
14876                    self.select_match_ranges(
14877                        selection.start..selection.end,
14878                        selection.reversed,
14879                        replace_newest,
14880                        autoscroll,
14881                        window,
14882                        cx,
14883                    );
14884                }
14885
14886                if selections.len() == 1 {
14887                    let selection = selections
14888                        .last()
14889                        .expect("ensured that there's only one selection");
14890                    let query = buffer
14891                        .text_for_range(selection.start..selection.end)
14892                        .collect::<String>();
14893                    let is_empty = query.is_empty();
14894                    let select_state = SelectNextState {
14895                        query: self.build_query(&[query], cx)?,
14896                        wordwise: true,
14897                        done: is_empty,
14898                    };
14899                    self.select_next_state = Some(select_state);
14900                } else {
14901                    self.select_next_state = None;
14902                }
14903            } else if let Some(selected_text) = selected_text {
14904                self.select_next_state = Some(SelectNextState {
14905                    query: self.build_query(&[selected_text], cx)?,
14906                    wordwise: false,
14907                    done: false,
14908                });
14909                self.select_next_match_internal(
14910                    display_map,
14911                    replace_newest,
14912                    autoscroll,
14913                    window,
14914                    cx,
14915                )?;
14916            }
14917        }
14918        Ok(())
14919    }
14920
14921    pub fn select_all_matches(
14922        &mut self,
14923        _action: &SelectAllMatches,
14924        window: &mut Window,
14925        cx: &mut Context<Self>,
14926    ) -> Result<()> {
14927        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14928
14929        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14930
14931        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14932        let Some(select_next_state) = self.select_next_state.as_mut() else {
14933            return Ok(());
14934        };
14935        if select_next_state.done {
14936            return Ok(());
14937        }
14938
14939        let mut new_selections = Vec::new();
14940
14941        let reversed = self
14942            .selections
14943            .oldest::<MultiBufferOffset>(&display_map)
14944            .reversed;
14945        let buffer = display_map.buffer_snapshot();
14946        let query_matches = select_next_state
14947            .query
14948            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
14949
14950        for query_match in query_matches.into_iter() {
14951            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14952            let offset_range = if reversed {
14953                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
14954            } else {
14955                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
14956            };
14957
14958            if !select_next_state.wordwise
14959                || (!buffer.is_inside_word(offset_range.start, None)
14960                    && !buffer.is_inside_word(offset_range.end, None))
14961            {
14962                new_selections.push(offset_range.start..offset_range.end);
14963            }
14964        }
14965
14966        select_next_state.done = true;
14967
14968        if new_selections.is_empty() {
14969            log::error!("bug: new_selections is empty in select_all_matches");
14970            return Ok(());
14971        }
14972
14973        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14974        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14975            selections.select_ranges(new_selections)
14976        });
14977
14978        Ok(())
14979    }
14980
14981    pub fn select_next(
14982        &mut self,
14983        action: &SelectNext,
14984        window: &mut Window,
14985        cx: &mut Context<Self>,
14986    ) -> Result<()> {
14987        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14988        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14989        self.select_next_match_internal(
14990            &display_map,
14991            action.replace_newest,
14992            Some(Autoscroll::newest()),
14993            window,
14994            cx,
14995        )?;
14996        Ok(())
14997    }
14998
14999    pub fn select_previous(
15000        &mut self,
15001        action: &SelectPrevious,
15002        window: &mut Window,
15003        cx: &mut Context<Self>,
15004    ) -> Result<()> {
15005        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15006        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15007        let buffer = display_map.buffer_snapshot();
15008        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15009        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15010            let query = &select_prev_state.query;
15011            if !select_prev_state.done {
15012                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15013                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15014                let mut next_selected_range = None;
15015                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15016                let bytes_before_last_selection =
15017                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15018                let bytes_after_first_selection =
15019                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15020                let query_matches = query
15021                    .stream_find_iter(bytes_before_last_selection)
15022                    .map(|result| (last_selection.start, result))
15023                    .chain(
15024                        query
15025                            .stream_find_iter(bytes_after_first_selection)
15026                            .map(|result| (buffer.len(), result)),
15027                    );
15028                for (end_offset, query_match) in query_matches {
15029                    let query_match = query_match.unwrap(); // can only fail due to I/O
15030                    let offset_range =
15031                        end_offset - query_match.end()..end_offset - query_match.start();
15032
15033                    if !select_prev_state.wordwise
15034                        || (!buffer.is_inside_word(offset_range.start, None)
15035                            && !buffer.is_inside_word(offset_range.end, None))
15036                    {
15037                        next_selected_range = Some(offset_range);
15038                        break;
15039                    }
15040                }
15041
15042                if let Some(next_selected_range) = next_selected_range {
15043                    self.select_match_ranges(
15044                        next_selected_range,
15045                        last_selection.reversed,
15046                        action.replace_newest,
15047                        Some(Autoscroll::newest()),
15048                        window,
15049                        cx,
15050                    );
15051                } else {
15052                    select_prev_state.done = true;
15053                }
15054            }
15055
15056            self.select_prev_state = Some(select_prev_state);
15057        } else {
15058            let mut only_carets = true;
15059            let mut same_text_selected = true;
15060            let mut selected_text = None;
15061
15062            let mut selections_iter = selections.iter().peekable();
15063            while let Some(selection) = selections_iter.next() {
15064                if selection.start != selection.end {
15065                    only_carets = false;
15066                }
15067
15068                if same_text_selected {
15069                    if selected_text.is_none() {
15070                        selected_text =
15071                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15072                    }
15073
15074                    if let Some(next_selection) = selections_iter.peek() {
15075                        if next_selection.len() == selection.len() {
15076                            let next_selected_text = buffer
15077                                .text_for_range(next_selection.range())
15078                                .collect::<String>();
15079                            if Some(next_selected_text) != selected_text {
15080                                same_text_selected = false;
15081                                selected_text = None;
15082                            }
15083                        } else {
15084                            same_text_selected = false;
15085                            selected_text = None;
15086                        }
15087                    }
15088                }
15089            }
15090
15091            if only_carets {
15092                for selection in &mut selections {
15093                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15094                    selection.start = word_range.start;
15095                    selection.end = word_range.end;
15096                    selection.goal = SelectionGoal::None;
15097                    selection.reversed = false;
15098                    self.select_match_ranges(
15099                        selection.start..selection.end,
15100                        selection.reversed,
15101                        action.replace_newest,
15102                        Some(Autoscroll::newest()),
15103                        window,
15104                        cx,
15105                    );
15106                }
15107                if selections.len() == 1 {
15108                    let selection = selections
15109                        .last()
15110                        .expect("ensured that there's only one selection");
15111                    let query = buffer
15112                        .text_for_range(selection.start..selection.end)
15113                        .collect::<String>();
15114                    let is_empty = query.is_empty();
15115                    let select_state = SelectNextState {
15116                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15117                        wordwise: true,
15118                        done: is_empty,
15119                    };
15120                    self.select_prev_state = Some(select_state);
15121                } else {
15122                    self.select_prev_state = None;
15123                }
15124            } else if let Some(selected_text) = selected_text {
15125                self.select_prev_state = Some(SelectNextState {
15126                    query: self
15127                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15128                    wordwise: false,
15129                    done: false,
15130                });
15131                self.select_previous(action, window, cx)?;
15132            }
15133        }
15134        Ok(())
15135    }
15136
15137    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15138    /// setting the case sensitivity based on the global
15139    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15140    /// editor's settings.
15141    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15142    where
15143        I: IntoIterator<Item = P>,
15144        P: AsRef<[u8]>,
15145    {
15146        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
15147            || EditorSettings::get_global(cx).search.case_sensitive,
15148            |value| value,
15149        );
15150
15151        let mut builder = AhoCorasickBuilder::new();
15152        builder.ascii_case_insensitive(!case_sensitive);
15153        builder.build(patterns)
15154    }
15155
15156    pub fn find_next_match(
15157        &mut self,
15158        _: &FindNextMatch,
15159        window: &mut Window,
15160        cx: &mut Context<Self>,
15161    ) -> Result<()> {
15162        let selections = self.selections.disjoint_anchors_arc();
15163        match selections.first() {
15164            Some(first) if selections.len() >= 2 => {
15165                self.change_selections(Default::default(), window, cx, |s| {
15166                    s.select_ranges([first.range()]);
15167                });
15168            }
15169            _ => self.select_next(
15170                &SelectNext {
15171                    replace_newest: true,
15172                },
15173                window,
15174                cx,
15175            )?,
15176        }
15177        Ok(())
15178    }
15179
15180    pub fn find_previous_match(
15181        &mut self,
15182        _: &FindPreviousMatch,
15183        window: &mut Window,
15184        cx: &mut Context<Self>,
15185    ) -> Result<()> {
15186        let selections = self.selections.disjoint_anchors_arc();
15187        match selections.last() {
15188            Some(last) if selections.len() >= 2 => {
15189                self.change_selections(Default::default(), window, cx, |s| {
15190                    s.select_ranges([last.range()]);
15191                });
15192            }
15193            _ => self.select_previous(
15194                &SelectPrevious {
15195                    replace_newest: true,
15196                },
15197                window,
15198                cx,
15199            )?,
15200        }
15201        Ok(())
15202    }
15203
15204    pub fn toggle_comments(
15205        &mut self,
15206        action: &ToggleComments,
15207        window: &mut Window,
15208        cx: &mut Context<Self>,
15209    ) {
15210        if self.read_only(cx) {
15211            return;
15212        }
15213        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15214        let text_layout_details = &self.text_layout_details(window);
15215        self.transact(window, cx, |this, window, cx| {
15216            let mut selections = this
15217                .selections
15218                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15219            let mut edits = Vec::new();
15220            let mut selection_edit_ranges = Vec::new();
15221            let mut last_toggled_row = None;
15222            let snapshot = this.buffer.read(cx).read(cx);
15223            let empty_str: Arc<str> = Arc::default();
15224            let mut suffixes_inserted = Vec::new();
15225            let ignore_indent = action.ignore_indent;
15226
15227            fn comment_prefix_range(
15228                snapshot: &MultiBufferSnapshot,
15229                row: MultiBufferRow,
15230                comment_prefix: &str,
15231                comment_prefix_whitespace: &str,
15232                ignore_indent: bool,
15233            ) -> Range<Point> {
15234                let indent_size = if ignore_indent {
15235                    0
15236                } else {
15237                    snapshot.indent_size_for_line(row).len
15238                };
15239
15240                let start = Point::new(row.0, indent_size);
15241
15242                let mut line_bytes = snapshot
15243                    .bytes_in_range(start..snapshot.max_point())
15244                    .flatten()
15245                    .copied();
15246
15247                // If this line currently begins with the line comment prefix, then record
15248                // the range containing the prefix.
15249                if line_bytes
15250                    .by_ref()
15251                    .take(comment_prefix.len())
15252                    .eq(comment_prefix.bytes())
15253                {
15254                    // Include any whitespace that matches the comment prefix.
15255                    let matching_whitespace_len = line_bytes
15256                        .zip(comment_prefix_whitespace.bytes())
15257                        .take_while(|(a, b)| a == b)
15258                        .count() as u32;
15259                    let end = Point::new(
15260                        start.row,
15261                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15262                    );
15263                    start..end
15264                } else {
15265                    start..start
15266                }
15267            }
15268
15269            fn comment_suffix_range(
15270                snapshot: &MultiBufferSnapshot,
15271                row: MultiBufferRow,
15272                comment_suffix: &str,
15273                comment_suffix_has_leading_space: bool,
15274            ) -> Range<Point> {
15275                let end = Point::new(row.0, snapshot.line_len(row));
15276                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15277
15278                let mut line_end_bytes = snapshot
15279                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15280                    .flatten()
15281                    .copied();
15282
15283                let leading_space_len = if suffix_start_column > 0
15284                    && line_end_bytes.next() == Some(b' ')
15285                    && comment_suffix_has_leading_space
15286                {
15287                    1
15288                } else {
15289                    0
15290                };
15291
15292                // If this line currently begins with the line comment prefix, then record
15293                // the range containing the prefix.
15294                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15295                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15296                    start..end
15297                } else {
15298                    end..end
15299                }
15300            }
15301
15302            // TODO: Handle selections that cross excerpts
15303            for selection in &mut selections {
15304                let start_column = snapshot
15305                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15306                    .len;
15307                let language = if let Some(language) =
15308                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15309                {
15310                    language
15311                } else {
15312                    continue;
15313                };
15314
15315                selection_edit_ranges.clear();
15316
15317                // If multiple selections contain a given row, avoid processing that
15318                // row more than once.
15319                let mut start_row = MultiBufferRow(selection.start.row);
15320                if last_toggled_row == Some(start_row) {
15321                    start_row = start_row.next_row();
15322                }
15323                let end_row =
15324                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15325                        MultiBufferRow(selection.end.row - 1)
15326                    } else {
15327                        MultiBufferRow(selection.end.row)
15328                    };
15329                last_toggled_row = Some(end_row);
15330
15331                if start_row > end_row {
15332                    continue;
15333                }
15334
15335                // If the language has line comments, toggle those.
15336                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15337
15338                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15339                if ignore_indent {
15340                    full_comment_prefixes = full_comment_prefixes
15341                        .into_iter()
15342                        .map(|s| Arc::from(s.trim_end()))
15343                        .collect();
15344                }
15345
15346                if !full_comment_prefixes.is_empty() {
15347                    let first_prefix = full_comment_prefixes
15348                        .first()
15349                        .expect("prefixes is non-empty");
15350                    let prefix_trimmed_lengths = full_comment_prefixes
15351                        .iter()
15352                        .map(|p| p.trim_end_matches(' ').len())
15353                        .collect::<SmallVec<[usize; 4]>>();
15354
15355                    let mut all_selection_lines_are_comments = true;
15356
15357                    for row in start_row.0..=end_row.0 {
15358                        let row = MultiBufferRow(row);
15359                        if start_row < end_row && snapshot.is_line_blank(row) {
15360                            continue;
15361                        }
15362
15363                        let prefix_range = full_comment_prefixes
15364                            .iter()
15365                            .zip(prefix_trimmed_lengths.iter().copied())
15366                            .map(|(prefix, trimmed_prefix_len)| {
15367                                comment_prefix_range(
15368                                    snapshot.deref(),
15369                                    row,
15370                                    &prefix[..trimmed_prefix_len],
15371                                    &prefix[trimmed_prefix_len..],
15372                                    ignore_indent,
15373                                )
15374                            })
15375                            .max_by_key(|range| range.end.column - range.start.column)
15376                            .expect("prefixes is non-empty");
15377
15378                        if prefix_range.is_empty() {
15379                            all_selection_lines_are_comments = false;
15380                        }
15381
15382                        selection_edit_ranges.push(prefix_range);
15383                    }
15384
15385                    if all_selection_lines_are_comments {
15386                        edits.extend(
15387                            selection_edit_ranges
15388                                .iter()
15389                                .cloned()
15390                                .map(|range| (range, empty_str.clone())),
15391                        );
15392                    } else {
15393                        let min_column = selection_edit_ranges
15394                            .iter()
15395                            .map(|range| range.start.column)
15396                            .min()
15397                            .unwrap_or(0);
15398                        edits.extend(selection_edit_ranges.iter().map(|range| {
15399                            let position = Point::new(range.start.row, min_column);
15400                            (position..position, first_prefix.clone())
15401                        }));
15402                    }
15403                } else if let Some(BlockCommentConfig {
15404                    start: full_comment_prefix,
15405                    end: comment_suffix,
15406                    ..
15407                }) = language.block_comment()
15408                {
15409                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15410                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15411                    let prefix_range = comment_prefix_range(
15412                        snapshot.deref(),
15413                        start_row,
15414                        comment_prefix,
15415                        comment_prefix_whitespace,
15416                        ignore_indent,
15417                    );
15418                    let suffix_range = comment_suffix_range(
15419                        snapshot.deref(),
15420                        end_row,
15421                        comment_suffix.trim_start_matches(' '),
15422                        comment_suffix.starts_with(' '),
15423                    );
15424
15425                    if prefix_range.is_empty() || suffix_range.is_empty() {
15426                        edits.push((
15427                            prefix_range.start..prefix_range.start,
15428                            full_comment_prefix.clone(),
15429                        ));
15430                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15431                        suffixes_inserted.push((end_row, comment_suffix.len()));
15432                    } else {
15433                        edits.push((prefix_range, empty_str.clone()));
15434                        edits.push((suffix_range, empty_str.clone()));
15435                    }
15436                } else {
15437                    continue;
15438                }
15439            }
15440
15441            drop(snapshot);
15442            this.buffer.update(cx, |buffer, cx| {
15443                buffer.edit(edits, None, cx);
15444            });
15445
15446            // Adjust selections so that they end before any comment suffixes that
15447            // were inserted.
15448            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15449            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15450            let snapshot = this.buffer.read(cx).read(cx);
15451            for selection in &mut selections {
15452                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15453                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15454                        Ordering::Less => {
15455                            suffixes_inserted.next();
15456                            continue;
15457                        }
15458                        Ordering::Greater => break,
15459                        Ordering::Equal => {
15460                            if selection.end.column == snapshot.line_len(row) {
15461                                if selection.is_empty() {
15462                                    selection.start.column -= suffix_len as u32;
15463                                }
15464                                selection.end.column -= suffix_len as u32;
15465                            }
15466                            break;
15467                        }
15468                    }
15469                }
15470            }
15471
15472            drop(snapshot);
15473            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15474
15475            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15476            let selections_on_single_row = selections.windows(2).all(|selections| {
15477                selections[0].start.row == selections[1].start.row
15478                    && selections[0].end.row == selections[1].end.row
15479                    && selections[0].start.row == selections[0].end.row
15480            });
15481            let selections_selecting = selections
15482                .iter()
15483                .any(|selection| selection.start != selection.end);
15484            let advance_downwards = action.advance_downwards
15485                && selections_on_single_row
15486                && !selections_selecting
15487                && !matches!(this.mode, EditorMode::SingleLine);
15488
15489            if advance_downwards {
15490                let snapshot = this.buffer.read(cx).snapshot(cx);
15491
15492                this.change_selections(Default::default(), window, cx, |s| {
15493                    s.move_cursors_with(|display_snapshot, display_point, _| {
15494                        let mut point = display_point.to_point(display_snapshot);
15495                        point.row += 1;
15496                        point = snapshot.clip_point(point, Bias::Left);
15497                        let display_point = point.to_display_point(display_snapshot);
15498                        let goal = SelectionGoal::HorizontalPosition(
15499                            display_snapshot
15500                                .x_for_display_point(display_point, text_layout_details)
15501                                .into(),
15502                        );
15503                        (display_point, goal)
15504                    })
15505                });
15506            }
15507        });
15508    }
15509
15510    pub fn select_enclosing_symbol(
15511        &mut self,
15512        _: &SelectEnclosingSymbol,
15513        window: &mut Window,
15514        cx: &mut Context<Self>,
15515    ) {
15516        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15517
15518        let buffer = self.buffer.read(cx).snapshot(cx);
15519        let old_selections = self
15520            .selections
15521            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15522            .into_boxed_slice();
15523
15524        fn update_selection(
15525            selection: &Selection<MultiBufferOffset>,
15526            buffer_snap: &MultiBufferSnapshot,
15527        ) -> Option<Selection<MultiBufferOffset>> {
15528            let cursor = selection.head();
15529            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15530            for symbol in symbols.iter().rev() {
15531                let start = symbol.range.start.to_offset(buffer_snap);
15532                let end = symbol.range.end.to_offset(buffer_snap);
15533                let new_range = start..end;
15534                if start < selection.start || end > selection.end {
15535                    return Some(Selection {
15536                        id: selection.id,
15537                        start: new_range.start,
15538                        end: new_range.end,
15539                        goal: SelectionGoal::None,
15540                        reversed: selection.reversed,
15541                    });
15542                }
15543            }
15544            None
15545        }
15546
15547        let mut selected_larger_symbol = false;
15548        let new_selections = old_selections
15549            .iter()
15550            .map(|selection| match update_selection(selection, &buffer) {
15551                Some(new_selection) => {
15552                    if new_selection.range() != selection.range() {
15553                        selected_larger_symbol = true;
15554                    }
15555                    new_selection
15556                }
15557                None => selection.clone(),
15558            })
15559            .collect::<Vec<_>>();
15560
15561        if selected_larger_symbol {
15562            self.change_selections(Default::default(), window, cx, |s| {
15563                s.select(new_selections);
15564            });
15565        }
15566    }
15567
15568    pub fn select_larger_syntax_node(
15569        &mut self,
15570        _: &SelectLargerSyntaxNode,
15571        window: &mut Window,
15572        cx: &mut Context<Self>,
15573    ) {
15574        let Some(visible_row_count) = self.visible_row_count() else {
15575            return;
15576        };
15577        let old_selections: Box<[_]> = self
15578            .selections
15579            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15580            .into();
15581        if old_selections.is_empty() {
15582            return;
15583        }
15584
15585        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15586
15587        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15588        let buffer = self.buffer.read(cx).snapshot(cx);
15589
15590        let mut selected_larger_node = false;
15591        let mut new_selections = old_selections
15592            .iter()
15593            .map(|selection| {
15594                let old_range = selection.start..selection.end;
15595
15596                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15597                    // manually select word at selection
15598                    if ["string_content", "inline"].contains(&node.kind()) {
15599                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15600                        // ignore if word is already selected
15601                        if !word_range.is_empty() && old_range != word_range {
15602                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15603                            // only select word if start and end point belongs to same word
15604                            if word_range == last_word_range {
15605                                selected_larger_node = true;
15606                                return Selection {
15607                                    id: selection.id,
15608                                    start: word_range.start,
15609                                    end: word_range.end,
15610                                    goal: SelectionGoal::None,
15611                                    reversed: selection.reversed,
15612                                };
15613                            }
15614                        }
15615                    }
15616                }
15617
15618                let mut new_range = old_range.clone();
15619                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15620                    new_range = range;
15621                    if !node.is_named() {
15622                        continue;
15623                    }
15624                    if !display_map.intersects_fold(new_range.start)
15625                        && !display_map.intersects_fold(new_range.end)
15626                    {
15627                        break;
15628                    }
15629                }
15630
15631                selected_larger_node |= new_range != old_range;
15632                Selection {
15633                    id: selection.id,
15634                    start: new_range.start,
15635                    end: new_range.end,
15636                    goal: SelectionGoal::None,
15637                    reversed: selection.reversed,
15638                }
15639            })
15640            .collect::<Vec<_>>();
15641
15642        if !selected_larger_node {
15643            return; // don't put this call in the history
15644        }
15645
15646        // scroll based on transformation done to the last selection created by the user
15647        let (last_old, last_new) = old_selections
15648            .last()
15649            .zip(new_selections.last().cloned())
15650            .expect("old_selections isn't empty");
15651
15652        // revert selection
15653        let is_selection_reversed = {
15654            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15655            new_selections.last_mut().expect("checked above").reversed =
15656                should_newest_selection_be_reversed;
15657            should_newest_selection_be_reversed
15658        };
15659
15660        if selected_larger_node {
15661            self.select_syntax_node_history.disable_clearing = true;
15662            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15663                s.select(new_selections.clone());
15664            });
15665            self.select_syntax_node_history.disable_clearing = false;
15666        }
15667
15668        let start_row = last_new.start.to_display_point(&display_map).row().0;
15669        let end_row = last_new.end.to_display_point(&display_map).row().0;
15670        let selection_height = end_row - start_row + 1;
15671        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15672
15673        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15674        let scroll_behavior = if fits_on_the_screen {
15675            self.request_autoscroll(Autoscroll::fit(), cx);
15676            SelectSyntaxNodeScrollBehavior::FitSelection
15677        } else if is_selection_reversed {
15678            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15679            SelectSyntaxNodeScrollBehavior::CursorTop
15680        } else {
15681            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15682            SelectSyntaxNodeScrollBehavior::CursorBottom
15683        };
15684
15685        self.select_syntax_node_history.push((
15686            old_selections,
15687            scroll_behavior,
15688            is_selection_reversed,
15689        ));
15690    }
15691
15692    pub fn select_smaller_syntax_node(
15693        &mut self,
15694        _: &SelectSmallerSyntaxNode,
15695        window: &mut Window,
15696        cx: &mut Context<Self>,
15697    ) {
15698        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15699
15700        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15701            self.select_syntax_node_history.pop()
15702        {
15703            if let Some(selection) = selections.last_mut() {
15704                selection.reversed = is_selection_reversed;
15705            }
15706
15707            self.select_syntax_node_history.disable_clearing = true;
15708            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15709                s.select(selections.to_vec());
15710            });
15711            self.select_syntax_node_history.disable_clearing = false;
15712
15713            match scroll_behavior {
15714                SelectSyntaxNodeScrollBehavior::CursorTop => {
15715                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15716                }
15717                SelectSyntaxNodeScrollBehavior::FitSelection => {
15718                    self.request_autoscroll(Autoscroll::fit(), cx);
15719                }
15720                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15721                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15722                }
15723            }
15724        }
15725    }
15726
15727    pub fn unwrap_syntax_node(
15728        &mut self,
15729        _: &UnwrapSyntaxNode,
15730        window: &mut Window,
15731        cx: &mut Context<Self>,
15732    ) {
15733        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15734
15735        let buffer = self.buffer.read(cx).snapshot(cx);
15736        let selections = self
15737            .selections
15738            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15739            .into_iter()
15740            // subtracting the offset requires sorting
15741            .sorted_by_key(|i| i.start);
15742
15743        let full_edits = selections
15744            .into_iter()
15745            .filter_map(|selection| {
15746                let child = if selection.is_empty()
15747                    && let Some((_, ancestor_range)) =
15748                        buffer.syntax_ancestor(selection.start..selection.end)
15749                {
15750                    ancestor_range
15751                } else {
15752                    selection.range()
15753                };
15754
15755                let mut parent = child.clone();
15756                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15757                    parent = ancestor_range;
15758                    if parent.start < child.start || parent.end > child.end {
15759                        break;
15760                    }
15761                }
15762
15763                if parent == child {
15764                    return None;
15765                }
15766                let text = buffer.text_for_range(child).collect::<String>();
15767                Some((selection.id, parent, text))
15768            })
15769            .collect::<Vec<_>>();
15770        if full_edits.is_empty() {
15771            return;
15772        }
15773
15774        self.transact(window, cx, |this, window, cx| {
15775            this.buffer.update(cx, |buffer, cx| {
15776                buffer.edit(
15777                    full_edits
15778                        .iter()
15779                        .map(|(_, p, t)| (p.clone(), t.clone()))
15780                        .collect::<Vec<_>>(),
15781                    None,
15782                    cx,
15783                );
15784            });
15785            this.change_selections(Default::default(), window, cx, |s| {
15786                let mut offset = 0;
15787                let mut selections = vec![];
15788                for (id, parent, text) in full_edits {
15789                    let start = parent.start - offset;
15790                    offset += (parent.end - parent.start) - text.len();
15791                    selections.push(Selection {
15792                        id,
15793                        start,
15794                        end: start + text.len(),
15795                        reversed: false,
15796                        goal: Default::default(),
15797                    });
15798                }
15799                s.select(selections);
15800            });
15801        });
15802    }
15803
15804    pub fn select_next_syntax_node(
15805        &mut self,
15806        _: &SelectNextSyntaxNode,
15807        window: &mut Window,
15808        cx: &mut Context<Self>,
15809    ) {
15810        let old_selections: Box<[_]> = self
15811            .selections
15812            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15813            .into();
15814        if old_selections.is_empty() {
15815            return;
15816        }
15817
15818        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15819
15820        let buffer = self.buffer.read(cx).snapshot(cx);
15821        let mut selected_sibling = false;
15822
15823        let new_selections = old_selections
15824            .iter()
15825            .map(|selection| {
15826                let old_range = selection.start..selection.end;
15827
15828                let old_range =
15829                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15830                let excerpt = buffer.excerpt_containing(old_range.clone());
15831
15832                if let Some(mut excerpt) = excerpt
15833                    && let Some(node) = excerpt
15834                        .buffer()
15835                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
15836                {
15837                    let new_range = excerpt.map_range_from_buffer(
15838                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15839                    );
15840                    selected_sibling = true;
15841                    Selection {
15842                        id: selection.id,
15843                        start: new_range.start,
15844                        end: new_range.end,
15845                        goal: SelectionGoal::None,
15846                        reversed: selection.reversed,
15847                    }
15848                } else {
15849                    selection.clone()
15850                }
15851            })
15852            .collect::<Vec<_>>();
15853
15854        if selected_sibling {
15855            self.change_selections(
15856                SelectionEffects::scroll(Autoscroll::fit()),
15857                window,
15858                cx,
15859                |s| {
15860                    s.select(new_selections);
15861                },
15862            );
15863        }
15864    }
15865
15866    pub fn select_prev_syntax_node(
15867        &mut self,
15868        _: &SelectPreviousSyntaxNode,
15869        window: &mut Window,
15870        cx: &mut Context<Self>,
15871    ) {
15872        let old_selections: Box<[_]> = self
15873            .selections
15874            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15875            .into();
15876        if old_selections.is_empty() {
15877            return;
15878        }
15879
15880        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15881
15882        let buffer = self.buffer.read(cx).snapshot(cx);
15883        let mut selected_sibling = false;
15884
15885        let new_selections = old_selections
15886            .iter()
15887            .map(|selection| {
15888                let old_range = selection.start..selection.end;
15889                let old_range =
15890                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15891                let excerpt = buffer.excerpt_containing(old_range.clone());
15892
15893                if let Some(mut excerpt) = excerpt
15894                    && let Some(node) = excerpt
15895                        .buffer()
15896                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
15897                {
15898                    let new_range = excerpt.map_range_from_buffer(
15899                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15900                    );
15901                    selected_sibling = true;
15902                    Selection {
15903                        id: selection.id,
15904                        start: new_range.start,
15905                        end: new_range.end,
15906                        goal: SelectionGoal::None,
15907                        reversed: selection.reversed,
15908                    }
15909                } else {
15910                    selection.clone()
15911                }
15912            })
15913            .collect::<Vec<_>>();
15914
15915        if selected_sibling {
15916            self.change_selections(
15917                SelectionEffects::scroll(Autoscroll::fit()),
15918                window,
15919                cx,
15920                |s| {
15921                    s.select(new_selections);
15922                },
15923            );
15924        }
15925    }
15926
15927    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15928        if !EditorSettings::get_global(cx).gutter.runnables {
15929            self.clear_tasks();
15930            return Task::ready(());
15931        }
15932        let project = self.project().map(Entity::downgrade);
15933        let task_sources = self.lsp_task_sources(cx);
15934        let multi_buffer = self.buffer.downgrade();
15935        cx.spawn_in(window, async move |editor, cx| {
15936            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15937            let Some(project) = project.and_then(|p| p.upgrade()) else {
15938                return;
15939            };
15940            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15941                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15942            }) else {
15943                return;
15944            };
15945
15946            let hide_runnables = project
15947                .update(cx, |project, _| project.is_via_collab())
15948                .unwrap_or(true);
15949            if hide_runnables {
15950                return;
15951            }
15952            let new_rows =
15953                cx.background_spawn({
15954                    let snapshot = display_snapshot.clone();
15955                    async move {
15956                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15957                    }
15958                })
15959                    .await;
15960            let Ok(lsp_tasks) =
15961                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15962            else {
15963                return;
15964            };
15965            let lsp_tasks = lsp_tasks.await;
15966
15967            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15968                lsp_tasks
15969                    .into_iter()
15970                    .flat_map(|(kind, tasks)| {
15971                        tasks.into_iter().filter_map(move |(location, task)| {
15972                            Some((kind.clone(), location?, task))
15973                        })
15974                    })
15975                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15976                        let buffer = location.target.buffer;
15977                        let buffer_snapshot = buffer.read(cx).snapshot();
15978                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15979                            |(excerpt_id, snapshot, _)| {
15980                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15981                                    display_snapshot
15982                                        .buffer_snapshot()
15983                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15984                                } else {
15985                                    None
15986                                }
15987                            },
15988                        );
15989                        if let Some(offset) = offset {
15990                            let task_buffer_range =
15991                                location.target.range.to_point(&buffer_snapshot);
15992                            let context_buffer_range =
15993                                task_buffer_range.to_offset(&buffer_snapshot);
15994                            let context_range = BufferOffset(context_buffer_range.start)
15995                                ..BufferOffset(context_buffer_range.end);
15996
15997                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15998                                .or_insert_with(|| RunnableTasks {
15999                                    templates: Vec::new(),
16000                                    offset,
16001                                    column: task_buffer_range.start.column,
16002                                    extra_variables: HashMap::default(),
16003                                    context_range,
16004                                })
16005                                .templates
16006                                .push((kind, task.original_task().clone()));
16007                        }
16008
16009                        acc
16010                    })
16011            }) else {
16012                return;
16013            };
16014
16015            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16016                buffer.language_settings(cx).tasks.prefer_lsp
16017            }) else {
16018                return;
16019            };
16020
16021            let rows = Self::runnable_rows(
16022                project,
16023                display_snapshot,
16024                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16025                new_rows,
16026                cx.clone(),
16027            )
16028            .await;
16029            editor
16030                .update(cx, |editor, _| {
16031                    editor.clear_tasks();
16032                    for (key, mut value) in rows {
16033                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16034                            value.templates.extend(lsp_tasks.templates);
16035                        }
16036
16037                        editor.insert_tasks(key, value);
16038                    }
16039                    for (key, value) in lsp_tasks_by_rows {
16040                        editor.insert_tasks(key, value);
16041                    }
16042                })
16043                .ok();
16044        })
16045    }
16046    fn fetch_runnable_ranges(
16047        snapshot: &DisplaySnapshot,
16048        range: Range<Anchor>,
16049    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16050        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16051    }
16052
16053    fn runnable_rows(
16054        project: Entity<Project>,
16055        snapshot: DisplaySnapshot,
16056        prefer_lsp: bool,
16057        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16058        cx: AsyncWindowContext,
16059    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16060        cx.spawn(async move |cx| {
16061            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16062            for (run_range, mut runnable) in runnable_ranges {
16063                let Some(tasks) = cx
16064                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16065                    .ok()
16066                else {
16067                    continue;
16068                };
16069                let mut tasks = tasks.await;
16070
16071                if prefer_lsp {
16072                    tasks.retain(|(task_kind, _)| {
16073                        !matches!(task_kind, TaskSourceKind::Language { .. })
16074                    });
16075                }
16076                if tasks.is_empty() {
16077                    continue;
16078                }
16079
16080                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16081                let Some(row) = snapshot
16082                    .buffer_snapshot()
16083                    .buffer_line_for_row(MultiBufferRow(point.row))
16084                    .map(|(_, range)| range.start.row)
16085                else {
16086                    continue;
16087                };
16088
16089                let context_range =
16090                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16091                runnable_rows.push((
16092                    (runnable.buffer_id, row),
16093                    RunnableTasks {
16094                        templates: tasks,
16095                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16096                        context_range,
16097                        column: point.column,
16098                        extra_variables: runnable.extra_captures,
16099                    },
16100                ));
16101            }
16102            runnable_rows
16103        })
16104    }
16105
16106    fn templates_with_tags(
16107        project: &Entity<Project>,
16108        runnable: &mut Runnable,
16109        cx: &mut App,
16110    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16111        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16112            let (worktree_id, file) = project
16113                .buffer_for_id(runnable.buffer, cx)
16114                .and_then(|buffer| buffer.read(cx).file())
16115                .map(|file| (file.worktree_id(cx), file.clone()))
16116                .unzip();
16117
16118            (
16119                project.task_store().read(cx).task_inventory().cloned(),
16120                worktree_id,
16121                file,
16122            )
16123        });
16124
16125        let tags = mem::take(&mut runnable.tags);
16126        let language = runnable.language.clone();
16127        cx.spawn(async move |cx| {
16128            let mut templates_with_tags = Vec::new();
16129            if let Some(inventory) = inventory {
16130                for RunnableTag(tag) in tags {
16131                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16132                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16133                    }) else {
16134                        return templates_with_tags;
16135                    };
16136                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16137                        move |(_, template)| {
16138                            template.tags.iter().any(|source_tag| source_tag == &tag)
16139                        },
16140                    ));
16141                }
16142            }
16143            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16144
16145            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16146                // Strongest source wins; if we have worktree tag binding, prefer that to
16147                // global and language bindings;
16148                // if we have a global binding, prefer that to language binding.
16149                let first_mismatch = templates_with_tags
16150                    .iter()
16151                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16152                if let Some(index) = first_mismatch {
16153                    templates_with_tags.truncate(index);
16154                }
16155            }
16156
16157            templates_with_tags
16158        })
16159    }
16160
16161    pub fn move_to_enclosing_bracket(
16162        &mut self,
16163        _: &MoveToEnclosingBracket,
16164        window: &mut Window,
16165        cx: &mut Context<Self>,
16166    ) {
16167        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16168        self.change_selections(Default::default(), window, cx, |s| {
16169            s.move_offsets_with(|snapshot, selection| {
16170                let Some(enclosing_bracket_ranges) =
16171                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16172                else {
16173                    return;
16174                };
16175
16176                let mut best_length = usize::MAX;
16177                let mut best_inside = false;
16178                let mut best_in_bracket_range = false;
16179                let mut best_destination = None;
16180                for (open, close) in enclosing_bracket_ranges {
16181                    let close = close.to_inclusive();
16182                    let length = *close.end() - open.start;
16183                    let inside = selection.start >= open.end && selection.end <= *close.start();
16184                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16185                        || close.contains(&selection.head());
16186
16187                    // If best is next to a bracket and current isn't, skip
16188                    if !in_bracket_range && best_in_bracket_range {
16189                        continue;
16190                    }
16191
16192                    // Prefer smaller lengths unless best is inside and current isn't
16193                    if length > best_length && (best_inside || !inside) {
16194                        continue;
16195                    }
16196
16197                    best_length = length;
16198                    best_inside = inside;
16199                    best_in_bracket_range = in_bracket_range;
16200                    best_destination = Some(
16201                        if close.contains(&selection.start) && close.contains(&selection.end) {
16202                            if inside { open.end } else { open.start }
16203                        } else if inside {
16204                            *close.start()
16205                        } else {
16206                            *close.end()
16207                        },
16208                    );
16209                }
16210
16211                if let Some(destination) = best_destination {
16212                    selection.collapse_to(destination, SelectionGoal::None);
16213                }
16214            })
16215        });
16216    }
16217
16218    pub fn undo_selection(
16219        &mut self,
16220        _: &UndoSelection,
16221        window: &mut Window,
16222        cx: &mut Context<Self>,
16223    ) {
16224        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16225        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16226            self.selection_history.mode = SelectionHistoryMode::Undoing;
16227            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16228                this.end_selection(window, cx);
16229                this.change_selections(
16230                    SelectionEffects::scroll(Autoscroll::newest()),
16231                    window,
16232                    cx,
16233                    |s| s.select_anchors(entry.selections.to_vec()),
16234                );
16235            });
16236            self.selection_history.mode = SelectionHistoryMode::Normal;
16237
16238            self.select_next_state = entry.select_next_state;
16239            self.select_prev_state = entry.select_prev_state;
16240            self.add_selections_state = entry.add_selections_state;
16241        }
16242    }
16243
16244    pub fn redo_selection(
16245        &mut self,
16246        _: &RedoSelection,
16247        window: &mut Window,
16248        cx: &mut Context<Self>,
16249    ) {
16250        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16251        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16252            self.selection_history.mode = SelectionHistoryMode::Redoing;
16253            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16254                this.end_selection(window, cx);
16255                this.change_selections(
16256                    SelectionEffects::scroll(Autoscroll::newest()),
16257                    window,
16258                    cx,
16259                    |s| s.select_anchors(entry.selections.to_vec()),
16260                );
16261            });
16262            self.selection_history.mode = SelectionHistoryMode::Normal;
16263
16264            self.select_next_state = entry.select_next_state;
16265            self.select_prev_state = entry.select_prev_state;
16266            self.add_selections_state = entry.add_selections_state;
16267        }
16268    }
16269
16270    pub fn expand_excerpts(
16271        &mut self,
16272        action: &ExpandExcerpts,
16273        _: &mut Window,
16274        cx: &mut Context<Self>,
16275    ) {
16276        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16277    }
16278
16279    pub fn expand_excerpts_down(
16280        &mut self,
16281        action: &ExpandExcerptsDown,
16282        _: &mut Window,
16283        cx: &mut Context<Self>,
16284    ) {
16285        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16286    }
16287
16288    pub fn expand_excerpts_up(
16289        &mut self,
16290        action: &ExpandExcerptsUp,
16291        _: &mut Window,
16292        cx: &mut Context<Self>,
16293    ) {
16294        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16295    }
16296
16297    pub fn expand_excerpts_for_direction(
16298        &mut self,
16299        lines: u32,
16300        direction: ExpandExcerptDirection,
16301
16302        cx: &mut Context<Self>,
16303    ) {
16304        let selections = self.selections.disjoint_anchors_arc();
16305
16306        let lines = if lines == 0 {
16307            EditorSettings::get_global(cx).expand_excerpt_lines
16308        } else {
16309            lines
16310        };
16311
16312        self.buffer.update(cx, |buffer, cx| {
16313            let snapshot = buffer.snapshot(cx);
16314            let mut excerpt_ids = selections
16315                .iter()
16316                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16317                .collect::<Vec<_>>();
16318            excerpt_ids.sort();
16319            excerpt_ids.dedup();
16320            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16321        })
16322    }
16323
16324    pub fn expand_excerpt(
16325        &mut self,
16326        excerpt: ExcerptId,
16327        direction: ExpandExcerptDirection,
16328        window: &mut Window,
16329        cx: &mut Context<Self>,
16330    ) {
16331        let current_scroll_position = self.scroll_position(cx);
16332        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16333        let mut scroll = None;
16334
16335        if direction == ExpandExcerptDirection::Down {
16336            let multi_buffer = self.buffer.read(cx);
16337            let snapshot = multi_buffer.snapshot(cx);
16338            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16339                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16340                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16341            {
16342                let buffer_snapshot = buffer.read(cx).snapshot();
16343                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16344                let last_row = buffer_snapshot.max_point().row;
16345                let lines_below = last_row.saturating_sub(excerpt_end_row);
16346                if lines_below >= lines_to_expand {
16347                    scroll = Some(
16348                        current_scroll_position
16349                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16350                    );
16351                }
16352            }
16353        }
16354        if direction == ExpandExcerptDirection::Up
16355            && self
16356                .buffer
16357                .read(cx)
16358                .snapshot(cx)
16359                .excerpt_before(excerpt)
16360                .is_none()
16361        {
16362            scroll = Some(current_scroll_position);
16363        }
16364
16365        self.buffer.update(cx, |buffer, cx| {
16366            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16367        });
16368
16369        if let Some(new_scroll_position) = scroll {
16370            self.set_scroll_position(new_scroll_position, window, cx);
16371        }
16372    }
16373
16374    pub fn go_to_singleton_buffer_point(
16375        &mut self,
16376        point: Point,
16377        window: &mut Window,
16378        cx: &mut Context<Self>,
16379    ) {
16380        self.go_to_singleton_buffer_range(point..point, window, cx);
16381    }
16382
16383    pub fn go_to_singleton_buffer_range(
16384        &mut self,
16385        range: Range<Point>,
16386        window: &mut Window,
16387        cx: &mut Context<Self>,
16388    ) {
16389        let multibuffer = self.buffer().read(cx);
16390        let Some(buffer) = multibuffer.as_singleton() else {
16391            return;
16392        };
16393        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16394            return;
16395        };
16396        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16397            return;
16398        };
16399        self.change_selections(
16400            SelectionEffects::default().nav_history(true),
16401            window,
16402            cx,
16403            |s| s.select_anchor_ranges([start..end]),
16404        );
16405    }
16406
16407    pub fn go_to_diagnostic(
16408        &mut self,
16409        action: &GoToDiagnostic,
16410        window: &mut Window,
16411        cx: &mut Context<Self>,
16412    ) {
16413        if !self.diagnostics_enabled() {
16414            return;
16415        }
16416        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16417        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16418    }
16419
16420    pub fn go_to_prev_diagnostic(
16421        &mut self,
16422        action: &GoToPreviousDiagnostic,
16423        window: &mut Window,
16424        cx: &mut Context<Self>,
16425    ) {
16426        if !self.diagnostics_enabled() {
16427            return;
16428        }
16429        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16430        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16431    }
16432
16433    pub fn go_to_diagnostic_impl(
16434        &mut self,
16435        direction: Direction,
16436        severity: GoToDiagnosticSeverityFilter,
16437        window: &mut Window,
16438        cx: &mut Context<Self>,
16439    ) {
16440        let buffer = self.buffer.read(cx).snapshot(cx);
16441        let selection = self
16442            .selections
16443            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16444
16445        let mut active_group_id = None;
16446        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16447            && active_group.active_range.start.to_offset(&buffer) == selection.start
16448        {
16449            active_group_id = Some(active_group.group_id);
16450        }
16451
16452        fn filtered<'a>(
16453            severity: GoToDiagnosticSeverityFilter,
16454            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16455        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16456            diagnostics
16457                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16458                .filter(|entry| entry.range.start != entry.range.end)
16459                .filter(|entry| !entry.diagnostic.is_unnecessary)
16460        }
16461
16462        let before = filtered(
16463            severity,
16464            buffer
16465                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16466                .filter(|entry| entry.range.start <= selection.start),
16467        );
16468        let after = filtered(
16469            severity,
16470            buffer
16471                .diagnostics_in_range(selection.start..buffer.len())
16472                .filter(|entry| entry.range.start >= selection.start),
16473        );
16474
16475        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16476        if direction == Direction::Prev {
16477            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16478            {
16479                for diagnostic in prev_diagnostics.into_iter().rev() {
16480                    if diagnostic.range.start != selection.start
16481                        || active_group_id
16482                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16483                    {
16484                        found = Some(diagnostic);
16485                        break 'outer;
16486                    }
16487                }
16488            }
16489        } else {
16490            for diagnostic in after.chain(before) {
16491                if diagnostic.range.start != selection.start
16492                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16493                {
16494                    found = Some(diagnostic);
16495                    break;
16496                }
16497            }
16498        }
16499        let Some(next_diagnostic) = found else {
16500            return;
16501        };
16502
16503        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16504        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16505            return;
16506        };
16507        let snapshot = self.snapshot(window, cx);
16508        if snapshot.intersects_fold(next_diagnostic.range.start) {
16509            self.unfold_ranges(
16510                std::slice::from_ref(&next_diagnostic.range),
16511                true,
16512                false,
16513                cx,
16514            );
16515        }
16516        self.change_selections(Default::default(), window, cx, |s| {
16517            s.select_ranges(vec![
16518                next_diagnostic.range.start..next_diagnostic.range.start,
16519            ])
16520        });
16521        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16522        self.refresh_edit_prediction(false, true, window, cx);
16523    }
16524
16525    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16526        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16527        let snapshot = self.snapshot(window, cx);
16528        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16529        self.go_to_hunk_before_or_after_position(
16530            &snapshot,
16531            selection.head(),
16532            Direction::Next,
16533            window,
16534            cx,
16535        );
16536    }
16537
16538    pub fn go_to_hunk_before_or_after_position(
16539        &mut self,
16540        snapshot: &EditorSnapshot,
16541        position: Point,
16542        direction: Direction,
16543        window: &mut Window,
16544        cx: &mut Context<Editor>,
16545    ) {
16546        let row = if direction == Direction::Next {
16547            self.hunk_after_position(snapshot, position)
16548                .map(|hunk| hunk.row_range.start)
16549        } else {
16550            self.hunk_before_position(snapshot, position)
16551        };
16552
16553        if let Some(row) = row {
16554            let destination = Point::new(row.0, 0);
16555            let autoscroll = Autoscroll::center();
16556
16557            self.unfold_ranges(&[destination..destination], false, false, cx);
16558            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16559                s.select_ranges([destination..destination]);
16560            });
16561        }
16562    }
16563
16564    fn hunk_after_position(
16565        &mut self,
16566        snapshot: &EditorSnapshot,
16567        position: Point,
16568    ) -> Option<MultiBufferDiffHunk> {
16569        snapshot
16570            .buffer_snapshot()
16571            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16572            .find(|hunk| hunk.row_range.start.0 > position.row)
16573            .or_else(|| {
16574                snapshot
16575                    .buffer_snapshot()
16576                    .diff_hunks_in_range(Point::zero()..position)
16577                    .find(|hunk| hunk.row_range.end.0 < position.row)
16578            })
16579    }
16580
16581    fn go_to_prev_hunk(
16582        &mut self,
16583        _: &GoToPreviousHunk,
16584        window: &mut Window,
16585        cx: &mut Context<Self>,
16586    ) {
16587        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16588        let snapshot = self.snapshot(window, cx);
16589        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16590        self.go_to_hunk_before_or_after_position(
16591            &snapshot,
16592            selection.head(),
16593            Direction::Prev,
16594            window,
16595            cx,
16596        );
16597    }
16598
16599    fn hunk_before_position(
16600        &mut self,
16601        snapshot: &EditorSnapshot,
16602        position: Point,
16603    ) -> Option<MultiBufferRow> {
16604        snapshot
16605            .buffer_snapshot()
16606            .diff_hunk_before(position)
16607            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16608    }
16609
16610    fn go_to_next_change(
16611        &mut self,
16612        _: &GoToNextChange,
16613        window: &mut Window,
16614        cx: &mut Context<Self>,
16615    ) {
16616        if let Some(selections) = self
16617            .change_list
16618            .next_change(1, Direction::Next)
16619            .map(|s| s.to_vec())
16620        {
16621            self.change_selections(Default::default(), window, cx, |s| {
16622                let map = s.display_snapshot();
16623                s.select_display_ranges(selections.iter().map(|a| {
16624                    let point = a.to_display_point(&map);
16625                    point..point
16626                }))
16627            })
16628        }
16629    }
16630
16631    fn go_to_previous_change(
16632        &mut self,
16633        _: &GoToPreviousChange,
16634        window: &mut Window,
16635        cx: &mut Context<Self>,
16636    ) {
16637        if let Some(selections) = self
16638            .change_list
16639            .next_change(1, Direction::Prev)
16640            .map(|s| s.to_vec())
16641        {
16642            self.change_selections(Default::default(), window, cx, |s| {
16643                let map = s.display_snapshot();
16644                s.select_display_ranges(selections.iter().map(|a| {
16645                    let point = a.to_display_point(&map);
16646                    point..point
16647                }))
16648            })
16649        }
16650    }
16651
16652    pub fn go_to_next_document_highlight(
16653        &mut self,
16654        _: &GoToNextDocumentHighlight,
16655        window: &mut Window,
16656        cx: &mut Context<Self>,
16657    ) {
16658        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16659    }
16660
16661    pub fn go_to_prev_document_highlight(
16662        &mut self,
16663        _: &GoToPreviousDocumentHighlight,
16664        window: &mut Window,
16665        cx: &mut Context<Self>,
16666    ) {
16667        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16668    }
16669
16670    pub fn go_to_document_highlight_before_or_after_position(
16671        &mut self,
16672        direction: Direction,
16673        window: &mut Window,
16674        cx: &mut Context<Editor>,
16675    ) {
16676        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16677        let snapshot = self.snapshot(window, cx);
16678        let buffer = &snapshot.buffer_snapshot();
16679        let position = self
16680            .selections
16681            .newest::<Point>(&snapshot.display_snapshot)
16682            .head();
16683        let anchor_position = buffer.anchor_after(position);
16684
16685        // Get all document highlights (both read and write)
16686        let mut all_highlights = Vec::new();
16687
16688        if let Some((_, read_highlights)) = self
16689            .background_highlights
16690            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16691        {
16692            all_highlights.extend(read_highlights.iter());
16693        }
16694
16695        if let Some((_, write_highlights)) = self
16696            .background_highlights
16697            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16698        {
16699            all_highlights.extend(write_highlights.iter());
16700        }
16701
16702        if all_highlights.is_empty() {
16703            return;
16704        }
16705
16706        // Sort highlights by position
16707        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16708
16709        let target_highlight = match direction {
16710            Direction::Next => {
16711                // Find the first highlight after the current position
16712                all_highlights
16713                    .iter()
16714                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16715            }
16716            Direction::Prev => {
16717                // Find the last highlight before the current position
16718                all_highlights
16719                    .iter()
16720                    .rev()
16721                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16722            }
16723        };
16724
16725        if let Some(highlight) = target_highlight {
16726            let destination = highlight.start.to_point(buffer);
16727            let autoscroll = Autoscroll::center();
16728
16729            self.unfold_ranges(&[destination..destination], false, false, cx);
16730            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16731                s.select_ranges([destination..destination]);
16732            });
16733        }
16734    }
16735
16736    fn go_to_line<T: 'static>(
16737        &mut self,
16738        position: Anchor,
16739        highlight_color: Option<Hsla>,
16740        window: &mut Window,
16741        cx: &mut Context<Self>,
16742    ) {
16743        let snapshot = self.snapshot(window, cx).display_snapshot;
16744        let position = position.to_point(&snapshot.buffer_snapshot());
16745        let start = snapshot
16746            .buffer_snapshot()
16747            .clip_point(Point::new(position.row, 0), Bias::Left);
16748        let end = start + Point::new(1, 0);
16749        let start = snapshot.buffer_snapshot().anchor_before(start);
16750        let end = snapshot.buffer_snapshot().anchor_before(end);
16751
16752        self.highlight_rows::<T>(
16753            start..end,
16754            highlight_color
16755                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16756            Default::default(),
16757            cx,
16758        );
16759
16760        if self.buffer.read(cx).is_singleton() {
16761            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16762        }
16763    }
16764
16765    pub fn go_to_definition(
16766        &mut self,
16767        _: &GoToDefinition,
16768        window: &mut Window,
16769        cx: &mut Context<Self>,
16770    ) -> Task<Result<Navigated>> {
16771        let definition =
16772            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16773        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16774        cx.spawn_in(window, async move |editor, cx| {
16775            if definition.await? == Navigated::Yes {
16776                return Ok(Navigated::Yes);
16777            }
16778            match fallback_strategy {
16779                GoToDefinitionFallback::None => Ok(Navigated::No),
16780                GoToDefinitionFallback::FindAllReferences => {
16781                    match editor.update_in(cx, |editor, window, cx| {
16782                        editor.find_all_references(&FindAllReferences, window, cx)
16783                    })? {
16784                        Some(references) => references.await,
16785                        None => Ok(Navigated::No),
16786                    }
16787                }
16788            }
16789        })
16790    }
16791
16792    pub fn go_to_declaration(
16793        &mut self,
16794        _: &GoToDeclaration,
16795        window: &mut Window,
16796        cx: &mut Context<Self>,
16797    ) -> Task<Result<Navigated>> {
16798        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16799    }
16800
16801    pub fn go_to_declaration_split(
16802        &mut self,
16803        _: &GoToDeclaration,
16804        window: &mut Window,
16805        cx: &mut Context<Self>,
16806    ) -> Task<Result<Navigated>> {
16807        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16808    }
16809
16810    pub fn go_to_implementation(
16811        &mut self,
16812        _: &GoToImplementation,
16813        window: &mut Window,
16814        cx: &mut Context<Self>,
16815    ) -> Task<Result<Navigated>> {
16816        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16817    }
16818
16819    pub fn go_to_implementation_split(
16820        &mut self,
16821        _: &GoToImplementationSplit,
16822        window: &mut Window,
16823        cx: &mut Context<Self>,
16824    ) -> Task<Result<Navigated>> {
16825        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16826    }
16827
16828    pub fn go_to_type_definition(
16829        &mut self,
16830        _: &GoToTypeDefinition,
16831        window: &mut Window,
16832        cx: &mut Context<Self>,
16833    ) -> Task<Result<Navigated>> {
16834        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16835    }
16836
16837    pub fn go_to_definition_split(
16838        &mut self,
16839        _: &GoToDefinitionSplit,
16840        window: &mut Window,
16841        cx: &mut Context<Self>,
16842    ) -> Task<Result<Navigated>> {
16843        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16844    }
16845
16846    pub fn go_to_type_definition_split(
16847        &mut self,
16848        _: &GoToTypeDefinitionSplit,
16849        window: &mut Window,
16850        cx: &mut Context<Self>,
16851    ) -> Task<Result<Navigated>> {
16852        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16853    }
16854
16855    fn go_to_definition_of_kind(
16856        &mut self,
16857        kind: GotoDefinitionKind,
16858        split: bool,
16859        window: &mut Window,
16860        cx: &mut Context<Self>,
16861    ) -> Task<Result<Navigated>> {
16862        let Some(provider) = self.semantics_provider.clone() else {
16863            return Task::ready(Ok(Navigated::No));
16864        };
16865        let head = self
16866            .selections
16867            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
16868            .head();
16869        let buffer = self.buffer.read(cx);
16870        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16871            return Task::ready(Ok(Navigated::No));
16872        };
16873        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16874            return Task::ready(Ok(Navigated::No));
16875        };
16876
16877        cx.spawn_in(window, async move |editor, cx| {
16878            let Some(definitions) = definitions.await? else {
16879                return Ok(Navigated::No);
16880            };
16881            let navigated = editor
16882                .update_in(cx, |editor, window, cx| {
16883                    editor.navigate_to_hover_links(
16884                        Some(kind),
16885                        definitions
16886                            .into_iter()
16887                            .filter(|location| {
16888                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16889                            })
16890                            .map(HoverLink::Text)
16891                            .collect::<Vec<_>>(),
16892                        split,
16893                        window,
16894                        cx,
16895                    )
16896                })?
16897                .await?;
16898            anyhow::Ok(navigated)
16899        })
16900    }
16901
16902    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16903        let selection = self.selections.newest_anchor();
16904        let head = selection.head();
16905        let tail = selection.tail();
16906
16907        let Some((buffer, start_position)) =
16908            self.buffer.read(cx).text_anchor_for_position(head, cx)
16909        else {
16910            return;
16911        };
16912
16913        let end_position = if head != tail {
16914            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16915                return;
16916            };
16917            Some(pos)
16918        } else {
16919            None
16920        };
16921
16922        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16923            let url = if let Some(end_pos) = end_position {
16924                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16925            } else {
16926                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16927            };
16928
16929            if let Some(url) = url {
16930                cx.update(|window, cx| {
16931                    if parse_zed_link(&url, cx).is_some() {
16932                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16933                    } else {
16934                        cx.open_url(&url);
16935                    }
16936                })?;
16937            }
16938
16939            anyhow::Ok(())
16940        });
16941
16942        url_finder.detach();
16943    }
16944
16945    pub fn open_selected_filename(
16946        &mut self,
16947        _: &OpenSelectedFilename,
16948        window: &mut Window,
16949        cx: &mut Context<Self>,
16950    ) {
16951        let Some(workspace) = self.workspace() else {
16952            return;
16953        };
16954
16955        let position = self.selections.newest_anchor().head();
16956
16957        let Some((buffer, buffer_position)) =
16958            self.buffer.read(cx).text_anchor_for_position(position, cx)
16959        else {
16960            return;
16961        };
16962
16963        let project = self.project.clone();
16964
16965        cx.spawn_in(window, async move |_, cx| {
16966            let result = find_file(&buffer, project, buffer_position, cx).await;
16967
16968            if let Some((_, path)) = result {
16969                workspace
16970                    .update_in(cx, |workspace, window, cx| {
16971                        workspace.open_resolved_path(path, window, cx)
16972                    })?
16973                    .await?;
16974            }
16975            anyhow::Ok(())
16976        })
16977        .detach();
16978    }
16979
16980    pub(crate) fn navigate_to_hover_links(
16981        &mut self,
16982        kind: Option<GotoDefinitionKind>,
16983        definitions: Vec<HoverLink>,
16984        split: bool,
16985        window: &mut Window,
16986        cx: &mut Context<Editor>,
16987    ) -> Task<Result<Navigated>> {
16988        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16989        let mut first_url_or_file = None;
16990        let definitions: Vec<_> = definitions
16991            .into_iter()
16992            .filter_map(|def| match def {
16993                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16994                HoverLink::InlayHint(lsp_location, server_id) => {
16995                    let computation =
16996                        self.compute_target_location(lsp_location, server_id, window, cx);
16997                    Some(cx.background_spawn(computation))
16998                }
16999                HoverLink::Url(url) => {
17000                    first_url_or_file = Some(Either::Left(url));
17001                    None
17002                }
17003                HoverLink::File(path) => {
17004                    first_url_or_file = Some(Either::Right(path));
17005                    None
17006                }
17007            })
17008            .collect();
17009
17010        let workspace = self.workspace();
17011
17012        cx.spawn_in(window, async move |editor, cx| {
17013            let locations: Vec<Location> = future::join_all(definitions)
17014                .await
17015                .into_iter()
17016                .filter_map(|location| location.transpose())
17017                .collect::<Result<_>>()
17018                .context("location tasks")?;
17019            let mut locations = cx.update(|_, cx| {
17020                locations
17021                    .into_iter()
17022                    .map(|location| {
17023                        let buffer = location.buffer.read(cx);
17024                        (location.buffer, location.range.to_point(buffer))
17025                    })
17026                    .into_group_map()
17027            })?;
17028            let mut num_locations = 0;
17029            for ranges in locations.values_mut() {
17030                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17031                ranges.dedup();
17032                num_locations += ranges.len();
17033            }
17034
17035            if num_locations > 1 {
17036                let Some(workspace) = workspace else {
17037                    return Ok(Navigated::No);
17038                };
17039
17040                let tab_kind = match kind {
17041                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17042                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17043                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17044                    Some(GotoDefinitionKind::Type) => "Types",
17045                };
17046                let title = editor
17047                    .update_in(cx, |_, _, cx| {
17048                        let target = locations
17049                            .iter()
17050                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17051                            .map(|(buffer, location)| {
17052                                buffer
17053                                    .read(cx)
17054                                    .text_for_range(location.clone())
17055                                    .collect::<String>()
17056                            })
17057                            .filter(|text| !text.contains('\n'))
17058                            .unique()
17059                            .take(3)
17060                            .join(", ");
17061                        if target.is_empty() {
17062                            tab_kind.to_owned()
17063                        } else {
17064                            format!("{tab_kind} for {target}")
17065                        }
17066                    })
17067                    .context("buffer title")?;
17068
17069                let opened = workspace
17070                    .update_in(cx, |workspace, window, cx| {
17071                        Self::open_locations_in_multibuffer(
17072                            workspace,
17073                            locations,
17074                            title,
17075                            split,
17076                            MultibufferSelectionMode::First,
17077                            window,
17078                            cx,
17079                        )
17080                    })
17081                    .is_ok();
17082
17083                anyhow::Ok(Navigated::from_bool(opened))
17084            } else if num_locations == 0 {
17085                // If there is one url or file, open it directly
17086                match first_url_or_file {
17087                    Some(Either::Left(url)) => {
17088                        cx.update(|_, cx| cx.open_url(&url))?;
17089                        Ok(Navigated::Yes)
17090                    }
17091                    Some(Either::Right(path)) => {
17092                        let Some(workspace) = workspace else {
17093                            return Ok(Navigated::No);
17094                        };
17095
17096                        workspace
17097                            .update_in(cx, |workspace, window, cx| {
17098                                workspace.open_resolved_path(path, window, cx)
17099                            })?
17100                            .await?;
17101                        Ok(Navigated::Yes)
17102                    }
17103                    None => Ok(Navigated::No),
17104                }
17105            } else {
17106                let Some(workspace) = workspace else {
17107                    return Ok(Navigated::No);
17108                };
17109
17110                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17111                let target_range = target_ranges.first().unwrap().clone();
17112
17113                editor.update_in(cx, |editor, window, cx| {
17114                    let range = target_range.to_point(target_buffer.read(cx));
17115                    let range = editor.range_for_match(&range);
17116                    let range = collapse_multiline_range(range);
17117
17118                    if !split
17119                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17120                    {
17121                        editor.go_to_singleton_buffer_range(range, window, cx);
17122                    } else {
17123                        let pane = workspace.read(cx).active_pane().clone();
17124                        window.defer(cx, move |window, cx| {
17125                            let target_editor: Entity<Self> =
17126                                workspace.update(cx, |workspace, cx| {
17127                                    let pane = if split {
17128                                        workspace.adjacent_pane(window, cx)
17129                                    } else {
17130                                        workspace.active_pane().clone()
17131                                    };
17132
17133                                    workspace.open_project_item(
17134                                        pane,
17135                                        target_buffer.clone(),
17136                                        true,
17137                                        true,
17138                                        window,
17139                                        cx,
17140                                    )
17141                                });
17142                            target_editor.update(cx, |target_editor, cx| {
17143                                // When selecting a definition in a different buffer, disable the nav history
17144                                // to avoid creating a history entry at the previous cursor location.
17145                                pane.update(cx, |pane, _| pane.disable_history());
17146                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17147                                pane.update(cx, |pane, _| pane.enable_history());
17148                            });
17149                        });
17150                    }
17151                    Navigated::Yes
17152                })
17153            }
17154        })
17155    }
17156
17157    fn compute_target_location(
17158        &self,
17159        lsp_location: lsp::Location,
17160        server_id: LanguageServerId,
17161        window: &mut Window,
17162        cx: &mut Context<Self>,
17163    ) -> Task<anyhow::Result<Option<Location>>> {
17164        let Some(project) = self.project.clone() else {
17165            return Task::ready(Ok(None));
17166        };
17167
17168        cx.spawn_in(window, async move |editor, cx| {
17169            let location_task = editor.update(cx, |_, cx| {
17170                project.update(cx, |project, cx| {
17171                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17172                })
17173            })?;
17174            let location = Some({
17175                let target_buffer_handle = location_task.await.context("open local buffer")?;
17176                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17177                    let target_start = target_buffer
17178                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17179                    let target_end = target_buffer
17180                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17181                    target_buffer.anchor_after(target_start)
17182                        ..target_buffer.anchor_before(target_end)
17183                })?;
17184                Location {
17185                    buffer: target_buffer_handle,
17186                    range,
17187                }
17188            });
17189            Ok(location)
17190        })
17191    }
17192
17193    fn go_to_next_reference(
17194        &mut self,
17195        _: &GoToNextReference,
17196        window: &mut Window,
17197        cx: &mut Context<Self>,
17198    ) {
17199        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17200        if let Some(task) = task {
17201            task.detach();
17202        };
17203    }
17204
17205    fn go_to_prev_reference(
17206        &mut self,
17207        _: &GoToPreviousReference,
17208        window: &mut Window,
17209        cx: &mut Context<Self>,
17210    ) {
17211        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17212        if let Some(task) = task {
17213            task.detach();
17214        };
17215    }
17216
17217    pub fn go_to_reference_before_or_after_position(
17218        &mut self,
17219        direction: Direction,
17220        count: usize,
17221        window: &mut Window,
17222        cx: &mut Context<Self>,
17223    ) -> Option<Task<Result<()>>> {
17224        let selection = self.selections.newest_anchor();
17225        let head = selection.head();
17226
17227        let multi_buffer = self.buffer.read(cx);
17228
17229        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17230        let workspace = self.workspace()?;
17231        let project = workspace.read(cx).project().clone();
17232        let references =
17233            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17234        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17235            let Some(locations) = references.await? else {
17236                return Ok(());
17237            };
17238
17239            if locations.is_empty() {
17240                // totally normal - the cursor may be on something which is not
17241                // a symbol (e.g. a keyword)
17242                log::info!("no references found under cursor");
17243                return Ok(());
17244            }
17245
17246            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17247
17248            let (locations, current_location_index) =
17249                multi_buffer.update(cx, |multi_buffer, cx| {
17250                    let mut locations = locations
17251                        .into_iter()
17252                        .filter_map(|loc| {
17253                            let start = multi_buffer.buffer_anchor_to_anchor(
17254                                &loc.buffer,
17255                                loc.range.start,
17256                                cx,
17257                            )?;
17258                            let end = multi_buffer.buffer_anchor_to_anchor(
17259                                &loc.buffer,
17260                                loc.range.end,
17261                                cx,
17262                            )?;
17263                            Some(start..end)
17264                        })
17265                        .collect::<Vec<_>>();
17266
17267                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17268                    // There is an O(n) implementation, but given this list will be
17269                    // small (usually <100 items), the extra O(log(n)) factor isn't
17270                    // worth the (surprisingly large amount of) extra complexity.
17271                    locations
17272                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17273
17274                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17275
17276                    let current_location_index = locations.iter().position(|loc| {
17277                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17278                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17279                    });
17280
17281                    (locations, current_location_index)
17282                })?;
17283
17284            let Some(current_location_index) = current_location_index else {
17285                // This indicates something has gone wrong, because we already
17286                // handle the "no references" case above
17287                log::error!(
17288                    "failed to find current reference under cursor. Total references: {}",
17289                    locations.len()
17290                );
17291                return Ok(());
17292            };
17293
17294            let destination_location_index = match direction {
17295                Direction::Next => (current_location_index + count) % locations.len(),
17296                Direction::Prev => {
17297                    (current_location_index + locations.len() - count % locations.len())
17298                        % locations.len()
17299                }
17300            };
17301
17302            // TODO(cameron): is this needed?
17303            // the thinking is to avoid "jumping to the current location" (avoid
17304            // polluting "jumplist" in vim terms)
17305            if current_location_index == destination_location_index {
17306                return Ok(());
17307            }
17308
17309            let Range { start, end } = locations[destination_location_index];
17310
17311            editor.update_in(cx, |editor, window, cx| {
17312                let effects = SelectionEffects::default();
17313
17314                editor.unfold_ranges(&[start..end], false, false, cx);
17315                editor.change_selections(effects, window, cx, |s| {
17316                    s.select_ranges([start..start]);
17317                });
17318            })?;
17319
17320            Ok(())
17321        }))
17322    }
17323
17324    pub fn find_all_references(
17325        &mut self,
17326        _: &FindAllReferences,
17327        window: &mut Window,
17328        cx: &mut Context<Self>,
17329    ) -> Option<Task<Result<Navigated>>> {
17330        let selection = self
17331            .selections
17332            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17333        let multi_buffer = self.buffer.read(cx);
17334        let head = selection.head();
17335
17336        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17337        let head_anchor = multi_buffer_snapshot.anchor_at(
17338            head,
17339            if head < selection.tail() {
17340                Bias::Right
17341            } else {
17342                Bias::Left
17343            },
17344        );
17345
17346        match self
17347            .find_all_references_task_sources
17348            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17349        {
17350            Ok(_) => {
17351                log::info!(
17352                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17353                );
17354                return None;
17355            }
17356            Err(i) => {
17357                self.find_all_references_task_sources.insert(i, head_anchor);
17358            }
17359        }
17360
17361        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17362        let workspace = self.workspace()?;
17363        let project = workspace.read(cx).project().clone();
17364        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17365        Some(cx.spawn_in(window, async move |editor, cx| {
17366            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17367                if let Ok(i) = editor
17368                    .find_all_references_task_sources
17369                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17370                {
17371                    editor.find_all_references_task_sources.remove(i);
17372                }
17373            });
17374
17375            let Some(locations) = references.await? else {
17376                return anyhow::Ok(Navigated::No);
17377            };
17378            let mut locations = cx.update(|_, cx| {
17379                locations
17380                    .into_iter()
17381                    .map(|location| {
17382                        let buffer = location.buffer.read(cx);
17383                        (location.buffer, location.range.to_point(buffer))
17384                    })
17385                    .into_group_map()
17386            })?;
17387            if locations.is_empty() {
17388                return anyhow::Ok(Navigated::No);
17389            }
17390            for ranges in locations.values_mut() {
17391                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17392                ranges.dedup();
17393            }
17394
17395            workspace.update_in(cx, |workspace, window, cx| {
17396                let target = locations
17397                    .iter()
17398                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17399                    .map(|(buffer, location)| {
17400                        buffer
17401                            .read(cx)
17402                            .text_for_range(location.clone())
17403                            .collect::<String>()
17404                    })
17405                    .filter(|text| !text.contains('\n'))
17406                    .unique()
17407                    .take(3)
17408                    .join(", ");
17409                let title = if target.is_empty() {
17410                    "References".to_owned()
17411                } else {
17412                    format!("References to {target}")
17413                };
17414                Self::open_locations_in_multibuffer(
17415                    workspace,
17416                    locations,
17417                    title,
17418                    false,
17419                    MultibufferSelectionMode::First,
17420                    window,
17421                    cx,
17422                );
17423                Navigated::Yes
17424            })
17425        }))
17426    }
17427
17428    /// Opens a multibuffer with the given project locations in it
17429    pub fn open_locations_in_multibuffer(
17430        workspace: &mut Workspace,
17431        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17432        title: String,
17433        split: bool,
17434        multibuffer_selection_mode: MultibufferSelectionMode,
17435        window: &mut Window,
17436        cx: &mut Context<Workspace>,
17437    ) {
17438        if locations.is_empty() {
17439            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17440            return;
17441        }
17442
17443        let capability = workspace.project().read(cx).capability();
17444        let mut ranges = <Vec<Range<Anchor>>>::new();
17445
17446        // a key to find existing multibuffer editors with the same set of locations
17447        // to prevent us from opening more and more multibuffer tabs for searches and the like
17448        let mut key = (title.clone(), vec![]);
17449        let excerpt_buffer = cx.new(|cx| {
17450            let key = &mut key.1;
17451            let mut multibuffer = MultiBuffer::new(capability);
17452            for (buffer, mut ranges_for_buffer) in locations {
17453                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17454                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17455                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17456                    PathKey::for_buffer(&buffer, cx),
17457                    buffer.clone(),
17458                    ranges_for_buffer,
17459                    multibuffer_context_lines(cx),
17460                    cx,
17461                );
17462                ranges.extend(new_ranges)
17463            }
17464
17465            multibuffer.with_title(title)
17466        });
17467        let existing = workspace.active_pane().update(cx, |pane, cx| {
17468            pane.items()
17469                .filter_map(|item| item.downcast::<Editor>())
17470                .find(|editor| {
17471                    editor
17472                        .read(cx)
17473                        .lookup_key
17474                        .as_ref()
17475                        .and_then(|it| {
17476                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17477                        })
17478                        .is_some_and(|it| *it == key)
17479                })
17480        });
17481        let editor = existing.unwrap_or_else(|| {
17482            cx.new(|cx| {
17483                let mut editor = Editor::for_multibuffer(
17484                    excerpt_buffer,
17485                    Some(workspace.project().clone()),
17486                    window,
17487                    cx,
17488                );
17489                editor.lookup_key = Some(Box::new(key));
17490                editor
17491            })
17492        });
17493        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17494            MultibufferSelectionMode::First => {
17495                if let Some(first_range) = ranges.first() {
17496                    editor.change_selections(
17497                        SelectionEffects::no_scroll(),
17498                        window,
17499                        cx,
17500                        |selections| {
17501                            selections.clear_disjoint();
17502                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17503                        },
17504                    );
17505                }
17506                editor.highlight_background::<Self>(
17507                    &ranges,
17508                    |theme| theme.colors().editor_highlighted_line_background,
17509                    cx,
17510                );
17511            }
17512            MultibufferSelectionMode::All => {
17513                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17514                    selections.clear_disjoint();
17515                    selections.select_anchor_ranges(ranges);
17516                });
17517            }
17518        });
17519
17520        let item = Box::new(editor);
17521        let item_id = item.item_id();
17522
17523        if split {
17524            let pane = workspace.adjacent_pane(window, cx);
17525            workspace.add_item(pane, item, None, true, true, window, cx);
17526        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17527            let (preview_item_id, preview_item_idx) =
17528                workspace.active_pane().read_with(cx, |pane, _| {
17529                    (pane.preview_item_id(), pane.preview_item_idx())
17530                });
17531
17532            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17533
17534            if let Some(preview_item_id) = preview_item_id {
17535                workspace.active_pane().update(cx, |pane, cx| {
17536                    pane.remove_item(preview_item_id, false, false, window, cx);
17537                });
17538            }
17539        } else {
17540            workspace.add_item_to_active_pane(item, None, true, window, cx);
17541        }
17542        workspace.active_pane().update(cx, |pane, cx| {
17543            pane.set_preview_item_id(Some(item_id), cx);
17544        });
17545    }
17546
17547    pub fn rename(
17548        &mut self,
17549        _: &Rename,
17550        window: &mut Window,
17551        cx: &mut Context<Self>,
17552    ) -> Option<Task<Result<()>>> {
17553        use language::ToOffset as _;
17554
17555        let provider = self.semantics_provider.clone()?;
17556        let selection = self.selections.newest_anchor().clone();
17557        let (cursor_buffer, cursor_buffer_position) = self
17558            .buffer
17559            .read(cx)
17560            .text_anchor_for_position(selection.head(), cx)?;
17561        let (tail_buffer, cursor_buffer_position_end) = self
17562            .buffer
17563            .read(cx)
17564            .text_anchor_for_position(selection.tail(), cx)?;
17565        if tail_buffer != cursor_buffer {
17566            return None;
17567        }
17568
17569        let snapshot = cursor_buffer.read(cx).snapshot();
17570        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17571        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17572        let prepare_rename = provider
17573            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17574            .unwrap_or_else(|| Task::ready(Ok(None)));
17575        drop(snapshot);
17576
17577        Some(cx.spawn_in(window, async move |this, cx| {
17578            let rename_range = if let Some(range) = prepare_rename.await? {
17579                Some(range)
17580            } else {
17581                this.update(cx, |this, cx| {
17582                    let buffer = this.buffer.read(cx).snapshot(cx);
17583                    let mut buffer_highlights = this
17584                        .document_highlights_for_position(selection.head(), &buffer)
17585                        .filter(|highlight| {
17586                            highlight.start.excerpt_id == selection.head().excerpt_id
17587                                && highlight.end.excerpt_id == selection.head().excerpt_id
17588                        });
17589                    buffer_highlights
17590                        .next()
17591                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17592                })?
17593            };
17594            if let Some(rename_range) = rename_range {
17595                this.update_in(cx, |this, window, cx| {
17596                    let snapshot = cursor_buffer.read(cx).snapshot();
17597                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17598                    let cursor_offset_in_rename_range =
17599                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17600                    let cursor_offset_in_rename_range_end =
17601                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17602
17603                    this.take_rename(false, window, cx);
17604                    let buffer = this.buffer.read(cx).read(cx);
17605                    let cursor_offset = selection.head().to_offset(&buffer);
17606                    let rename_start =
17607                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17608                    let rename_end = rename_start + rename_buffer_range.len();
17609                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17610                    let mut old_highlight_id = None;
17611                    let old_name: Arc<str> = buffer
17612                        .chunks(rename_start..rename_end, true)
17613                        .map(|chunk| {
17614                            if old_highlight_id.is_none() {
17615                                old_highlight_id = chunk.syntax_highlight_id;
17616                            }
17617                            chunk.text
17618                        })
17619                        .collect::<String>()
17620                        .into();
17621
17622                    drop(buffer);
17623
17624                    // Position the selection in the rename editor so that it matches the current selection.
17625                    this.show_local_selections = false;
17626                    let rename_editor = cx.new(|cx| {
17627                        let mut editor = Editor::single_line(window, cx);
17628                        editor.buffer.update(cx, |buffer, cx| {
17629                            buffer.edit(
17630                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
17631                                None,
17632                                cx,
17633                            )
17634                        });
17635                        let cursor_offset_in_rename_range =
17636                            MultiBufferOffset(cursor_offset_in_rename_range);
17637                        let cursor_offset_in_rename_range_end =
17638                            MultiBufferOffset(cursor_offset_in_rename_range_end);
17639                        let rename_selection_range = match cursor_offset_in_rename_range
17640                            .cmp(&cursor_offset_in_rename_range_end)
17641                        {
17642                            Ordering::Equal => {
17643                                editor.select_all(&SelectAll, window, cx);
17644                                return editor;
17645                            }
17646                            Ordering::Less => {
17647                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17648                            }
17649                            Ordering::Greater => {
17650                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17651                            }
17652                        };
17653                        if rename_selection_range.end.0 > old_name.len() {
17654                            editor.select_all(&SelectAll, window, cx);
17655                        } else {
17656                            editor.change_selections(Default::default(), window, cx, |s| {
17657                                s.select_ranges([rename_selection_range]);
17658                            });
17659                        }
17660                        editor
17661                    });
17662                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17663                        if e == &EditorEvent::Focused {
17664                            cx.emit(EditorEvent::FocusedIn)
17665                        }
17666                    })
17667                    .detach();
17668
17669                    let write_highlights =
17670                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17671                    let read_highlights =
17672                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17673                    let ranges = write_highlights
17674                        .iter()
17675                        .flat_map(|(_, ranges)| ranges.iter())
17676                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17677                        .cloned()
17678                        .collect();
17679
17680                    this.highlight_text::<Rename>(
17681                        ranges,
17682                        HighlightStyle {
17683                            fade_out: Some(0.6),
17684                            ..Default::default()
17685                        },
17686                        cx,
17687                    );
17688                    let rename_focus_handle = rename_editor.focus_handle(cx);
17689                    window.focus(&rename_focus_handle);
17690                    let block_id = this.insert_blocks(
17691                        [BlockProperties {
17692                            style: BlockStyle::Flex,
17693                            placement: BlockPlacement::Below(range.start),
17694                            height: Some(1),
17695                            render: Arc::new({
17696                                let rename_editor = rename_editor.clone();
17697                                move |cx: &mut BlockContext| {
17698                                    let mut text_style = cx.editor_style.text.clone();
17699                                    if let Some(highlight_style) = old_highlight_id
17700                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17701                                    {
17702                                        text_style = text_style.highlight(highlight_style);
17703                                    }
17704                                    div()
17705                                        .block_mouse_except_scroll()
17706                                        .pl(cx.anchor_x)
17707                                        .child(EditorElement::new(
17708                                            &rename_editor,
17709                                            EditorStyle {
17710                                                background: cx.theme().system().transparent,
17711                                                local_player: cx.editor_style.local_player,
17712                                                text: text_style,
17713                                                scrollbar_width: cx.editor_style.scrollbar_width,
17714                                                syntax: cx.editor_style.syntax.clone(),
17715                                                status: cx.editor_style.status.clone(),
17716                                                inlay_hints_style: HighlightStyle {
17717                                                    font_weight: Some(FontWeight::BOLD),
17718                                                    ..make_inlay_hints_style(cx.app)
17719                                                },
17720                                                edit_prediction_styles: make_suggestion_styles(
17721                                                    cx.app,
17722                                                ),
17723                                                ..EditorStyle::default()
17724                                            },
17725                                        ))
17726                                        .into_any_element()
17727                                }
17728                            }),
17729                            priority: 0,
17730                        }],
17731                        Some(Autoscroll::fit()),
17732                        cx,
17733                    )[0];
17734                    this.pending_rename = Some(RenameState {
17735                        range,
17736                        old_name,
17737                        editor: rename_editor,
17738                        block_id,
17739                    });
17740                })?;
17741            }
17742
17743            Ok(())
17744        }))
17745    }
17746
17747    pub fn confirm_rename(
17748        &mut self,
17749        _: &ConfirmRename,
17750        window: &mut Window,
17751        cx: &mut Context<Self>,
17752    ) -> Option<Task<Result<()>>> {
17753        let rename = self.take_rename(false, window, cx)?;
17754        let workspace = self.workspace()?.downgrade();
17755        let (buffer, start) = self
17756            .buffer
17757            .read(cx)
17758            .text_anchor_for_position(rename.range.start, cx)?;
17759        let (end_buffer, _) = self
17760            .buffer
17761            .read(cx)
17762            .text_anchor_for_position(rename.range.end, cx)?;
17763        if buffer != end_buffer {
17764            return None;
17765        }
17766
17767        let old_name = rename.old_name;
17768        let new_name = rename.editor.read(cx).text(cx);
17769
17770        let rename = self.semantics_provider.as_ref()?.perform_rename(
17771            &buffer,
17772            start,
17773            new_name.clone(),
17774            cx,
17775        )?;
17776
17777        Some(cx.spawn_in(window, async move |editor, cx| {
17778            let project_transaction = rename.await?;
17779            Self::open_project_transaction(
17780                &editor,
17781                workspace,
17782                project_transaction,
17783                format!("Rename: {}{}", old_name, new_name),
17784                cx,
17785            )
17786            .await?;
17787
17788            editor.update(cx, |editor, cx| {
17789                editor.refresh_document_highlights(cx);
17790            })?;
17791            Ok(())
17792        }))
17793    }
17794
17795    fn take_rename(
17796        &mut self,
17797        moving_cursor: bool,
17798        window: &mut Window,
17799        cx: &mut Context<Self>,
17800    ) -> Option<RenameState> {
17801        let rename = self.pending_rename.take()?;
17802        if rename.editor.focus_handle(cx).is_focused(window) {
17803            window.focus(&self.focus_handle);
17804        }
17805
17806        self.remove_blocks(
17807            [rename.block_id].into_iter().collect(),
17808            Some(Autoscroll::fit()),
17809            cx,
17810        );
17811        self.clear_highlights::<Rename>(cx);
17812        self.show_local_selections = true;
17813
17814        if moving_cursor {
17815            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17816                editor
17817                    .selections
17818                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
17819                    .head()
17820            });
17821
17822            // Update the selection to match the position of the selection inside
17823            // the rename editor.
17824            let snapshot = self.buffer.read(cx).read(cx);
17825            let rename_range = rename.range.to_offset(&snapshot);
17826            let cursor_in_editor = snapshot
17827                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17828                .min(rename_range.end);
17829            drop(snapshot);
17830
17831            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17832                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17833            });
17834        } else {
17835            self.refresh_document_highlights(cx);
17836        }
17837
17838        Some(rename)
17839    }
17840
17841    pub fn pending_rename(&self) -> Option<&RenameState> {
17842        self.pending_rename.as_ref()
17843    }
17844
17845    fn format(
17846        &mut self,
17847        _: &Format,
17848        window: &mut Window,
17849        cx: &mut Context<Self>,
17850    ) -> Option<Task<Result<()>>> {
17851        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17852
17853        let project = match &self.project {
17854            Some(project) => project.clone(),
17855            None => return None,
17856        };
17857
17858        Some(self.perform_format(
17859            project,
17860            FormatTrigger::Manual,
17861            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17862            window,
17863            cx,
17864        ))
17865    }
17866
17867    fn format_selections(
17868        &mut self,
17869        _: &FormatSelections,
17870        window: &mut Window,
17871        cx: &mut Context<Self>,
17872    ) -> Option<Task<Result<()>>> {
17873        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17874
17875        let project = match &self.project {
17876            Some(project) => project.clone(),
17877            None => return None,
17878        };
17879
17880        let ranges = self
17881            .selections
17882            .all_adjusted(&self.display_snapshot(cx))
17883            .into_iter()
17884            .map(|selection| selection.range())
17885            .collect_vec();
17886
17887        Some(self.perform_format(
17888            project,
17889            FormatTrigger::Manual,
17890            FormatTarget::Ranges(ranges),
17891            window,
17892            cx,
17893        ))
17894    }
17895
17896    fn perform_format(
17897        &mut self,
17898        project: Entity<Project>,
17899        trigger: FormatTrigger,
17900        target: FormatTarget,
17901        window: &mut Window,
17902        cx: &mut Context<Self>,
17903    ) -> Task<Result<()>> {
17904        let buffer = self.buffer.clone();
17905        let (buffers, target) = match target {
17906            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17907            FormatTarget::Ranges(selection_ranges) => {
17908                let multi_buffer = buffer.read(cx);
17909                let snapshot = multi_buffer.read(cx);
17910                let mut buffers = HashSet::default();
17911                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17912                    BTreeMap::new();
17913                for selection_range in selection_ranges {
17914                    for (buffer, buffer_range, _) in
17915                        snapshot.range_to_buffer_ranges(selection_range)
17916                    {
17917                        let buffer_id = buffer.remote_id();
17918                        let start = buffer.anchor_before(buffer_range.start);
17919                        let end = buffer.anchor_after(buffer_range.end);
17920                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17921                        buffer_id_to_ranges
17922                            .entry(buffer_id)
17923                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17924                            .or_insert_with(|| vec![start..end]);
17925                    }
17926                }
17927                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17928            }
17929        };
17930
17931        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17932        let selections_prev = transaction_id_prev
17933            .and_then(|transaction_id_prev| {
17934                // default to selections as they were after the last edit, if we have them,
17935                // instead of how they are now.
17936                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17937                // will take you back to where you made the last edit, instead of staying where you scrolled
17938                self.selection_history
17939                    .transaction(transaction_id_prev)
17940                    .map(|t| t.0.clone())
17941            })
17942            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17943
17944        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17945        let format = project.update(cx, |project, cx| {
17946            project.format(buffers, target, true, trigger, cx)
17947        });
17948
17949        cx.spawn_in(window, async move |editor, cx| {
17950            let transaction = futures::select_biased! {
17951                transaction = format.log_err().fuse() => transaction,
17952                () = timeout => {
17953                    log::warn!("timed out waiting for formatting");
17954                    None
17955                }
17956            };
17957
17958            buffer
17959                .update(cx, |buffer, cx| {
17960                    if let Some(transaction) = transaction
17961                        && !buffer.is_singleton()
17962                    {
17963                        buffer.push_transaction(&transaction.0, cx);
17964                    }
17965                    cx.notify();
17966                })
17967                .ok();
17968
17969            if let Some(transaction_id_now) =
17970                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17971            {
17972                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17973                if has_new_transaction {
17974                    _ = editor.update(cx, |editor, _| {
17975                        editor
17976                            .selection_history
17977                            .insert_transaction(transaction_id_now, selections_prev);
17978                    });
17979                }
17980            }
17981
17982            Ok(())
17983        })
17984    }
17985
17986    fn organize_imports(
17987        &mut self,
17988        _: &OrganizeImports,
17989        window: &mut Window,
17990        cx: &mut Context<Self>,
17991    ) -> Option<Task<Result<()>>> {
17992        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17993        let project = match &self.project {
17994            Some(project) => project.clone(),
17995            None => return None,
17996        };
17997        Some(self.perform_code_action_kind(
17998            project,
17999            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18000            window,
18001            cx,
18002        ))
18003    }
18004
18005    fn perform_code_action_kind(
18006        &mut self,
18007        project: Entity<Project>,
18008        kind: CodeActionKind,
18009        window: &mut Window,
18010        cx: &mut Context<Self>,
18011    ) -> Task<Result<()>> {
18012        let buffer = self.buffer.clone();
18013        let buffers = buffer.read(cx).all_buffers();
18014        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18015        let apply_action = project.update(cx, |project, cx| {
18016            project.apply_code_action_kind(buffers, kind, true, cx)
18017        });
18018        cx.spawn_in(window, async move |_, cx| {
18019            let transaction = futures::select_biased! {
18020                () = timeout => {
18021                    log::warn!("timed out waiting for executing code action");
18022                    None
18023                }
18024                transaction = apply_action.log_err().fuse() => transaction,
18025            };
18026            buffer
18027                .update(cx, |buffer, cx| {
18028                    // check if we need this
18029                    if let Some(transaction) = transaction
18030                        && !buffer.is_singleton()
18031                    {
18032                        buffer.push_transaction(&transaction.0, cx);
18033                    }
18034                    cx.notify();
18035                })
18036                .ok();
18037            Ok(())
18038        })
18039    }
18040
18041    pub fn restart_language_server(
18042        &mut self,
18043        _: &RestartLanguageServer,
18044        _: &mut Window,
18045        cx: &mut Context<Self>,
18046    ) {
18047        if let Some(project) = self.project.clone() {
18048            self.buffer.update(cx, |multi_buffer, cx| {
18049                project.update(cx, |project, cx| {
18050                    project.restart_language_servers_for_buffers(
18051                        multi_buffer.all_buffers().into_iter().collect(),
18052                        HashSet::default(),
18053                        cx,
18054                    );
18055                });
18056            })
18057        }
18058    }
18059
18060    pub fn stop_language_server(
18061        &mut self,
18062        _: &StopLanguageServer,
18063        _: &mut Window,
18064        cx: &mut Context<Self>,
18065    ) {
18066        if let Some(project) = self.project.clone() {
18067            self.buffer.update(cx, |multi_buffer, cx| {
18068                project.update(cx, |project, cx| {
18069                    project.stop_language_servers_for_buffers(
18070                        multi_buffer.all_buffers().into_iter().collect(),
18071                        HashSet::default(),
18072                        cx,
18073                    );
18074                });
18075            });
18076            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18077        }
18078    }
18079
18080    fn cancel_language_server_work(
18081        workspace: &mut Workspace,
18082        _: &actions::CancelLanguageServerWork,
18083        _: &mut Window,
18084        cx: &mut Context<Workspace>,
18085    ) {
18086        let project = workspace.project();
18087        let buffers = workspace
18088            .active_item(cx)
18089            .and_then(|item| item.act_as::<Editor>(cx))
18090            .map_or(HashSet::default(), |editor| {
18091                editor.read(cx).buffer.read(cx).all_buffers()
18092            });
18093        project.update(cx, |project, cx| {
18094            project.cancel_language_server_work_for_buffers(buffers, cx);
18095        });
18096    }
18097
18098    fn show_character_palette(
18099        &mut self,
18100        _: &ShowCharacterPalette,
18101        window: &mut Window,
18102        _: &mut Context<Self>,
18103    ) {
18104        window.show_character_palette();
18105    }
18106
18107    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18108        if !self.diagnostics_enabled() {
18109            return;
18110        }
18111
18112        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18113            let buffer = self.buffer.read(cx).snapshot(cx);
18114            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18115            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18116            let is_valid = buffer
18117                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18118                .any(|entry| {
18119                    entry.diagnostic.is_primary
18120                        && !entry.range.is_empty()
18121                        && entry.range.start == primary_range_start
18122                        && entry.diagnostic.message == active_diagnostics.active_message
18123                });
18124
18125            if !is_valid {
18126                self.dismiss_diagnostics(cx);
18127            }
18128        }
18129    }
18130
18131    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18132        match &self.active_diagnostics {
18133            ActiveDiagnostic::Group(group) => Some(group),
18134            _ => None,
18135        }
18136    }
18137
18138    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18139        if !self.diagnostics_enabled() {
18140            return;
18141        }
18142        self.dismiss_diagnostics(cx);
18143        self.active_diagnostics = ActiveDiagnostic::All;
18144    }
18145
18146    fn activate_diagnostics(
18147        &mut self,
18148        buffer_id: BufferId,
18149        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18150        window: &mut Window,
18151        cx: &mut Context<Self>,
18152    ) {
18153        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18154            return;
18155        }
18156        self.dismiss_diagnostics(cx);
18157        let snapshot = self.snapshot(window, cx);
18158        let buffer = self.buffer.read(cx).snapshot(cx);
18159        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18160            return;
18161        };
18162
18163        let diagnostic_group = buffer
18164            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18165            .collect::<Vec<_>>();
18166
18167        let language_registry = self
18168            .project()
18169            .map(|project| project.read(cx).languages().clone());
18170
18171        let blocks = renderer.render_group(
18172            diagnostic_group,
18173            buffer_id,
18174            snapshot,
18175            cx.weak_entity(),
18176            language_registry,
18177            cx,
18178        );
18179
18180        let blocks = self.display_map.update(cx, |display_map, cx| {
18181            display_map.insert_blocks(blocks, cx).into_iter().collect()
18182        });
18183        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18184            active_range: buffer.anchor_before(diagnostic.range.start)
18185                ..buffer.anchor_after(diagnostic.range.end),
18186            active_message: diagnostic.diagnostic.message.clone(),
18187            group_id: diagnostic.diagnostic.group_id,
18188            blocks,
18189        });
18190        cx.notify();
18191    }
18192
18193    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18194        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18195            return;
18196        };
18197
18198        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18199        if let ActiveDiagnostic::Group(group) = prev {
18200            self.display_map.update(cx, |display_map, cx| {
18201                display_map.remove_blocks(group.blocks, cx);
18202            });
18203            cx.notify();
18204        }
18205    }
18206
18207    /// Disable inline diagnostics rendering for this editor.
18208    pub fn disable_inline_diagnostics(&mut self) {
18209        self.inline_diagnostics_enabled = false;
18210        self.inline_diagnostics_update = Task::ready(());
18211        self.inline_diagnostics.clear();
18212    }
18213
18214    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18215        self.diagnostics_enabled = false;
18216        self.dismiss_diagnostics(cx);
18217        self.inline_diagnostics_update = Task::ready(());
18218        self.inline_diagnostics.clear();
18219    }
18220
18221    pub fn disable_word_completions(&mut self) {
18222        self.word_completions_enabled = false;
18223    }
18224
18225    pub fn diagnostics_enabled(&self) -> bool {
18226        self.diagnostics_enabled && self.mode.is_full()
18227    }
18228
18229    pub fn inline_diagnostics_enabled(&self) -> bool {
18230        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18231    }
18232
18233    pub fn show_inline_diagnostics(&self) -> bool {
18234        self.show_inline_diagnostics
18235    }
18236
18237    pub fn toggle_inline_diagnostics(
18238        &mut self,
18239        _: &ToggleInlineDiagnostics,
18240        window: &mut Window,
18241        cx: &mut Context<Editor>,
18242    ) {
18243        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18244        self.refresh_inline_diagnostics(false, window, cx);
18245    }
18246
18247    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18248        self.diagnostics_max_severity = severity;
18249        self.display_map.update(cx, |display_map, _| {
18250            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18251        });
18252    }
18253
18254    pub fn toggle_diagnostics(
18255        &mut self,
18256        _: &ToggleDiagnostics,
18257        window: &mut Window,
18258        cx: &mut Context<Editor>,
18259    ) {
18260        if !self.diagnostics_enabled() {
18261            return;
18262        }
18263
18264        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18265            EditorSettings::get_global(cx)
18266                .diagnostics_max_severity
18267                .filter(|severity| severity != &DiagnosticSeverity::Off)
18268                .unwrap_or(DiagnosticSeverity::Hint)
18269        } else {
18270            DiagnosticSeverity::Off
18271        };
18272        self.set_max_diagnostics_severity(new_severity, cx);
18273        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18274            self.active_diagnostics = ActiveDiagnostic::None;
18275            self.inline_diagnostics_update = Task::ready(());
18276            self.inline_diagnostics.clear();
18277        } else {
18278            self.refresh_inline_diagnostics(false, window, cx);
18279        }
18280
18281        cx.notify();
18282    }
18283
18284    pub fn toggle_minimap(
18285        &mut self,
18286        _: &ToggleMinimap,
18287        window: &mut Window,
18288        cx: &mut Context<Editor>,
18289    ) {
18290        if self.supports_minimap(cx) {
18291            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18292        }
18293    }
18294
18295    fn refresh_inline_diagnostics(
18296        &mut self,
18297        debounce: bool,
18298        window: &mut Window,
18299        cx: &mut Context<Self>,
18300    ) {
18301        let max_severity = ProjectSettings::get_global(cx)
18302            .diagnostics
18303            .inline
18304            .max_severity
18305            .unwrap_or(self.diagnostics_max_severity);
18306
18307        if !self.inline_diagnostics_enabled()
18308            || !self.diagnostics_enabled()
18309            || !self.show_inline_diagnostics
18310            || max_severity == DiagnosticSeverity::Off
18311        {
18312            self.inline_diagnostics_update = Task::ready(());
18313            self.inline_diagnostics.clear();
18314            return;
18315        }
18316
18317        let debounce_ms = ProjectSettings::get_global(cx)
18318            .diagnostics
18319            .inline
18320            .update_debounce_ms;
18321        let debounce = if debounce && debounce_ms > 0 {
18322            Some(Duration::from_millis(debounce_ms))
18323        } else {
18324            None
18325        };
18326        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18327            if let Some(debounce) = debounce {
18328                cx.background_executor().timer(debounce).await;
18329            }
18330            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18331                editor
18332                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18333                    .ok()
18334            }) else {
18335                return;
18336            };
18337
18338            let new_inline_diagnostics = cx
18339                .background_spawn(async move {
18340                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18341                    for diagnostic_entry in
18342                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18343                    {
18344                        let message = diagnostic_entry
18345                            .diagnostic
18346                            .message
18347                            .split_once('\n')
18348                            .map(|(line, _)| line)
18349                            .map(SharedString::new)
18350                            .unwrap_or_else(|| {
18351                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18352                            });
18353                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18354                        let (Ok(i) | Err(i)) = inline_diagnostics
18355                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18356                        inline_diagnostics.insert(
18357                            i,
18358                            (
18359                                start_anchor,
18360                                InlineDiagnostic {
18361                                    message,
18362                                    group_id: diagnostic_entry.diagnostic.group_id,
18363                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18364                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18365                                    severity: diagnostic_entry.diagnostic.severity,
18366                                },
18367                            ),
18368                        );
18369                    }
18370                    inline_diagnostics
18371                })
18372                .await;
18373
18374            editor
18375                .update(cx, |editor, cx| {
18376                    editor.inline_diagnostics = new_inline_diagnostics;
18377                    cx.notify();
18378                })
18379                .ok();
18380        });
18381    }
18382
18383    fn pull_diagnostics(
18384        &mut self,
18385        buffer_id: Option<BufferId>,
18386        window: &Window,
18387        cx: &mut Context<Self>,
18388    ) -> Option<()> {
18389        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18390            return None;
18391        }
18392        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18393            .diagnostics
18394            .lsp_pull_diagnostics;
18395        if !pull_diagnostics_settings.enabled {
18396            return None;
18397        }
18398        let project = self.project()?.downgrade();
18399        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18400        let mut buffers = self.buffer.read(cx).all_buffers();
18401        buffers.retain(|buffer| {
18402            let buffer_id_to_retain = buffer.read(cx).remote_id();
18403            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18404                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18405        });
18406        if buffers.is_empty() {
18407            self.pull_diagnostics_task = Task::ready(());
18408            return None;
18409        }
18410
18411        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18412            cx.background_executor().timer(debounce).await;
18413
18414            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18415                buffers
18416                    .into_iter()
18417                    .filter_map(|buffer| {
18418                        project
18419                            .update(cx, |project, cx| {
18420                                project.lsp_store().update(cx, |lsp_store, cx| {
18421                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18422                                })
18423                            })
18424                            .ok()
18425                    })
18426                    .collect::<FuturesUnordered<_>>()
18427            }) else {
18428                return;
18429            };
18430
18431            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18432                match pull_task {
18433                    Ok(()) => {
18434                        if editor
18435                            .update_in(cx, |editor, window, cx| {
18436                                editor.update_diagnostics_state(window, cx);
18437                            })
18438                            .is_err()
18439                        {
18440                            return;
18441                        }
18442                    }
18443                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18444                }
18445            }
18446        });
18447
18448        Some(())
18449    }
18450
18451    pub fn set_selections_from_remote(
18452        &mut self,
18453        selections: Vec<Selection<Anchor>>,
18454        pending_selection: Option<Selection<Anchor>>,
18455        window: &mut Window,
18456        cx: &mut Context<Self>,
18457    ) {
18458        let old_cursor_position = self.selections.newest_anchor().head();
18459        self.selections
18460            .change_with(&self.display_snapshot(cx), |s| {
18461                s.select_anchors(selections);
18462                if let Some(pending_selection) = pending_selection {
18463                    s.set_pending(pending_selection, SelectMode::Character);
18464                } else {
18465                    s.clear_pending();
18466                }
18467            });
18468        self.selections_did_change(
18469            false,
18470            &old_cursor_position,
18471            SelectionEffects::default(),
18472            window,
18473            cx,
18474        );
18475    }
18476
18477    pub fn transact(
18478        &mut self,
18479        window: &mut Window,
18480        cx: &mut Context<Self>,
18481        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18482    ) -> Option<TransactionId> {
18483        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18484            this.start_transaction_at(Instant::now(), window, cx);
18485            update(this, window, cx);
18486            this.end_transaction_at(Instant::now(), cx)
18487        })
18488    }
18489
18490    pub fn start_transaction_at(
18491        &mut self,
18492        now: Instant,
18493        window: &mut Window,
18494        cx: &mut Context<Self>,
18495    ) -> Option<TransactionId> {
18496        self.end_selection(window, cx);
18497        if let Some(tx_id) = self
18498            .buffer
18499            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18500        {
18501            self.selection_history
18502                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18503            cx.emit(EditorEvent::TransactionBegun {
18504                transaction_id: tx_id,
18505            });
18506            Some(tx_id)
18507        } else {
18508            None
18509        }
18510    }
18511
18512    pub fn end_transaction_at(
18513        &mut self,
18514        now: Instant,
18515        cx: &mut Context<Self>,
18516    ) -> Option<TransactionId> {
18517        if let Some(transaction_id) = self
18518            .buffer
18519            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18520        {
18521            if let Some((_, end_selections)) =
18522                self.selection_history.transaction_mut(transaction_id)
18523            {
18524                *end_selections = Some(self.selections.disjoint_anchors_arc());
18525            } else {
18526                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18527            }
18528
18529            cx.emit(EditorEvent::Edited { transaction_id });
18530            Some(transaction_id)
18531        } else {
18532            None
18533        }
18534    }
18535
18536    pub fn modify_transaction_selection_history(
18537        &mut self,
18538        transaction_id: TransactionId,
18539        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18540    ) -> bool {
18541        self.selection_history
18542            .transaction_mut(transaction_id)
18543            .map(modify)
18544            .is_some()
18545    }
18546
18547    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18548        if self.selection_mark_mode {
18549            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18550                s.move_with(|_, sel| {
18551                    sel.collapse_to(sel.head(), SelectionGoal::None);
18552                });
18553            })
18554        }
18555        self.selection_mark_mode = true;
18556        cx.notify();
18557    }
18558
18559    pub fn swap_selection_ends(
18560        &mut self,
18561        _: &actions::SwapSelectionEnds,
18562        window: &mut Window,
18563        cx: &mut Context<Self>,
18564    ) {
18565        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18566            s.move_with(|_, sel| {
18567                if sel.start != sel.end {
18568                    sel.reversed = !sel.reversed
18569                }
18570            });
18571        });
18572        self.request_autoscroll(Autoscroll::newest(), cx);
18573        cx.notify();
18574    }
18575
18576    pub fn toggle_focus(
18577        workspace: &mut Workspace,
18578        _: &actions::ToggleFocus,
18579        window: &mut Window,
18580        cx: &mut Context<Workspace>,
18581    ) {
18582        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18583            return;
18584        };
18585        workspace.activate_item(&item, true, true, window, cx);
18586    }
18587
18588    pub fn toggle_fold(
18589        &mut self,
18590        _: &actions::ToggleFold,
18591        window: &mut Window,
18592        cx: &mut Context<Self>,
18593    ) {
18594        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18595            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18596            let selection = self.selections.newest::<Point>(&display_map);
18597
18598            let range = if selection.is_empty() {
18599                let point = selection.head().to_display_point(&display_map);
18600                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18601                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18602                    .to_point(&display_map);
18603                start..end
18604            } else {
18605                selection.range()
18606            };
18607            if display_map.folds_in_range(range).next().is_some() {
18608                self.unfold_lines(&Default::default(), window, cx)
18609            } else {
18610                self.fold(&Default::default(), window, cx)
18611            }
18612        } else {
18613            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18614            let buffer_ids: HashSet<_> = self
18615                .selections
18616                .disjoint_anchor_ranges()
18617                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18618                .collect();
18619
18620            let should_unfold = buffer_ids
18621                .iter()
18622                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18623
18624            for buffer_id in buffer_ids {
18625                if should_unfold {
18626                    self.unfold_buffer(buffer_id, cx);
18627                } else {
18628                    self.fold_buffer(buffer_id, cx);
18629                }
18630            }
18631        }
18632    }
18633
18634    pub fn toggle_fold_recursive(
18635        &mut self,
18636        _: &actions::ToggleFoldRecursive,
18637        window: &mut Window,
18638        cx: &mut Context<Self>,
18639    ) {
18640        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18641
18642        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18643        let range = if selection.is_empty() {
18644            let point = selection.head().to_display_point(&display_map);
18645            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18646            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18647                .to_point(&display_map);
18648            start..end
18649        } else {
18650            selection.range()
18651        };
18652        if display_map.folds_in_range(range).next().is_some() {
18653            self.unfold_recursive(&Default::default(), window, cx)
18654        } else {
18655            self.fold_recursive(&Default::default(), window, cx)
18656        }
18657    }
18658
18659    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18660        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18661            let mut to_fold = Vec::new();
18662            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18663            let selections = self.selections.all_adjusted(&display_map);
18664
18665            for selection in selections {
18666                let range = selection.range().sorted();
18667                let buffer_start_row = range.start.row;
18668
18669                if range.start.row != range.end.row {
18670                    let mut found = false;
18671                    let mut row = range.start.row;
18672                    while row <= range.end.row {
18673                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18674                        {
18675                            found = true;
18676                            row = crease.range().end.row + 1;
18677                            to_fold.push(crease);
18678                        } else {
18679                            row += 1
18680                        }
18681                    }
18682                    if found {
18683                        continue;
18684                    }
18685                }
18686
18687                for row in (0..=range.start.row).rev() {
18688                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18689                        && crease.range().end.row >= buffer_start_row
18690                    {
18691                        to_fold.push(crease);
18692                        if row <= range.start.row {
18693                            break;
18694                        }
18695                    }
18696                }
18697            }
18698
18699            self.fold_creases(to_fold, true, window, cx);
18700        } else {
18701            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18702            let buffer_ids = self
18703                .selections
18704                .disjoint_anchor_ranges()
18705                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18706                .collect::<HashSet<_>>();
18707            for buffer_id in buffer_ids {
18708                self.fold_buffer(buffer_id, cx);
18709            }
18710        }
18711    }
18712
18713    pub fn toggle_fold_all(
18714        &mut self,
18715        _: &actions::ToggleFoldAll,
18716        window: &mut Window,
18717        cx: &mut Context<Self>,
18718    ) {
18719        if self.buffer.read(cx).is_singleton() {
18720            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18721            let has_folds = display_map
18722                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
18723                .next()
18724                .is_some();
18725
18726            if has_folds {
18727                self.unfold_all(&actions::UnfoldAll, window, cx);
18728            } else {
18729                self.fold_all(&actions::FoldAll, window, cx);
18730            }
18731        } else {
18732            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18733            let should_unfold = buffer_ids
18734                .iter()
18735                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18736
18737            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18738                editor
18739                    .update_in(cx, |editor, _, cx| {
18740                        for buffer_id in buffer_ids {
18741                            if should_unfold {
18742                                editor.unfold_buffer(buffer_id, cx);
18743                            } else {
18744                                editor.fold_buffer(buffer_id, cx);
18745                            }
18746                        }
18747                    })
18748                    .ok();
18749            });
18750        }
18751    }
18752
18753    fn fold_at_level(
18754        &mut self,
18755        fold_at: &FoldAtLevel,
18756        window: &mut Window,
18757        cx: &mut Context<Self>,
18758    ) {
18759        if !self.buffer.read(cx).is_singleton() {
18760            return;
18761        }
18762
18763        let fold_at_level = fold_at.0;
18764        let snapshot = self.buffer.read(cx).snapshot(cx);
18765        let mut to_fold = Vec::new();
18766        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18767
18768        let row_ranges_to_keep: Vec<Range<u32>> = self
18769            .selections
18770            .all::<Point>(&self.display_snapshot(cx))
18771            .into_iter()
18772            .map(|sel| sel.start.row..sel.end.row)
18773            .collect();
18774
18775        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18776            while start_row < end_row {
18777                match self
18778                    .snapshot(window, cx)
18779                    .crease_for_buffer_row(MultiBufferRow(start_row))
18780                {
18781                    Some(crease) => {
18782                        let nested_start_row = crease.range().start.row + 1;
18783                        let nested_end_row = crease.range().end.row;
18784
18785                        if current_level < fold_at_level {
18786                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18787                        } else if current_level == fold_at_level {
18788                            // Fold iff there is no selection completely contained within the fold region
18789                            if !row_ranges_to_keep.iter().any(|selection| {
18790                                selection.end >= nested_start_row
18791                                    && selection.start <= nested_end_row
18792                            }) {
18793                                to_fold.push(crease);
18794                            }
18795                        }
18796
18797                        start_row = nested_end_row + 1;
18798                    }
18799                    None => start_row += 1,
18800                }
18801            }
18802        }
18803
18804        self.fold_creases(to_fold, true, window, cx);
18805    }
18806
18807    pub fn fold_at_level_1(
18808        &mut self,
18809        _: &actions::FoldAtLevel1,
18810        window: &mut Window,
18811        cx: &mut Context<Self>,
18812    ) {
18813        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18814    }
18815
18816    pub fn fold_at_level_2(
18817        &mut self,
18818        _: &actions::FoldAtLevel2,
18819        window: &mut Window,
18820        cx: &mut Context<Self>,
18821    ) {
18822        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18823    }
18824
18825    pub fn fold_at_level_3(
18826        &mut self,
18827        _: &actions::FoldAtLevel3,
18828        window: &mut Window,
18829        cx: &mut Context<Self>,
18830    ) {
18831        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18832    }
18833
18834    pub fn fold_at_level_4(
18835        &mut self,
18836        _: &actions::FoldAtLevel4,
18837        window: &mut Window,
18838        cx: &mut Context<Self>,
18839    ) {
18840        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18841    }
18842
18843    pub fn fold_at_level_5(
18844        &mut self,
18845        _: &actions::FoldAtLevel5,
18846        window: &mut Window,
18847        cx: &mut Context<Self>,
18848    ) {
18849        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18850    }
18851
18852    pub fn fold_at_level_6(
18853        &mut self,
18854        _: &actions::FoldAtLevel6,
18855        window: &mut Window,
18856        cx: &mut Context<Self>,
18857    ) {
18858        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18859    }
18860
18861    pub fn fold_at_level_7(
18862        &mut self,
18863        _: &actions::FoldAtLevel7,
18864        window: &mut Window,
18865        cx: &mut Context<Self>,
18866    ) {
18867        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18868    }
18869
18870    pub fn fold_at_level_8(
18871        &mut self,
18872        _: &actions::FoldAtLevel8,
18873        window: &mut Window,
18874        cx: &mut Context<Self>,
18875    ) {
18876        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18877    }
18878
18879    pub fn fold_at_level_9(
18880        &mut self,
18881        _: &actions::FoldAtLevel9,
18882        window: &mut Window,
18883        cx: &mut Context<Self>,
18884    ) {
18885        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18886    }
18887
18888    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18889        if self.buffer.read(cx).is_singleton() {
18890            let mut fold_ranges = Vec::new();
18891            let snapshot = self.buffer.read(cx).snapshot(cx);
18892
18893            for row in 0..snapshot.max_row().0 {
18894                if let Some(foldable_range) = self
18895                    .snapshot(window, cx)
18896                    .crease_for_buffer_row(MultiBufferRow(row))
18897                {
18898                    fold_ranges.push(foldable_range);
18899                }
18900            }
18901
18902            self.fold_creases(fold_ranges, true, window, cx);
18903        } else {
18904            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18905                editor
18906                    .update_in(cx, |editor, _, cx| {
18907                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18908                            editor.fold_buffer(buffer_id, cx);
18909                        }
18910                    })
18911                    .ok();
18912            });
18913        }
18914    }
18915
18916    pub fn fold_function_bodies(
18917        &mut self,
18918        _: &actions::FoldFunctionBodies,
18919        window: &mut Window,
18920        cx: &mut Context<Self>,
18921    ) {
18922        let snapshot = self.buffer.read(cx).snapshot(cx);
18923
18924        let ranges = snapshot
18925            .text_object_ranges(
18926                MultiBufferOffset(0)..snapshot.len(),
18927                TreeSitterOptions::default(),
18928            )
18929            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18930            .collect::<Vec<_>>();
18931
18932        let creases = ranges
18933            .into_iter()
18934            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18935            .collect();
18936
18937        self.fold_creases(creases, true, window, cx);
18938    }
18939
18940    pub fn fold_recursive(
18941        &mut self,
18942        _: &actions::FoldRecursive,
18943        window: &mut Window,
18944        cx: &mut Context<Self>,
18945    ) {
18946        let mut to_fold = Vec::new();
18947        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18948        let selections = self.selections.all_adjusted(&display_map);
18949
18950        for selection in selections {
18951            let range = selection.range().sorted();
18952            let buffer_start_row = range.start.row;
18953
18954            if range.start.row != range.end.row {
18955                let mut found = false;
18956                for row in range.start.row..=range.end.row {
18957                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18958                        found = true;
18959                        to_fold.push(crease);
18960                    }
18961                }
18962                if found {
18963                    continue;
18964                }
18965            }
18966
18967            for row in (0..=range.start.row).rev() {
18968                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18969                    if crease.range().end.row >= buffer_start_row {
18970                        to_fold.push(crease);
18971                    } else {
18972                        break;
18973                    }
18974                }
18975            }
18976        }
18977
18978        self.fold_creases(to_fold, true, window, cx);
18979    }
18980
18981    pub fn fold_at(
18982        &mut self,
18983        buffer_row: MultiBufferRow,
18984        window: &mut Window,
18985        cx: &mut Context<Self>,
18986    ) {
18987        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18988
18989        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18990            let autoscroll = self
18991                .selections
18992                .all::<Point>(&display_map)
18993                .iter()
18994                .any(|selection| crease.range().overlaps(&selection.range()));
18995
18996            self.fold_creases(vec![crease], autoscroll, window, cx);
18997        }
18998    }
18999
19000    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19001        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19002            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19003            let buffer = display_map.buffer_snapshot();
19004            let selections = self.selections.all::<Point>(&display_map);
19005            let ranges = selections
19006                .iter()
19007                .map(|s| {
19008                    let range = s.display_range(&display_map).sorted();
19009                    let mut start = range.start.to_point(&display_map);
19010                    let mut end = range.end.to_point(&display_map);
19011                    start.column = 0;
19012                    end.column = buffer.line_len(MultiBufferRow(end.row));
19013                    start..end
19014                })
19015                .collect::<Vec<_>>();
19016
19017            self.unfold_ranges(&ranges, true, true, cx);
19018        } else {
19019            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19020            let buffer_ids = self
19021                .selections
19022                .disjoint_anchor_ranges()
19023                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19024                .collect::<HashSet<_>>();
19025            for buffer_id in buffer_ids {
19026                self.unfold_buffer(buffer_id, cx);
19027            }
19028        }
19029    }
19030
19031    pub fn unfold_recursive(
19032        &mut self,
19033        _: &UnfoldRecursive,
19034        _window: &mut Window,
19035        cx: &mut Context<Self>,
19036    ) {
19037        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19038        let selections = self.selections.all::<Point>(&display_map);
19039        let ranges = selections
19040            .iter()
19041            .map(|s| {
19042                let mut range = s.display_range(&display_map).sorted();
19043                *range.start.column_mut() = 0;
19044                *range.end.column_mut() = display_map.line_len(range.end.row());
19045                let start = range.start.to_point(&display_map);
19046                let end = range.end.to_point(&display_map);
19047                start..end
19048            })
19049            .collect::<Vec<_>>();
19050
19051        self.unfold_ranges(&ranges, true, true, cx);
19052    }
19053
19054    pub fn unfold_at(
19055        &mut self,
19056        buffer_row: MultiBufferRow,
19057        _window: &mut Window,
19058        cx: &mut Context<Self>,
19059    ) {
19060        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19061
19062        let intersection_range = Point::new(buffer_row.0, 0)
19063            ..Point::new(
19064                buffer_row.0,
19065                display_map.buffer_snapshot().line_len(buffer_row),
19066            );
19067
19068        let autoscroll = self
19069            .selections
19070            .all::<Point>(&display_map)
19071            .iter()
19072            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19073
19074        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19075    }
19076
19077    pub fn unfold_all(
19078        &mut self,
19079        _: &actions::UnfoldAll,
19080        _window: &mut Window,
19081        cx: &mut Context<Self>,
19082    ) {
19083        if self.buffer.read(cx).is_singleton() {
19084            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19085            self.unfold_ranges(
19086                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19087                true,
19088                true,
19089                cx,
19090            );
19091        } else {
19092            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19093                editor
19094                    .update(cx, |editor, cx| {
19095                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19096                            editor.unfold_buffer(buffer_id, cx);
19097                        }
19098                    })
19099                    .ok();
19100            });
19101        }
19102    }
19103
19104    pub fn fold_selected_ranges(
19105        &mut self,
19106        _: &FoldSelectedRanges,
19107        window: &mut Window,
19108        cx: &mut Context<Self>,
19109    ) {
19110        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19111        let selections = self.selections.all_adjusted(&display_map);
19112        let ranges = selections
19113            .into_iter()
19114            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19115            .collect::<Vec<_>>();
19116        self.fold_creases(ranges, true, window, cx);
19117    }
19118
19119    pub fn fold_ranges<T: ToOffset + Clone>(
19120        &mut self,
19121        ranges: Vec<Range<T>>,
19122        auto_scroll: bool,
19123        window: &mut Window,
19124        cx: &mut Context<Self>,
19125    ) {
19126        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19127        let ranges = ranges
19128            .into_iter()
19129            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19130            .collect::<Vec<_>>();
19131        self.fold_creases(ranges, auto_scroll, window, cx);
19132    }
19133
19134    pub fn fold_creases<T: ToOffset + Clone>(
19135        &mut self,
19136        creases: Vec<Crease<T>>,
19137        auto_scroll: bool,
19138        _window: &mut Window,
19139        cx: &mut Context<Self>,
19140    ) {
19141        if creases.is_empty() {
19142            return;
19143        }
19144
19145        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19146
19147        if auto_scroll {
19148            self.request_autoscroll(Autoscroll::fit(), cx);
19149        }
19150
19151        cx.notify();
19152
19153        self.scrollbar_marker_state.dirty = true;
19154        self.folds_did_change(cx);
19155    }
19156
19157    /// Removes any folds whose ranges intersect any of the given ranges.
19158    pub fn unfold_ranges<T: ToOffset + Clone>(
19159        &mut self,
19160        ranges: &[Range<T>],
19161        inclusive: bool,
19162        auto_scroll: bool,
19163        cx: &mut Context<Self>,
19164    ) {
19165        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19166            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19167        });
19168        self.folds_did_change(cx);
19169    }
19170
19171    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19172        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19173            return;
19174        }
19175
19176        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19177        self.display_map.update(cx, |display_map, cx| {
19178            display_map.fold_buffers([buffer_id], cx)
19179        });
19180
19181        let snapshot = self.display_snapshot(cx);
19182        self.selections.change_with(&snapshot, |selections| {
19183            selections.remove_selections_from_buffer(buffer_id);
19184        });
19185
19186        cx.emit(EditorEvent::BufferFoldToggled {
19187            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19188            folded: true,
19189        });
19190        cx.notify();
19191    }
19192
19193    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19194        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19195            return;
19196        }
19197        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19198        self.display_map.update(cx, |display_map, cx| {
19199            display_map.unfold_buffers([buffer_id], cx);
19200        });
19201        cx.emit(EditorEvent::BufferFoldToggled {
19202            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19203            folded: false,
19204        });
19205        cx.notify();
19206    }
19207
19208    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19209        self.display_map.read(cx).is_buffer_folded(buffer)
19210    }
19211
19212    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19213        self.display_map.read(cx).folded_buffers()
19214    }
19215
19216    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19217        self.display_map.update(cx, |display_map, cx| {
19218            display_map.disable_header_for_buffer(buffer_id, cx);
19219        });
19220        cx.notify();
19221    }
19222
19223    /// Removes any folds with the given ranges.
19224    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19225        &mut self,
19226        ranges: &[Range<T>],
19227        type_id: TypeId,
19228        auto_scroll: bool,
19229        cx: &mut Context<Self>,
19230    ) {
19231        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19232            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19233        });
19234        self.folds_did_change(cx);
19235    }
19236
19237    fn remove_folds_with<T: ToOffset + Clone>(
19238        &mut self,
19239        ranges: &[Range<T>],
19240        auto_scroll: bool,
19241        cx: &mut Context<Self>,
19242        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19243    ) {
19244        if ranges.is_empty() {
19245            return;
19246        }
19247
19248        let mut buffers_affected = HashSet::default();
19249        let multi_buffer = self.buffer().read(cx);
19250        for range in ranges {
19251            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19252                buffers_affected.insert(buffer.read(cx).remote_id());
19253            };
19254        }
19255
19256        self.display_map.update(cx, update);
19257
19258        if auto_scroll {
19259            self.request_autoscroll(Autoscroll::fit(), cx);
19260        }
19261
19262        cx.notify();
19263        self.scrollbar_marker_state.dirty = true;
19264        self.active_indent_guides_state.dirty = true;
19265    }
19266
19267    pub fn update_renderer_widths(
19268        &mut self,
19269        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19270        cx: &mut Context<Self>,
19271    ) -> bool {
19272        self.display_map
19273            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19274    }
19275
19276    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19277        self.display_map.read(cx).fold_placeholder.clone()
19278    }
19279
19280    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19281        self.use_base_text_line_numbers = show;
19282    }
19283
19284    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19285        self.buffer.update(cx, |buffer, cx| {
19286            buffer.set_all_diff_hunks_expanded(cx);
19287        });
19288    }
19289
19290    pub fn expand_all_diff_hunks(
19291        &mut self,
19292        _: &ExpandAllDiffHunks,
19293        _window: &mut Window,
19294        cx: &mut Context<Self>,
19295    ) {
19296        self.buffer.update(cx, |buffer, cx| {
19297            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19298        });
19299    }
19300
19301    pub fn collapse_all_diff_hunks(
19302        &mut self,
19303        _: &CollapseAllDiffHunks,
19304        _window: &mut Window,
19305        cx: &mut Context<Self>,
19306    ) {
19307        self.buffer.update(cx, |buffer, cx| {
19308            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19309        });
19310    }
19311
19312    pub fn toggle_selected_diff_hunks(
19313        &mut self,
19314        _: &ToggleSelectedDiffHunks,
19315        _window: &mut Window,
19316        cx: &mut Context<Self>,
19317    ) {
19318        let ranges: Vec<_> = self
19319            .selections
19320            .disjoint_anchors()
19321            .iter()
19322            .map(|s| s.range())
19323            .collect();
19324        self.toggle_diff_hunks_in_ranges(ranges, cx);
19325    }
19326
19327    pub fn diff_hunks_in_ranges<'a>(
19328        &'a self,
19329        ranges: &'a [Range<Anchor>],
19330        buffer: &'a MultiBufferSnapshot,
19331    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19332        ranges.iter().flat_map(move |range| {
19333            let end_excerpt_id = range.end.excerpt_id;
19334            let range = range.to_point(buffer);
19335            let mut peek_end = range.end;
19336            if range.end.row < buffer.max_row().0 {
19337                peek_end = Point::new(range.end.row + 1, 0);
19338            }
19339            buffer
19340                .diff_hunks_in_range(range.start..peek_end)
19341                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19342        })
19343    }
19344
19345    pub fn has_stageable_diff_hunks_in_ranges(
19346        &self,
19347        ranges: &[Range<Anchor>],
19348        snapshot: &MultiBufferSnapshot,
19349    ) -> bool {
19350        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19351        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19352    }
19353
19354    pub fn toggle_staged_selected_diff_hunks(
19355        &mut self,
19356        _: &::git::ToggleStaged,
19357        _: &mut Window,
19358        cx: &mut Context<Self>,
19359    ) {
19360        let snapshot = self.buffer.read(cx).snapshot(cx);
19361        let ranges: Vec<_> = self
19362            .selections
19363            .disjoint_anchors()
19364            .iter()
19365            .map(|s| s.range())
19366            .collect();
19367        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19368        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19369    }
19370
19371    pub fn set_render_diff_hunk_controls(
19372        &mut self,
19373        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19374        cx: &mut Context<Self>,
19375    ) {
19376        self.render_diff_hunk_controls = render_diff_hunk_controls;
19377        cx.notify();
19378    }
19379
19380    pub fn stage_and_next(
19381        &mut self,
19382        _: &::git::StageAndNext,
19383        window: &mut Window,
19384        cx: &mut Context<Self>,
19385    ) {
19386        self.do_stage_or_unstage_and_next(true, window, cx);
19387    }
19388
19389    pub fn unstage_and_next(
19390        &mut self,
19391        _: &::git::UnstageAndNext,
19392        window: &mut Window,
19393        cx: &mut Context<Self>,
19394    ) {
19395        self.do_stage_or_unstage_and_next(false, window, cx);
19396    }
19397
19398    pub fn stage_or_unstage_diff_hunks(
19399        &mut self,
19400        stage: bool,
19401        ranges: Vec<Range<Anchor>>,
19402        cx: &mut Context<Self>,
19403    ) {
19404        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19405        cx.spawn(async move |this, cx| {
19406            task.await?;
19407            this.update(cx, |this, cx| {
19408                let snapshot = this.buffer.read(cx).snapshot(cx);
19409                let chunk_by = this
19410                    .diff_hunks_in_ranges(&ranges, &snapshot)
19411                    .chunk_by(|hunk| hunk.buffer_id);
19412                for (buffer_id, hunks) in &chunk_by {
19413                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19414                }
19415            })
19416        })
19417        .detach_and_log_err(cx);
19418    }
19419
19420    fn save_buffers_for_ranges_if_needed(
19421        &mut self,
19422        ranges: &[Range<Anchor>],
19423        cx: &mut Context<Editor>,
19424    ) -> Task<Result<()>> {
19425        let multibuffer = self.buffer.read(cx);
19426        let snapshot = multibuffer.read(cx);
19427        let buffer_ids: HashSet<_> = ranges
19428            .iter()
19429            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19430            .collect();
19431        drop(snapshot);
19432
19433        let mut buffers = HashSet::default();
19434        for buffer_id in buffer_ids {
19435            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19436                let buffer = buffer_entity.read(cx);
19437                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19438                {
19439                    buffers.insert(buffer_entity);
19440                }
19441            }
19442        }
19443
19444        if let Some(project) = &self.project {
19445            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19446        } else {
19447            Task::ready(Ok(()))
19448        }
19449    }
19450
19451    fn do_stage_or_unstage_and_next(
19452        &mut self,
19453        stage: bool,
19454        window: &mut Window,
19455        cx: &mut Context<Self>,
19456    ) {
19457        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19458
19459        if ranges.iter().any(|range| range.start != range.end) {
19460            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19461            return;
19462        }
19463
19464        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19465        let snapshot = self.snapshot(window, cx);
19466        let position = self
19467            .selections
19468            .newest::<Point>(&snapshot.display_snapshot)
19469            .head();
19470        let mut row = snapshot
19471            .buffer_snapshot()
19472            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19473            .find(|hunk| hunk.row_range.start.0 > position.row)
19474            .map(|hunk| hunk.row_range.start);
19475
19476        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19477        // Outside of the project diff editor, wrap around to the beginning.
19478        if !all_diff_hunks_expanded {
19479            row = row.or_else(|| {
19480                snapshot
19481                    .buffer_snapshot()
19482                    .diff_hunks_in_range(Point::zero()..position)
19483                    .find(|hunk| hunk.row_range.end.0 < position.row)
19484                    .map(|hunk| hunk.row_range.start)
19485            });
19486        }
19487
19488        if let Some(row) = row {
19489            let destination = Point::new(row.0, 0);
19490            let autoscroll = Autoscroll::center();
19491
19492            self.unfold_ranges(&[destination..destination], false, false, cx);
19493            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19494                s.select_ranges([destination..destination]);
19495            });
19496        }
19497    }
19498
19499    fn do_stage_or_unstage(
19500        &self,
19501        stage: bool,
19502        buffer_id: BufferId,
19503        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19504        cx: &mut App,
19505    ) -> Option<()> {
19506        let project = self.project()?;
19507        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19508        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19509        let buffer_snapshot = buffer.read(cx).snapshot();
19510        let file_exists = buffer_snapshot
19511            .file()
19512            .is_some_and(|file| file.disk_state().exists());
19513        diff.update(cx, |diff, cx| {
19514            diff.stage_or_unstage_hunks(
19515                stage,
19516                &hunks
19517                    .map(|hunk| buffer_diff::DiffHunk {
19518                        buffer_range: hunk.buffer_range,
19519                        // We don't need to pass in word diffs here because they're only used for rendering and
19520                        // this function changes internal state
19521                        base_word_diffs: Vec::default(),
19522                        buffer_word_diffs: Vec::default(),
19523                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19524                            ..hunk.diff_base_byte_range.end.0,
19525                        secondary_status: hunk.secondary_status,
19526                        range: Point::zero()..Point::zero(), // unused
19527                    })
19528                    .collect::<Vec<_>>(),
19529                &buffer_snapshot,
19530                file_exists,
19531                cx,
19532            )
19533        });
19534        None
19535    }
19536
19537    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19538        let ranges: Vec<_> = self
19539            .selections
19540            .disjoint_anchors()
19541            .iter()
19542            .map(|s| s.range())
19543            .collect();
19544        self.buffer
19545            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19546    }
19547
19548    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19549        self.buffer.update(cx, |buffer, cx| {
19550            let ranges = vec![Anchor::min()..Anchor::max()];
19551            if !buffer.all_diff_hunks_expanded()
19552                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19553            {
19554                buffer.collapse_diff_hunks(ranges, cx);
19555                true
19556            } else {
19557                false
19558            }
19559        })
19560    }
19561
19562    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19563        if self.buffer.read(cx).all_diff_hunks_expanded() {
19564            return true;
19565        }
19566        let ranges = vec![Anchor::min()..Anchor::max()];
19567        self.buffer
19568            .read(cx)
19569            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19570    }
19571
19572    fn toggle_diff_hunks_in_ranges(
19573        &mut self,
19574        ranges: Vec<Range<Anchor>>,
19575        cx: &mut Context<Editor>,
19576    ) {
19577        self.buffer.update(cx, |buffer, cx| {
19578            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19579            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19580        })
19581    }
19582
19583    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19584        self.buffer.update(cx, |buffer, cx| {
19585            let snapshot = buffer.snapshot(cx);
19586            let excerpt_id = range.end.excerpt_id;
19587            let point_range = range.to_point(&snapshot);
19588            let expand = !buffer.single_hunk_is_expanded(range, cx);
19589            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19590        })
19591    }
19592
19593    pub(crate) fn apply_all_diff_hunks(
19594        &mut self,
19595        _: &ApplyAllDiffHunks,
19596        window: &mut Window,
19597        cx: &mut Context<Self>,
19598    ) {
19599        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19600
19601        let buffers = self.buffer.read(cx).all_buffers();
19602        for branch_buffer in buffers {
19603            branch_buffer.update(cx, |branch_buffer, cx| {
19604                branch_buffer.merge_into_base(Vec::new(), cx);
19605            });
19606        }
19607
19608        if let Some(project) = self.project.clone() {
19609            self.save(
19610                SaveOptions {
19611                    format: true,
19612                    autosave: false,
19613                },
19614                project,
19615                window,
19616                cx,
19617            )
19618            .detach_and_log_err(cx);
19619        }
19620    }
19621
19622    pub(crate) fn apply_selected_diff_hunks(
19623        &mut self,
19624        _: &ApplyDiffHunk,
19625        window: &mut Window,
19626        cx: &mut Context<Self>,
19627    ) {
19628        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19629        let snapshot = self.snapshot(window, cx);
19630        let hunks = snapshot.hunks_for_ranges(
19631            self.selections
19632                .all(&snapshot.display_snapshot)
19633                .into_iter()
19634                .map(|selection| selection.range()),
19635        );
19636        let mut ranges_by_buffer = HashMap::default();
19637        self.transact(window, cx, |editor, _window, cx| {
19638            for hunk in hunks {
19639                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19640                    ranges_by_buffer
19641                        .entry(buffer.clone())
19642                        .or_insert_with(Vec::new)
19643                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19644                }
19645            }
19646
19647            for (buffer, ranges) in ranges_by_buffer {
19648                buffer.update(cx, |buffer, cx| {
19649                    buffer.merge_into_base(ranges, cx);
19650                });
19651            }
19652        });
19653
19654        if let Some(project) = self.project.clone() {
19655            self.save(
19656                SaveOptions {
19657                    format: true,
19658                    autosave: false,
19659                },
19660                project,
19661                window,
19662                cx,
19663            )
19664            .detach_and_log_err(cx);
19665        }
19666    }
19667
19668    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19669        if hovered != self.gutter_hovered {
19670            self.gutter_hovered = hovered;
19671            cx.notify();
19672        }
19673    }
19674
19675    pub fn insert_blocks(
19676        &mut self,
19677        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19678        autoscroll: Option<Autoscroll>,
19679        cx: &mut Context<Self>,
19680    ) -> Vec<CustomBlockId> {
19681        let blocks = self
19682            .display_map
19683            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19684        if let Some(autoscroll) = autoscroll {
19685            self.request_autoscroll(autoscroll, cx);
19686        }
19687        cx.notify();
19688        blocks
19689    }
19690
19691    pub fn resize_blocks(
19692        &mut self,
19693        heights: HashMap<CustomBlockId, u32>,
19694        autoscroll: Option<Autoscroll>,
19695        cx: &mut Context<Self>,
19696    ) {
19697        self.display_map
19698            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19699        if let Some(autoscroll) = autoscroll {
19700            self.request_autoscroll(autoscroll, cx);
19701        }
19702        cx.notify();
19703    }
19704
19705    pub fn replace_blocks(
19706        &mut self,
19707        renderers: HashMap<CustomBlockId, RenderBlock>,
19708        autoscroll: Option<Autoscroll>,
19709        cx: &mut Context<Self>,
19710    ) {
19711        self.display_map
19712            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19713        if let Some(autoscroll) = autoscroll {
19714            self.request_autoscroll(autoscroll, cx);
19715        }
19716        cx.notify();
19717    }
19718
19719    pub fn remove_blocks(
19720        &mut self,
19721        block_ids: HashSet<CustomBlockId>,
19722        autoscroll: Option<Autoscroll>,
19723        cx: &mut Context<Self>,
19724    ) {
19725        self.display_map.update(cx, |display_map, cx| {
19726            display_map.remove_blocks(block_ids, cx)
19727        });
19728        if let Some(autoscroll) = autoscroll {
19729            self.request_autoscroll(autoscroll, cx);
19730        }
19731        cx.notify();
19732    }
19733
19734    pub fn row_for_block(
19735        &self,
19736        block_id: CustomBlockId,
19737        cx: &mut Context<Self>,
19738    ) -> Option<DisplayRow> {
19739        self.display_map
19740            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19741    }
19742
19743    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19744        self.focused_block = Some(focused_block);
19745    }
19746
19747    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19748        self.focused_block.take()
19749    }
19750
19751    pub fn insert_creases(
19752        &mut self,
19753        creases: impl IntoIterator<Item = Crease<Anchor>>,
19754        cx: &mut Context<Self>,
19755    ) -> Vec<CreaseId> {
19756        self.display_map
19757            .update(cx, |map, cx| map.insert_creases(creases, cx))
19758    }
19759
19760    pub fn remove_creases(
19761        &mut self,
19762        ids: impl IntoIterator<Item = CreaseId>,
19763        cx: &mut Context<Self>,
19764    ) -> Vec<(CreaseId, Range<Anchor>)> {
19765        self.display_map
19766            .update(cx, |map, cx| map.remove_creases(ids, cx))
19767    }
19768
19769    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19770        self.display_map
19771            .update(cx, |map, cx| map.snapshot(cx))
19772            .longest_row()
19773    }
19774
19775    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19776        self.display_map
19777            .update(cx, |map, cx| map.snapshot(cx))
19778            .max_point()
19779    }
19780
19781    pub fn text(&self, cx: &App) -> String {
19782        self.buffer.read(cx).read(cx).text()
19783    }
19784
19785    pub fn is_empty(&self, cx: &App) -> bool {
19786        self.buffer.read(cx).read(cx).is_empty()
19787    }
19788
19789    pub fn text_option(&self, cx: &App) -> Option<String> {
19790        let text = self.text(cx);
19791        let text = text.trim();
19792
19793        if text.is_empty() {
19794            return None;
19795        }
19796
19797        Some(text.to_string())
19798    }
19799
19800    pub fn set_text(
19801        &mut self,
19802        text: impl Into<Arc<str>>,
19803        window: &mut Window,
19804        cx: &mut Context<Self>,
19805    ) {
19806        self.transact(window, cx, |this, _, cx| {
19807            this.buffer
19808                .read(cx)
19809                .as_singleton()
19810                .expect("you can only call set_text on editors for singleton buffers")
19811                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19812        });
19813    }
19814
19815    pub fn display_text(&self, cx: &mut App) -> String {
19816        self.display_map
19817            .update(cx, |map, cx| map.snapshot(cx))
19818            .text()
19819    }
19820
19821    fn create_minimap(
19822        &self,
19823        minimap_settings: MinimapSettings,
19824        window: &mut Window,
19825        cx: &mut Context<Self>,
19826    ) -> Option<Entity<Self>> {
19827        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19828            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19829    }
19830
19831    fn initialize_new_minimap(
19832        &self,
19833        minimap_settings: MinimapSettings,
19834        window: &mut Window,
19835        cx: &mut Context<Self>,
19836    ) -> Entity<Self> {
19837        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19838
19839        let mut minimap = Editor::new_internal(
19840            EditorMode::Minimap {
19841                parent: cx.weak_entity(),
19842            },
19843            self.buffer.clone(),
19844            None,
19845            Some(self.display_map.clone()),
19846            window,
19847            cx,
19848        );
19849        minimap.scroll_manager.clone_state(&self.scroll_manager);
19850        minimap.set_text_style_refinement(TextStyleRefinement {
19851            font_size: Some(MINIMAP_FONT_SIZE),
19852            font_weight: Some(MINIMAP_FONT_WEIGHT),
19853            ..Default::default()
19854        });
19855        minimap.update_minimap_configuration(minimap_settings, cx);
19856        cx.new(|_| minimap)
19857    }
19858
19859    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19860        let current_line_highlight = minimap_settings
19861            .current_line_highlight
19862            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19863        self.set_current_line_highlight(Some(current_line_highlight));
19864    }
19865
19866    pub fn minimap(&self) -> Option<&Entity<Self>> {
19867        self.minimap
19868            .as_ref()
19869            .filter(|_| self.minimap_visibility.visible())
19870    }
19871
19872    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19873        let mut wrap_guides = smallvec![];
19874
19875        if self.show_wrap_guides == Some(false) {
19876            return wrap_guides;
19877        }
19878
19879        let settings = self.buffer.read(cx).language_settings(cx);
19880        if settings.show_wrap_guides {
19881            match self.soft_wrap_mode(cx) {
19882                SoftWrap::Column(soft_wrap) => {
19883                    wrap_guides.push((soft_wrap as usize, true));
19884                }
19885                SoftWrap::Bounded(soft_wrap) => {
19886                    wrap_guides.push((soft_wrap as usize, true));
19887                }
19888                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19889            }
19890            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19891        }
19892
19893        wrap_guides
19894    }
19895
19896    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19897        let settings = self.buffer.read(cx).language_settings(cx);
19898        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19899        match mode {
19900            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19901                SoftWrap::None
19902            }
19903            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19904            language_settings::SoftWrap::PreferredLineLength => {
19905                SoftWrap::Column(settings.preferred_line_length)
19906            }
19907            language_settings::SoftWrap::Bounded => {
19908                SoftWrap::Bounded(settings.preferred_line_length)
19909            }
19910        }
19911    }
19912
19913    pub fn set_soft_wrap_mode(
19914        &mut self,
19915        mode: language_settings::SoftWrap,
19916
19917        cx: &mut Context<Self>,
19918    ) {
19919        self.soft_wrap_mode_override = Some(mode);
19920        cx.notify();
19921    }
19922
19923    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19924        self.hard_wrap = hard_wrap;
19925        cx.notify();
19926    }
19927
19928    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19929        self.text_style_refinement = Some(style);
19930    }
19931
19932    /// called by the Element so we know what style we were most recently rendered with.
19933    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19934        // We intentionally do not inform the display map about the minimap style
19935        // so that wrapping is not recalculated and stays consistent for the editor
19936        // and its linked minimap.
19937        if !self.mode.is_minimap() {
19938            let font = style.text.font();
19939            let font_size = style.text.font_size.to_pixels(window.rem_size());
19940            let display_map = self
19941                .placeholder_display_map
19942                .as_ref()
19943                .filter(|_| self.is_empty(cx))
19944                .unwrap_or(&self.display_map);
19945
19946            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19947        }
19948        self.style = Some(style);
19949    }
19950
19951    pub fn style(&self) -> Option<&EditorStyle> {
19952        self.style.as_ref()
19953    }
19954
19955    // Called by the element. This method is not designed to be called outside of the editor
19956    // element's layout code because it does not notify when rewrapping is computed synchronously.
19957    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19958        if self.is_empty(cx) {
19959            self.placeholder_display_map
19960                .as_ref()
19961                .map_or(false, |display_map| {
19962                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19963                })
19964        } else {
19965            self.display_map
19966                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19967        }
19968    }
19969
19970    pub fn set_soft_wrap(&mut self) {
19971        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19972    }
19973
19974    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19975        if self.soft_wrap_mode_override.is_some() {
19976            self.soft_wrap_mode_override.take();
19977        } else {
19978            let soft_wrap = match self.soft_wrap_mode(cx) {
19979                SoftWrap::GitDiff => return,
19980                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19981                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19982                    language_settings::SoftWrap::None
19983                }
19984            };
19985            self.soft_wrap_mode_override = Some(soft_wrap);
19986        }
19987        cx.notify();
19988    }
19989
19990    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19991        let Some(workspace) = self.workspace() else {
19992            return;
19993        };
19994        let fs = workspace.read(cx).app_state().fs.clone();
19995        let current_show = TabBarSettings::get_global(cx).show;
19996        update_settings_file(fs, cx, move |setting, _| {
19997            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19998        });
19999    }
20000
20001    pub fn toggle_indent_guides(
20002        &mut self,
20003        _: &ToggleIndentGuides,
20004        _: &mut Window,
20005        cx: &mut Context<Self>,
20006    ) {
20007        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20008            self.buffer
20009                .read(cx)
20010                .language_settings(cx)
20011                .indent_guides
20012                .enabled
20013        });
20014        self.show_indent_guides = Some(!currently_enabled);
20015        cx.notify();
20016    }
20017
20018    fn should_show_indent_guides(&self) -> Option<bool> {
20019        self.show_indent_guides
20020    }
20021
20022    pub fn toggle_line_numbers(
20023        &mut self,
20024        _: &ToggleLineNumbers,
20025        _: &mut Window,
20026        cx: &mut Context<Self>,
20027    ) {
20028        let mut editor_settings = EditorSettings::get_global(cx).clone();
20029        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20030        EditorSettings::override_global(editor_settings, cx);
20031    }
20032
20033    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20034        if let Some(show_line_numbers) = self.show_line_numbers {
20035            return show_line_numbers;
20036        }
20037        EditorSettings::get_global(cx).gutter.line_numbers
20038    }
20039
20040    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
20041        match (
20042            self.use_relative_line_numbers,
20043            EditorSettings::get_global(cx).relative_line_numbers,
20044        ) {
20045            (None, setting) => setting,
20046            (Some(false), _) => RelativeLineNumbers::Disabled,
20047            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20048            (Some(true), _) => RelativeLineNumbers::Enabled,
20049        }
20050    }
20051
20052    pub fn toggle_relative_line_numbers(
20053        &mut self,
20054        _: &ToggleRelativeLineNumbers,
20055        _: &mut Window,
20056        cx: &mut Context<Self>,
20057    ) {
20058        let is_relative = self.relative_line_numbers(cx);
20059        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20060    }
20061
20062    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20063        self.use_relative_line_numbers = is_relative;
20064        cx.notify();
20065    }
20066
20067    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20068        self.show_gutter = show_gutter;
20069        cx.notify();
20070    }
20071
20072    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20073        self.show_scrollbars = ScrollbarAxes {
20074            horizontal: show,
20075            vertical: show,
20076        };
20077        cx.notify();
20078    }
20079
20080    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20081        self.show_scrollbars.vertical = show;
20082        cx.notify();
20083    }
20084
20085    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20086        self.show_scrollbars.horizontal = show;
20087        cx.notify();
20088    }
20089
20090    pub fn set_minimap_visibility(
20091        &mut self,
20092        minimap_visibility: MinimapVisibility,
20093        window: &mut Window,
20094        cx: &mut Context<Self>,
20095    ) {
20096        if self.minimap_visibility != minimap_visibility {
20097            if minimap_visibility.visible() && self.minimap.is_none() {
20098                let minimap_settings = EditorSettings::get_global(cx).minimap;
20099                self.minimap =
20100                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20101            }
20102            self.minimap_visibility = minimap_visibility;
20103            cx.notify();
20104        }
20105    }
20106
20107    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20108        self.set_show_scrollbars(false, cx);
20109        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20110    }
20111
20112    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20113        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20114    }
20115
20116    /// Normally the text in full mode and auto height editors is padded on the
20117    /// left side by roughly half a character width for improved hit testing.
20118    ///
20119    /// Use this method to disable this for cases where this is not wanted (e.g.
20120    /// if you want to align the editor text with some other text above or below)
20121    /// or if you want to add this padding to single-line editors.
20122    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20123        self.offset_content = offset_content;
20124        cx.notify();
20125    }
20126
20127    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20128        self.show_line_numbers = Some(show_line_numbers);
20129        cx.notify();
20130    }
20131
20132    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20133        self.disable_expand_excerpt_buttons = true;
20134        cx.notify();
20135    }
20136
20137    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20138        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20139        cx.notify();
20140    }
20141
20142    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20143        self.show_code_actions = Some(show_code_actions);
20144        cx.notify();
20145    }
20146
20147    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20148        self.show_runnables = Some(show_runnables);
20149        cx.notify();
20150    }
20151
20152    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20153        self.show_breakpoints = Some(show_breakpoints);
20154        cx.notify();
20155    }
20156
20157    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20158        if self.display_map.read(cx).masked != masked {
20159            self.display_map.update(cx, |map, _| map.masked = masked);
20160        }
20161        cx.notify()
20162    }
20163
20164    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20165        self.show_wrap_guides = Some(show_wrap_guides);
20166        cx.notify();
20167    }
20168
20169    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20170        self.show_indent_guides = Some(show_indent_guides);
20171        cx.notify();
20172    }
20173
20174    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20175        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20176            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20177                && let Some(dir) = file.abs_path(cx).parent()
20178            {
20179                return Some(dir.to_owned());
20180            }
20181        }
20182
20183        None
20184    }
20185
20186    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20187        self.active_excerpt(cx)?
20188            .1
20189            .read(cx)
20190            .file()
20191            .and_then(|f| f.as_local())
20192    }
20193
20194    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20195        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20196            let buffer = buffer.read(cx);
20197            if let Some(project_path) = buffer.project_path(cx) {
20198                let project = self.project()?.read(cx);
20199                project.absolute_path(&project_path, cx)
20200            } else {
20201                buffer
20202                    .file()
20203                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20204            }
20205        })
20206    }
20207
20208    pub fn reveal_in_finder(
20209        &mut self,
20210        _: &RevealInFileManager,
20211        _window: &mut Window,
20212        cx: &mut Context<Self>,
20213    ) {
20214        if let Some(target) = self.target_file(cx) {
20215            cx.reveal_path(&target.abs_path(cx));
20216        }
20217    }
20218
20219    pub fn copy_path(
20220        &mut self,
20221        _: &zed_actions::workspace::CopyPath,
20222        _window: &mut Window,
20223        cx: &mut Context<Self>,
20224    ) {
20225        if let Some(path) = self.target_file_abs_path(cx)
20226            && let Some(path) = path.to_str()
20227        {
20228            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20229        } else {
20230            cx.propagate();
20231        }
20232    }
20233
20234    pub fn copy_relative_path(
20235        &mut self,
20236        _: &zed_actions::workspace::CopyRelativePath,
20237        _window: &mut Window,
20238        cx: &mut Context<Self>,
20239    ) {
20240        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20241            let project = self.project()?.read(cx);
20242            let path = buffer.read(cx).file()?.path();
20243            let path = path.display(project.path_style(cx));
20244            Some(path)
20245        }) {
20246            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20247        } else {
20248            cx.propagate();
20249        }
20250    }
20251
20252    /// Returns the project path for the editor's buffer, if any buffer is
20253    /// opened in the editor.
20254    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20255        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20256            buffer.read(cx).project_path(cx)
20257        } else {
20258            None
20259        }
20260    }
20261
20262    // Returns true if the editor handled a go-to-line request
20263    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20264        maybe!({
20265            let breakpoint_store = self.breakpoint_store.as_ref()?;
20266
20267            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20268            else {
20269                self.clear_row_highlights::<ActiveDebugLine>();
20270                return None;
20271            };
20272
20273            let position = active_stack_frame.position;
20274            let buffer_id = position.buffer_id?;
20275            let snapshot = self
20276                .project
20277                .as_ref()?
20278                .read(cx)
20279                .buffer_for_id(buffer_id, cx)?
20280                .read(cx)
20281                .snapshot();
20282
20283            let mut handled = false;
20284            for (id, ExcerptRange { context, .. }) in
20285                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20286            {
20287                if context.start.cmp(&position, &snapshot).is_ge()
20288                    || context.end.cmp(&position, &snapshot).is_lt()
20289                {
20290                    continue;
20291                }
20292                let snapshot = self.buffer.read(cx).snapshot(cx);
20293                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20294
20295                handled = true;
20296                self.clear_row_highlights::<ActiveDebugLine>();
20297
20298                self.go_to_line::<ActiveDebugLine>(
20299                    multibuffer_anchor,
20300                    Some(cx.theme().colors().editor_debugger_active_line_background),
20301                    window,
20302                    cx,
20303                );
20304
20305                cx.notify();
20306            }
20307
20308            handled.then_some(())
20309        })
20310        .is_some()
20311    }
20312
20313    pub fn copy_file_name_without_extension(
20314        &mut self,
20315        _: &CopyFileNameWithoutExtension,
20316        _: &mut Window,
20317        cx: &mut Context<Self>,
20318    ) {
20319        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20320            let file = buffer.read(cx).file()?;
20321            file.path().file_stem()
20322        }) {
20323            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20324        }
20325    }
20326
20327    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20328        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20329            let file = buffer.read(cx).file()?;
20330            Some(file.file_name(cx))
20331        }) {
20332            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20333        }
20334    }
20335
20336    pub fn toggle_git_blame(
20337        &mut self,
20338        _: &::git::Blame,
20339        window: &mut Window,
20340        cx: &mut Context<Self>,
20341    ) {
20342        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20343
20344        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20345            self.start_git_blame(true, window, cx);
20346        }
20347
20348        cx.notify();
20349    }
20350
20351    pub fn toggle_git_blame_inline(
20352        &mut self,
20353        _: &ToggleGitBlameInline,
20354        window: &mut Window,
20355        cx: &mut Context<Self>,
20356    ) {
20357        self.toggle_git_blame_inline_internal(true, window, cx);
20358        cx.notify();
20359    }
20360
20361    pub fn open_git_blame_commit(
20362        &mut self,
20363        _: &OpenGitBlameCommit,
20364        window: &mut Window,
20365        cx: &mut Context<Self>,
20366    ) {
20367        self.open_git_blame_commit_internal(window, cx);
20368    }
20369
20370    fn open_git_blame_commit_internal(
20371        &mut self,
20372        window: &mut Window,
20373        cx: &mut Context<Self>,
20374    ) -> Option<()> {
20375        let blame = self.blame.as_ref()?;
20376        let snapshot = self.snapshot(window, cx);
20377        let cursor = self
20378            .selections
20379            .newest::<Point>(&snapshot.display_snapshot)
20380            .head();
20381        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20382        let (_, blame_entry) = blame
20383            .update(cx, |blame, cx| {
20384                blame
20385                    .blame_for_rows(
20386                        &[RowInfo {
20387                            buffer_id: Some(buffer.remote_id()),
20388                            buffer_row: Some(point.row),
20389                            ..Default::default()
20390                        }],
20391                        cx,
20392                    )
20393                    .next()
20394            })
20395            .flatten()?;
20396        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20397        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20398        let workspace = self.workspace()?.downgrade();
20399        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20400        None
20401    }
20402
20403    pub fn git_blame_inline_enabled(&self) -> bool {
20404        self.git_blame_inline_enabled
20405    }
20406
20407    pub fn toggle_selection_menu(
20408        &mut self,
20409        _: &ToggleSelectionMenu,
20410        _: &mut Window,
20411        cx: &mut Context<Self>,
20412    ) {
20413        self.show_selection_menu = self
20414            .show_selection_menu
20415            .map(|show_selections_menu| !show_selections_menu)
20416            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20417
20418        cx.notify();
20419    }
20420
20421    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20422        self.show_selection_menu
20423            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20424    }
20425
20426    fn start_git_blame(
20427        &mut self,
20428        user_triggered: bool,
20429        window: &mut Window,
20430        cx: &mut Context<Self>,
20431    ) {
20432        if let Some(project) = self.project() {
20433            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20434                && buffer.read(cx).file().is_none()
20435            {
20436                return;
20437            }
20438
20439            let focused = self.focus_handle(cx).contains_focused(window, cx);
20440
20441            let project = project.clone();
20442            let blame = cx
20443                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20444            self.blame_subscription =
20445                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20446            self.blame = Some(blame);
20447        }
20448    }
20449
20450    fn toggle_git_blame_inline_internal(
20451        &mut self,
20452        user_triggered: bool,
20453        window: &mut Window,
20454        cx: &mut Context<Self>,
20455    ) {
20456        if self.git_blame_inline_enabled {
20457            self.git_blame_inline_enabled = false;
20458            self.show_git_blame_inline = false;
20459            self.show_git_blame_inline_delay_task.take();
20460        } else {
20461            self.git_blame_inline_enabled = true;
20462            self.start_git_blame_inline(user_triggered, window, cx);
20463        }
20464
20465        cx.notify();
20466    }
20467
20468    fn start_git_blame_inline(
20469        &mut self,
20470        user_triggered: bool,
20471        window: &mut Window,
20472        cx: &mut Context<Self>,
20473    ) {
20474        self.start_git_blame(user_triggered, window, cx);
20475
20476        if ProjectSettings::get_global(cx)
20477            .git
20478            .inline_blame_delay()
20479            .is_some()
20480        {
20481            self.start_inline_blame_timer(window, cx);
20482        } else {
20483            self.show_git_blame_inline = true
20484        }
20485    }
20486
20487    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20488        self.blame.as_ref()
20489    }
20490
20491    pub fn show_git_blame_gutter(&self) -> bool {
20492        self.show_git_blame_gutter
20493    }
20494
20495    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20496        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20497    }
20498
20499    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20500        self.show_git_blame_inline
20501            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20502            && !self.newest_selection_head_on_empty_line(cx)
20503            && self.has_blame_entries(cx)
20504    }
20505
20506    fn has_blame_entries(&self, cx: &App) -> bool {
20507        self.blame()
20508            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20509    }
20510
20511    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20512        let cursor_anchor = self.selections.newest_anchor().head();
20513
20514        let snapshot = self.buffer.read(cx).snapshot(cx);
20515        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20516
20517        snapshot.line_len(buffer_row) == 0
20518    }
20519
20520    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20521        let buffer_and_selection = maybe!({
20522            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20523            let selection_range = selection.range();
20524
20525            let multi_buffer = self.buffer().read(cx);
20526            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20527            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20528
20529            let (buffer, range, _) = if selection.reversed {
20530                buffer_ranges.first()
20531            } else {
20532                buffer_ranges.last()
20533            }?;
20534
20535            let selection = text::ToPoint::to_point(&range.start, buffer).row
20536                ..text::ToPoint::to_point(&range.end, buffer).row;
20537            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20538        });
20539
20540        let Some((buffer, selection)) = buffer_and_selection else {
20541            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20542        };
20543
20544        let Some(project) = self.project() else {
20545            return Task::ready(Err(anyhow!("editor does not have project")));
20546        };
20547
20548        project.update(cx, |project, cx| {
20549            project.get_permalink_to_line(&buffer, selection, cx)
20550        })
20551    }
20552
20553    pub fn copy_permalink_to_line(
20554        &mut self,
20555        _: &CopyPermalinkToLine,
20556        window: &mut Window,
20557        cx: &mut Context<Self>,
20558    ) {
20559        let permalink_task = self.get_permalink_to_line(cx);
20560        let workspace = self.workspace();
20561
20562        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20563            Ok(permalink) => {
20564                cx.update(|_, cx| {
20565                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20566                })
20567                .ok();
20568            }
20569            Err(err) => {
20570                let message = format!("Failed to copy permalink: {err}");
20571
20572                anyhow::Result::<()>::Err(err).log_err();
20573
20574                if let Some(workspace) = workspace {
20575                    workspace
20576                        .update_in(cx, |workspace, _, cx| {
20577                            struct CopyPermalinkToLine;
20578
20579                            workspace.show_toast(
20580                                Toast::new(
20581                                    NotificationId::unique::<CopyPermalinkToLine>(),
20582                                    message,
20583                                ),
20584                                cx,
20585                            )
20586                        })
20587                        .ok();
20588                }
20589            }
20590        })
20591        .detach();
20592    }
20593
20594    pub fn copy_file_location(
20595        &mut self,
20596        _: &CopyFileLocation,
20597        _: &mut Window,
20598        cx: &mut Context<Self>,
20599    ) {
20600        let selection = self
20601            .selections
20602            .newest::<Point>(&self.display_snapshot(cx))
20603            .start
20604            .row
20605            + 1;
20606        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20607            let project = self.project()?.read(cx);
20608            let file = buffer.read(cx).file()?;
20609            let path = file.path().display(project.path_style(cx));
20610
20611            Some(format!("{path}:{selection}"))
20612        }) {
20613            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
20614        }
20615    }
20616
20617    pub fn open_permalink_to_line(
20618        &mut self,
20619        _: &OpenPermalinkToLine,
20620        window: &mut Window,
20621        cx: &mut Context<Self>,
20622    ) {
20623        let permalink_task = self.get_permalink_to_line(cx);
20624        let workspace = self.workspace();
20625
20626        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20627            Ok(permalink) => {
20628                cx.update(|_, cx| {
20629                    cx.open_url(permalink.as_ref());
20630                })
20631                .ok();
20632            }
20633            Err(err) => {
20634                let message = format!("Failed to open permalink: {err}");
20635
20636                anyhow::Result::<()>::Err(err).log_err();
20637
20638                if let Some(workspace) = workspace {
20639                    workspace
20640                        .update(cx, |workspace, cx| {
20641                            struct OpenPermalinkToLine;
20642
20643                            workspace.show_toast(
20644                                Toast::new(
20645                                    NotificationId::unique::<OpenPermalinkToLine>(),
20646                                    message,
20647                                ),
20648                                cx,
20649                            )
20650                        })
20651                        .ok();
20652                }
20653            }
20654        })
20655        .detach();
20656    }
20657
20658    pub fn insert_uuid_v4(
20659        &mut self,
20660        _: &InsertUuidV4,
20661        window: &mut Window,
20662        cx: &mut Context<Self>,
20663    ) {
20664        self.insert_uuid(UuidVersion::V4, window, cx);
20665    }
20666
20667    pub fn insert_uuid_v7(
20668        &mut self,
20669        _: &InsertUuidV7,
20670        window: &mut Window,
20671        cx: &mut Context<Self>,
20672    ) {
20673        self.insert_uuid(UuidVersion::V7, window, cx);
20674    }
20675
20676    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20677        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20678        self.transact(window, cx, |this, window, cx| {
20679            let edits = this
20680                .selections
20681                .all::<Point>(&this.display_snapshot(cx))
20682                .into_iter()
20683                .map(|selection| {
20684                    let uuid = match version {
20685                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20686                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20687                    };
20688
20689                    (selection.range(), uuid.to_string())
20690                });
20691            this.edit(edits, cx);
20692            this.refresh_edit_prediction(true, false, window, cx);
20693        });
20694    }
20695
20696    pub fn open_selections_in_multibuffer(
20697        &mut self,
20698        _: &OpenSelectionsInMultibuffer,
20699        window: &mut Window,
20700        cx: &mut Context<Self>,
20701    ) {
20702        let multibuffer = self.buffer.read(cx);
20703
20704        let Some(buffer) = multibuffer.as_singleton() else {
20705            return;
20706        };
20707
20708        let Some(workspace) = self.workspace() else {
20709            return;
20710        };
20711
20712        let title = multibuffer.title(cx).to_string();
20713
20714        let locations = self
20715            .selections
20716            .all_anchors(&self.display_snapshot(cx))
20717            .iter()
20718            .map(|selection| {
20719                (
20720                    buffer.clone(),
20721                    (selection.start.text_anchor..selection.end.text_anchor)
20722                        .to_point(buffer.read(cx)),
20723                )
20724            })
20725            .into_group_map();
20726
20727        cx.spawn_in(window, async move |_, cx| {
20728            workspace.update_in(cx, |workspace, window, cx| {
20729                Self::open_locations_in_multibuffer(
20730                    workspace,
20731                    locations,
20732                    format!("Selections for '{title}'"),
20733                    false,
20734                    MultibufferSelectionMode::All,
20735                    window,
20736                    cx,
20737                );
20738            })
20739        })
20740        .detach();
20741    }
20742
20743    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20744    /// last highlight added will be used.
20745    ///
20746    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20747    pub fn highlight_rows<T: 'static>(
20748        &mut self,
20749        range: Range<Anchor>,
20750        color: Hsla,
20751        options: RowHighlightOptions,
20752        cx: &mut Context<Self>,
20753    ) {
20754        let snapshot = self.buffer().read(cx).snapshot(cx);
20755        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20756        let ix = row_highlights.binary_search_by(|highlight| {
20757            Ordering::Equal
20758                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20759                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20760        });
20761
20762        if let Err(mut ix) = ix {
20763            let index = post_inc(&mut self.highlight_order);
20764
20765            // If this range intersects with the preceding highlight, then merge it with
20766            // the preceding highlight. Otherwise insert a new highlight.
20767            let mut merged = false;
20768            if ix > 0 {
20769                let prev_highlight = &mut row_highlights[ix - 1];
20770                if prev_highlight
20771                    .range
20772                    .end
20773                    .cmp(&range.start, &snapshot)
20774                    .is_ge()
20775                {
20776                    ix -= 1;
20777                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20778                        prev_highlight.range.end = range.end;
20779                    }
20780                    merged = true;
20781                    prev_highlight.index = index;
20782                    prev_highlight.color = color;
20783                    prev_highlight.options = options;
20784                }
20785            }
20786
20787            if !merged {
20788                row_highlights.insert(
20789                    ix,
20790                    RowHighlight {
20791                        range,
20792                        index,
20793                        color,
20794                        options,
20795                        type_id: TypeId::of::<T>(),
20796                    },
20797                );
20798            }
20799
20800            // If any of the following highlights intersect with this one, merge them.
20801            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20802                let highlight = &row_highlights[ix];
20803                if next_highlight
20804                    .range
20805                    .start
20806                    .cmp(&highlight.range.end, &snapshot)
20807                    .is_le()
20808                {
20809                    if next_highlight
20810                        .range
20811                        .end
20812                        .cmp(&highlight.range.end, &snapshot)
20813                        .is_gt()
20814                    {
20815                        row_highlights[ix].range.end = next_highlight.range.end;
20816                    }
20817                    row_highlights.remove(ix + 1);
20818                } else {
20819                    break;
20820                }
20821            }
20822        }
20823    }
20824
20825    /// Remove any highlighted row ranges of the given type that intersect the
20826    /// given ranges.
20827    pub fn remove_highlighted_rows<T: 'static>(
20828        &mut self,
20829        ranges_to_remove: Vec<Range<Anchor>>,
20830        cx: &mut Context<Self>,
20831    ) {
20832        let snapshot = self.buffer().read(cx).snapshot(cx);
20833        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20834        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20835        row_highlights.retain(|highlight| {
20836            while let Some(range_to_remove) = ranges_to_remove.peek() {
20837                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20838                    Ordering::Less | Ordering::Equal => {
20839                        ranges_to_remove.next();
20840                    }
20841                    Ordering::Greater => {
20842                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20843                            Ordering::Less | Ordering::Equal => {
20844                                return false;
20845                            }
20846                            Ordering::Greater => break,
20847                        }
20848                    }
20849                }
20850            }
20851
20852            true
20853        })
20854    }
20855
20856    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20857    pub fn clear_row_highlights<T: 'static>(&mut self) {
20858        self.highlighted_rows.remove(&TypeId::of::<T>());
20859    }
20860
20861    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20862    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20863        self.highlighted_rows
20864            .get(&TypeId::of::<T>())
20865            .map_or(&[] as &[_], |vec| vec.as_slice())
20866            .iter()
20867            .map(|highlight| (highlight.range.clone(), highlight.color))
20868    }
20869
20870    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20871    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20872    /// Allows to ignore certain kinds of highlights.
20873    pub fn highlighted_display_rows(
20874        &self,
20875        window: &mut Window,
20876        cx: &mut App,
20877    ) -> BTreeMap<DisplayRow, LineHighlight> {
20878        let snapshot = self.snapshot(window, cx);
20879        let mut used_highlight_orders = HashMap::default();
20880        self.highlighted_rows
20881            .iter()
20882            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20883            .fold(
20884                BTreeMap::<DisplayRow, LineHighlight>::new(),
20885                |mut unique_rows, highlight| {
20886                    let start = highlight.range.start.to_display_point(&snapshot);
20887                    let end = highlight.range.end.to_display_point(&snapshot);
20888                    let start_row = start.row().0;
20889                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
20890                    {
20891                        end.row().0.saturating_sub(1)
20892                    } else {
20893                        end.row().0
20894                    };
20895                    for row in start_row..=end_row {
20896                        let used_index =
20897                            used_highlight_orders.entry(row).or_insert(highlight.index);
20898                        if highlight.index >= *used_index {
20899                            *used_index = highlight.index;
20900                            unique_rows.insert(
20901                                DisplayRow(row),
20902                                LineHighlight {
20903                                    include_gutter: highlight.options.include_gutter,
20904                                    border: None,
20905                                    background: highlight.color.into(),
20906                                    type_id: Some(highlight.type_id),
20907                                },
20908                            );
20909                        }
20910                    }
20911                    unique_rows
20912                },
20913            )
20914    }
20915
20916    pub fn highlighted_display_row_for_autoscroll(
20917        &self,
20918        snapshot: &DisplaySnapshot,
20919    ) -> Option<DisplayRow> {
20920        self.highlighted_rows
20921            .values()
20922            .flat_map(|highlighted_rows| highlighted_rows.iter())
20923            .filter_map(|highlight| {
20924                if highlight.options.autoscroll {
20925                    Some(highlight.range.start.to_display_point(snapshot).row())
20926                } else {
20927                    None
20928                }
20929            })
20930            .min()
20931    }
20932
20933    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20934        self.highlight_background::<SearchWithinRange>(
20935            ranges,
20936            |colors| colors.colors().editor_document_highlight_read_background,
20937            cx,
20938        )
20939    }
20940
20941    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20942        self.breadcrumb_header = Some(new_header);
20943    }
20944
20945    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20946        self.clear_background_highlights::<SearchWithinRange>(cx);
20947    }
20948
20949    pub fn highlight_background<T: 'static>(
20950        &mut self,
20951        ranges: &[Range<Anchor>],
20952        color_fetcher: fn(&Theme) -> Hsla,
20953        cx: &mut Context<Self>,
20954    ) {
20955        self.background_highlights.insert(
20956            HighlightKey::Type(TypeId::of::<T>()),
20957            (color_fetcher, Arc::from(ranges)),
20958        );
20959        self.scrollbar_marker_state.dirty = true;
20960        cx.notify();
20961    }
20962
20963    pub fn highlight_background_key<T: 'static>(
20964        &mut self,
20965        key: usize,
20966        ranges: &[Range<Anchor>],
20967        color_fetcher: fn(&Theme) -> Hsla,
20968        cx: &mut Context<Self>,
20969    ) {
20970        self.background_highlights.insert(
20971            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20972            (color_fetcher, Arc::from(ranges)),
20973        );
20974        self.scrollbar_marker_state.dirty = true;
20975        cx.notify();
20976    }
20977
20978    pub fn clear_background_highlights<T: 'static>(
20979        &mut self,
20980        cx: &mut Context<Self>,
20981    ) -> Option<BackgroundHighlight> {
20982        let text_highlights = self
20983            .background_highlights
20984            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20985        if !text_highlights.1.is_empty() {
20986            self.scrollbar_marker_state.dirty = true;
20987            cx.notify();
20988        }
20989        Some(text_highlights)
20990    }
20991
20992    pub fn highlight_gutter<T: 'static>(
20993        &mut self,
20994        ranges: impl Into<Vec<Range<Anchor>>>,
20995        color_fetcher: fn(&App) -> Hsla,
20996        cx: &mut Context<Self>,
20997    ) {
20998        self.gutter_highlights
20999            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21000        cx.notify();
21001    }
21002
21003    pub fn clear_gutter_highlights<T: 'static>(
21004        &mut self,
21005        cx: &mut Context<Self>,
21006    ) -> Option<GutterHighlight> {
21007        cx.notify();
21008        self.gutter_highlights.remove(&TypeId::of::<T>())
21009    }
21010
21011    pub fn insert_gutter_highlight<T: 'static>(
21012        &mut self,
21013        range: Range<Anchor>,
21014        color_fetcher: fn(&App) -> Hsla,
21015        cx: &mut Context<Self>,
21016    ) {
21017        let snapshot = self.buffer().read(cx).snapshot(cx);
21018        let mut highlights = self
21019            .gutter_highlights
21020            .remove(&TypeId::of::<T>())
21021            .map(|(_, highlights)| highlights)
21022            .unwrap_or_default();
21023        let ix = highlights.binary_search_by(|highlight| {
21024            Ordering::Equal
21025                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21026                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21027        });
21028        if let Err(ix) = ix {
21029            highlights.insert(ix, range);
21030        }
21031        self.gutter_highlights
21032            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21033    }
21034
21035    pub fn remove_gutter_highlights<T: 'static>(
21036        &mut self,
21037        ranges_to_remove: Vec<Range<Anchor>>,
21038        cx: &mut Context<Self>,
21039    ) {
21040        let snapshot = self.buffer().read(cx).snapshot(cx);
21041        let Some((color_fetcher, mut gutter_highlights)) =
21042            self.gutter_highlights.remove(&TypeId::of::<T>())
21043        else {
21044            return;
21045        };
21046        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21047        gutter_highlights.retain(|highlight| {
21048            while let Some(range_to_remove) = ranges_to_remove.peek() {
21049                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21050                    Ordering::Less | Ordering::Equal => {
21051                        ranges_to_remove.next();
21052                    }
21053                    Ordering::Greater => {
21054                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21055                            Ordering::Less | Ordering::Equal => {
21056                                return false;
21057                            }
21058                            Ordering::Greater => break,
21059                        }
21060                    }
21061                }
21062            }
21063
21064            true
21065        });
21066        self.gutter_highlights
21067            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21068    }
21069
21070    #[cfg(feature = "test-support")]
21071    pub fn all_text_highlights(
21072        &self,
21073        window: &mut Window,
21074        cx: &mut Context<Self>,
21075    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21076        let snapshot = self.snapshot(window, cx);
21077        self.display_map.update(cx, |display_map, _| {
21078            display_map
21079                .all_text_highlights()
21080                .map(|highlight| {
21081                    let (style, ranges) = highlight.as_ref();
21082                    (
21083                        *style,
21084                        ranges
21085                            .iter()
21086                            .map(|range| range.clone().to_display_points(&snapshot))
21087                            .collect(),
21088                    )
21089                })
21090                .collect()
21091        })
21092    }
21093
21094    #[cfg(feature = "test-support")]
21095    pub fn all_text_background_highlights(
21096        &self,
21097        window: &mut Window,
21098        cx: &mut Context<Self>,
21099    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21100        let snapshot = self.snapshot(window, cx);
21101        let buffer = &snapshot.buffer_snapshot();
21102        let start = buffer.anchor_before(MultiBufferOffset(0));
21103        let end = buffer.anchor_after(buffer.len());
21104        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21105    }
21106
21107    #[cfg(any(test, feature = "test-support"))]
21108    pub fn sorted_background_highlights_in_range(
21109        &self,
21110        search_range: Range<Anchor>,
21111        display_snapshot: &DisplaySnapshot,
21112        theme: &Theme,
21113    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21114        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21115        res.sort_by(|a, b| {
21116            a.0.start
21117                .cmp(&b.0.start)
21118                .then_with(|| a.0.end.cmp(&b.0.end))
21119                .then_with(|| a.1.cmp(&b.1))
21120        });
21121        res
21122    }
21123
21124    #[cfg(feature = "test-support")]
21125    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21126        let snapshot = self.buffer().read(cx).snapshot(cx);
21127
21128        let highlights = self
21129            .background_highlights
21130            .get(&HighlightKey::Type(TypeId::of::<
21131                items::BufferSearchHighlights,
21132            >()));
21133
21134        if let Some((_color, ranges)) = highlights {
21135            ranges
21136                .iter()
21137                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21138                .collect_vec()
21139        } else {
21140            vec![]
21141        }
21142    }
21143
21144    fn document_highlights_for_position<'a>(
21145        &'a self,
21146        position: Anchor,
21147        buffer: &'a MultiBufferSnapshot,
21148    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21149        let read_highlights = self
21150            .background_highlights
21151            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21152            .map(|h| &h.1);
21153        let write_highlights = self
21154            .background_highlights
21155            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21156            .map(|h| &h.1);
21157        let left_position = position.bias_left(buffer);
21158        let right_position = position.bias_right(buffer);
21159        read_highlights
21160            .into_iter()
21161            .chain(write_highlights)
21162            .flat_map(move |ranges| {
21163                let start_ix = match ranges.binary_search_by(|probe| {
21164                    let cmp = probe.end.cmp(&left_position, buffer);
21165                    if cmp.is_ge() {
21166                        Ordering::Greater
21167                    } else {
21168                        Ordering::Less
21169                    }
21170                }) {
21171                    Ok(i) | Err(i) => i,
21172                };
21173
21174                ranges[start_ix..]
21175                    .iter()
21176                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21177            })
21178    }
21179
21180    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21181        self.background_highlights
21182            .get(&HighlightKey::Type(TypeId::of::<T>()))
21183            .is_some_and(|(_, highlights)| !highlights.is_empty())
21184    }
21185
21186    /// Returns all background highlights for a given range.
21187    ///
21188    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21189    pub fn background_highlights_in_range(
21190        &self,
21191        search_range: Range<Anchor>,
21192        display_snapshot: &DisplaySnapshot,
21193        theme: &Theme,
21194    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21195        let mut results = Vec::new();
21196        for (color_fetcher, ranges) in self.background_highlights.values() {
21197            let color = color_fetcher(theme);
21198            let start_ix = match ranges.binary_search_by(|probe| {
21199                let cmp = probe
21200                    .end
21201                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21202                if cmp.is_gt() {
21203                    Ordering::Greater
21204                } else {
21205                    Ordering::Less
21206                }
21207            }) {
21208                Ok(i) | Err(i) => i,
21209            };
21210            for range in &ranges[start_ix..] {
21211                if range
21212                    .start
21213                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21214                    .is_ge()
21215                {
21216                    break;
21217                }
21218
21219                let start = range.start.to_display_point(display_snapshot);
21220                let end = range.end.to_display_point(display_snapshot);
21221                results.push((start..end, color))
21222            }
21223        }
21224        results
21225    }
21226
21227    pub fn gutter_highlights_in_range(
21228        &self,
21229        search_range: Range<Anchor>,
21230        display_snapshot: &DisplaySnapshot,
21231        cx: &App,
21232    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21233        let mut results = Vec::new();
21234        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21235            let color = color_fetcher(cx);
21236            let start_ix = match ranges.binary_search_by(|probe| {
21237                let cmp = probe
21238                    .end
21239                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21240                if cmp.is_gt() {
21241                    Ordering::Greater
21242                } else {
21243                    Ordering::Less
21244                }
21245            }) {
21246                Ok(i) | Err(i) => i,
21247            };
21248            for range in &ranges[start_ix..] {
21249                if range
21250                    .start
21251                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21252                    .is_ge()
21253                {
21254                    break;
21255                }
21256
21257                let start = range.start.to_display_point(display_snapshot);
21258                let end = range.end.to_display_point(display_snapshot);
21259                results.push((start..end, color))
21260            }
21261        }
21262        results
21263    }
21264
21265    /// Get the text ranges corresponding to the redaction query
21266    pub fn redacted_ranges(
21267        &self,
21268        search_range: Range<Anchor>,
21269        display_snapshot: &DisplaySnapshot,
21270        cx: &App,
21271    ) -> Vec<Range<DisplayPoint>> {
21272        display_snapshot
21273            .buffer_snapshot()
21274            .redacted_ranges(search_range, |file| {
21275                if let Some(file) = file {
21276                    file.is_private()
21277                        && EditorSettings::get(
21278                            Some(SettingsLocation {
21279                                worktree_id: file.worktree_id(cx),
21280                                path: file.path().as_ref(),
21281                            }),
21282                            cx,
21283                        )
21284                        .redact_private_values
21285                } else {
21286                    false
21287                }
21288            })
21289            .map(|range| {
21290                range.start.to_display_point(display_snapshot)
21291                    ..range.end.to_display_point(display_snapshot)
21292            })
21293            .collect()
21294    }
21295
21296    pub fn highlight_text_key<T: 'static>(
21297        &mut self,
21298        key: usize,
21299        ranges: Vec<Range<Anchor>>,
21300        style: HighlightStyle,
21301        merge: bool,
21302        cx: &mut Context<Self>,
21303    ) {
21304        self.display_map.update(cx, |map, cx| {
21305            map.highlight_text(
21306                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21307                ranges,
21308                style,
21309                merge,
21310                cx,
21311            );
21312        });
21313        cx.notify();
21314    }
21315
21316    pub fn highlight_text<T: 'static>(
21317        &mut self,
21318        ranges: Vec<Range<Anchor>>,
21319        style: HighlightStyle,
21320        cx: &mut Context<Self>,
21321    ) {
21322        self.display_map.update(cx, |map, cx| {
21323            map.highlight_text(
21324                HighlightKey::Type(TypeId::of::<T>()),
21325                ranges,
21326                style,
21327                false,
21328                cx,
21329            )
21330        });
21331        cx.notify();
21332    }
21333
21334    pub fn text_highlights<'a, T: 'static>(
21335        &'a self,
21336        cx: &'a App,
21337    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21338        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21339    }
21340
21341    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21342        let cleared = self
21343            .display_map
21344            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21345        if cleared {
21346            cx.notify();
21347        }
21348    }
21349
21350    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21351        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21352            && self.focus_handle.is_focused(window)
21353    }
21354
21355    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21356        self.show_cursor_when_unfocused = is_enabled;
21357        cx.notify();
21358    }
21359
21360    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21361        cx.notify();
21362    }
21363
21364    fn on_debug_session_event(
21365        &mut self,
21366        _session: Entity<Session>,
21367        event: &SessionEvent,
21368        cx: &mut Context<Self>,
21369    ) {
21370        if let SessionEvent::InvalidateInlineValue = event {
21371            self.refresh_inline_values(cx);
21372        }
21373    }
21374
21375    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21376        let Some(project) = self.project.clone() else {
21377            return;
21378        };
21379
21380        if !self.inline_value_cache.enabled {
21381            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21382            self.splice_inlays(&inlays, Vec::new(), cx);
21383            return;
21384        }
21385
21386        let current_execution_position = self
21387            .highlighted_rows
21388            .get(&TypeId::of::<ActiveDebugLine>())
21389            .and_then(|lines| lines.last().map(|line| line.range.end));
21390
21391        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21392            let inline_values = editor
21393                .update(cx, |editor, cx| {
21394                    let Some(current_execution_position) = current_execution_position else {
21395                        return Some(Task::ready(Ok(Vec::new())));
21396                    };
21397
21398                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21399                        let snapshot = buffer.snapshot(cx);
21400
21401                        let excerpt = snapshot.excerpt_containing(
21402                            current_execution_position..current_execution_position,
21403                        )?;
21404
21405                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21406                    })?;
21407
21408                    let range =
21409                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21410
21411                    project.inline_values(buffer, range, cx)
21412                })
21413                .ok()
21414                .flatten()?
21415                .await
21416                .context("refreshing debugger inlays")
21417                .log_err()?;
21418
21419            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21420
21421            for (buffer_id, inline_value) in inline_values
21422                .into_iter()
21423                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21424            {
21425                buffer_inline_values
21426                    .entry(buffer_id)
21427                    .or_default()
21428                    .push(inline_value);
21429            }
21430
21431            editor
21432                .update(cx, |editor, cx| {
21433                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21434                    let mut new_inlays = Vec::default();
21435
21436                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21437                        let buffer_id = buffer_snapshot.remote_id();
21438                        buffer_inline_values
21439                            .get(&buffer_id)
21440                            .into_iter()
21441                            .flatten()
21442                            .for_each(|hint| {
21443                                let inlay = Inlay::debugger(
21444                                    post_inc(&mut editor.next_inlay_id),
21445                                    Anchor::in_buffer(excerpt_id, hint.position),
21446                                    hint.text(),
21447                                );
21448                                if !inlay.text().chars().contains(&'\n') {
21449                                    new_inlays.push(inlay);
21450                                }
21451                            });
21452                    }
21453
21454                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21455                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21456
21457                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21458                })
21459                .ok()?;
21460            Some(())
21461        });
21462    }
21463
21464    fn on_buffer_event(
21465        &mut self,
21466        multibuffer: &Entity<MultiBuffer>,
21467        event: &multi_buffer::Event,
21468        window: &mut Window,
21469        cx: &mut Context<Self>,
21470    ) {
21471        match event {
21472            multi_buffer::Event::Edited { edited_buffer } => {
21473                self.scrollbar_marker_state.dirty = true;
21474                self.active_indent_guides_state.dirty = true;
21475                self.refresh_active_diagnostics(cx);
21476                self.refresh_code_actions(window, cx);
21477                self.refresh_single_line_folds(window, cx);
21478                self.refresh_matching_bracket_highlights(window, cx);
21479                if self.has_active_edit_prediction() {
21480                    self.update_visible_edit_prediction(window, cx);
21481                }
21482
21483                if let Some(buffer) = edited_buffer {
21484                    if buffer.read(cx).file().is_none() {
21485                        cx.emit(EditorEvent::TitleChanged);
21486                    }
21487
21488                    if self.project.is_some() {
21489                        let buffer_id = buffer.read(cx).remote_id();
21490                        self.register_buffer(buffer_id, cx);
21491                        self.update_lsp_data(Some(buffer_id), window, cx);
21492                        self.refresh_inlay_hints(
21493                            InlayHintRefreshReason::BufferEdited(buffer_id),
21494                            cx,
21495                        );
21496                    }
21497                }
21498
21499                cx.emit(EditorEvent::BufferEdited);
21500                cx.emit(SearchEvent::MatchesInvalidated);
21501
21502                let Some(project) = &self.project else { return };
21503                let (telemetry, is_via_ssh) = {
21504                    let project = project.read(cx);
21505                    let telemetry = project.client().telemetry().clone();
21506                    let is_via_ssh = project.is_via_remote_server();
21507                    (telemetry, is_via_ssh)
21508                };
21509                telemetry.log_edit_event("editor", is_via_ssh);
21510            }
21511            multi_buffer::Event::ExcerptsAdded {
21512                buffer,
21513                predecessor,
21514                excerpts,
21515            } => {
21516                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21517                let buffer_id = buffer.read(cx).remote_id();
21518                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21519                    && let Some(project) = &self.project
21520                {
21521                    update_uncommitted_diff_for_buffer(
21522                        cx.entity(),
21523                        project,
21524                        [buffer.clone()],
21525                        self.buffer.clone(),
21526                        cx,
21527                    )
21528                    .detach();
21529                }
21530                self.update_lsp_data(Some(buffer_id), window, cx);
21531                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21532                self.colorize_brackets(false, cx);
21533                cx.emit(EditorEvent::ExcerptsAdded {
21534                    buffer: buffer.clone(),
21535                    predecessor: *predecessor,
21536                    excerpts: excerpts.clone(),
21537                });
21538            }
21539            multi_buffer::Event::ExcerptsRemoved {
21540                ids,
21541                removed_buffer_ids,
21542            } => {
21543                if let Some(inlay_hints) = &mut self.inlay_hints {
21544                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21545                }
21546                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21547                for buffer_id in removed_buffer_ids {
21548                    self.registered_buffers.remove(buffer_id);
21549                }
21550                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21551                cx.emit(EditorEvent::ExcerptsRemoved {
21552                    ids: ids.clone(),
21553                    removed_buffer_ids: removed_buffer_ids.clone(),
21554                });
21555            }
21556            multi_buffer::Event::ExcerptsEdited {
21557                excerpt_ids,
21558                buffer_ids,
21559            } => {
21560                self.display_map.update(cx, |map, cx| {
21561                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21562                });
21563                cx.emit(EditorEvent::ExcerptsEdited {
21564                    ids: excerpt_ids.clone(),
21565                });
21566            }
21567            multi_buffer::Event::ExcerptsExpanded { ids } => {
21568                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21569                self.refresh_document_highlights(cx);
21570                for id in ids {
21571                    self.fetched_tree_sitter_chunks.remove(id);
21572                }
21573                self.colorize_brackets(false, cx);
21574                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21575            }
21576            multi_buffer::Event::Reparsed(buffer_id) => {
21577                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21578                self.refresh_selected_text_highlights(true, window, cx);
21579                self.colorize_brackets(true, cx);
21580                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21581
21582                cx.emit(EditorEvent::Reparsed(*buffer_id));
21583            }
21584            multi_buffer::Event::DiffHunksToggled => {
21585                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21586            }
21587            multi_buffer::Event::LanguageChanged(buffer_id) => {
21588                self.registered_buffers.remove(&buffer_id);
21589                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21590                cx.emit(EditorEvent::Reparsed(*buffer_id));
21591                cx.notify();
21592            }
21593            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21594            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21595            multi_buffer::Event::FileHandleChanged
21596            | multi_buffer::Event::Reloaded
21597            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21598            multi_buffer::Event::DiagnosticsUpdated => {
21599                self.update_diagnostics_state(window, cx);
21600            }
21601            _ => {}
21602        };
21603    }
21604
21605    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21606        if !self.diagnostics_enabled() {
21607            return;
21608        }
21609        self.refresh_active_diagnostics(cx);
21610        self.refresh_inline_diagnostics(true, window, cx);
21611        self.scrollbar_marker_state.dirty = true;
21612        cx.notify();
21613    }
21614
21615    pub fn start_temporary_diff_override(&mut self) {
21616        self.load_diff_task.take();
21617        self.temporary_diff_override = true;
21618    }
21619
21620    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21621        self.temporary_diff_override = false;
21622        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21623        self.buffer.update(cx, |buffer, cx| {
21624            buffer.set_all_diff_hunks_collapsed(cx);
21625        });
21626
21627        if let Some(project) = self.project.clone() {
21628            self.load_diff_task = Some(
21629                update_uncommitted_diff_for_buffer(
21630                    cx.entity(),
21631                    &project,
21632                    self.buffer.read(cx).all_buffers(),
21633                    self.buffer.clone(),
21634                    cx,
21635                )
21636                .shared(),
21637            );
21638        }
21639    }
21640
21641    fn on_display_map_changed(
21642        &mut self,
21643        _: Entity<DisplayMap>,
21644        _: &mut Window,
21645        cx: &mut Context<Self>,
21646    ) {
21647        cx.notify();
21648    }
21649
21650    fn fetch_accent_overrides(&self, cx: &App) -> Vec<SharedString> {
21651        if !self.mode.is_full() {
21652            return Vec::new();
21653        }
21654
21655        let theme_settings = theme::ThemeSettings::get_global(cx);
21656
21657        theme_settings
21658            .theme_overrides
21659            .get(cx.theme().name.as_ref())
21660            .map(|theme_style| &theme_style.accents)
21661            .into_iter()
21662            .flatten()
21663            .chain(
21664                theme_settings
21665                    .experimental_theme_overrides
21666                    .as_ref()
21667                    .map(|overrides| &overrides.accents)
21668                    .into_iter()
21669                    .flatten(),
21670            )
21671            .flat_map(|accent| accent.0.clone())
21672            .collect()
21673    }
21674
21675    fn fetch_applicable_language_settings(
21676        &self,
21677        cx: &App,
21678    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
21679        if !self.mode.is_full() {
21680            return HashMap::default();
21681        }
21682
21683        self.buffer().read(cx).all_buffers().into_iter().fold(
21684            HashMap::default(),
21685            |mut acc, buffer| {
21686                let buffer = buffer.read(cx);
21687                let language = buffer.language().map(|language| language.name());
21688                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
21689                    let file = buffer.file();
21690                    v.insert(language_settings(language, file, cx).into_owned());
21691                }
21692                acc
21693            },
21694        )
21695    }
21696
21697    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21698        let new_language_settings = self.fetch_applicable_language_settings(cx);
21699        let language_settings_changed = new_language_settings != self.applicable_language_settings;
21700        self.applicable_language_settings = new_language_settings;
21701
21702        let new_accent_overrides = self.fetch_accent_overrides(cx);
21703        let accent_overrides_changed = new_accent_overrides != self.accent_overrides;
21704        self.accent_overrides = new_accent_overrides;
21705
21706        if self.diagnostics_enabled() {
21707            let new_severity = EditorSettings::get_global(cx)
21708                .diagnostics_max_severity
21709                .unwrap_or(DiagnosticSeverity::Hint);
21710            self.set_max_diagnostics_severity(new_severity, cx);
21711        }
21712        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21713        self.update_edit_prediction_settings(cx);
21714        self.refresh_edit_prediction(true, false, window, cx);
21715        self.refresh_inline_values(cx);
21716        self.refresh_inlay_hints(
21717            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21718                self.selections.newest_anchor().head(),
21719                &self.buffer.read(cx).snapshot(cx),
21720                cx,
21721            )),
21722            cx,
21723        );
21724
21725        let old_cursor_shape = self.cursor_shape;
21726        let old_show_breadcrumbs = self.show_breadcrumbs;
21727
21728        {
21729            let editor_settings = EditorSettings::get_global(cx);
21730            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21731            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21732            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21733            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21734        }
21735
21736        if old_cursor_shape != self.cursor_shape {
21737            cx.emit(EditorEvent::CursorShapeChanged);
21738        }
21739
21740        if old_show_breadcrumbs != self.show_breadcrumbs {
21741            cx.emit(EditorEvent::BreadcrumbsChanged);
21742        }
21743
21744        let project_settings = ProjectSettings::get_global(cx);
21745        self.buffer_serialization = self
21746            .should_serialize_buffer()
21747            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21748
21749        if self.mode.is_full() {
21750            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21751            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21752            if self.show_inline_diagnostics != show_inline_diagnostics {
21753                self.show_inline_diagnostics = show_inline_diagnostics;
21754                self.refresh_inline_diagnostics(false, window, cx);
21755            }
21756
21757            if self.git_blame_inline_enabled != inline_blame_enabled {
21758                self.toggle_git_blame_inline_internal(false, window, cx);
21759            }
21760
21761            let minimap_settings = EditorSettings::get_global(cx).minimap;
21762            if self.minimap_visibility != MinimapVisibility::Disabled {
21763                if self.minimap_visibility.settings_visibility()
21764                    != minimap_settings.minimap_enabled()
21765                {
21766                    self.set_minimap_visibility(
21767                        MinimapVisibility::for_mode(self.mode(), cx),
21768                        window,
21769                        cx,
21770                    );
21771                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21772                    minimap_entity.update(cx, |minimap_editor, cx| {
21773                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21774                    })
21775                }
21776            }
21777
21778            if language_settings_changed || accent_overrides_changed {
21779                self.colorize_brackets(true, cx);
21780            }
21781
21782            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21783                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21784            }) {
21785                if !inlay_splice.is_empty() {
21786                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21787                }
21788                self.refresh_colors_for_visible_range(None, window, cx);
21789            }
21790        }
21791
21792        cx.notify();
21793    }
21794
21795    pub fn set_searchable(&mut self, searchable: bool) {
21796        self.searchable = searchable;
21797    }
21798
21799    pub fn searchable(&self) -> bool {
21800        self.searchable
21801    }
21802
21803    pub fn open_excerpts_in_split(
21804        &mut self,
21805        _: &OpenExcerptsSplit,
21806        window: &mut Window,
21807        cx: &mut Context<Self>,
21808    ) {
21809        self.open_excerpts_common(None, true, window, cx)
21810    }
21811
21812    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21813        self.open_excerpts_common(None, false, window, cx)
21814    }
21815
21816    fn open_excerpts_common(
21817        &mut self,
21818        jump_data: Option<JumpData>,
21819        split: bool,
21820        window: &mut Window,
21821        cx: &mut Context<Self>,
21822    ) {
21823        let Some(workspace) = self.workspace() else {
21824            cx.propagate();
21825            return;
21826        };
21827
21828        if self.buffer.read(cx).is_singleton() {
21829            cx.propagate();
21830            return;
21831        }
21832
21833        let mut new_selections_by_buffer = HashMap::default();
21834        match &jump_data {
21835            Some(JumpData::MultiBufferPoint {
21836                excerpt_id,
21837                position,
21838                anchor,
21839                line_offset_from_top,
21840            }) => {
21841                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21842                if let Some(buffer) = multi_buffer_snapshot
21843                    .buffer_id_for_excerpt(*excerpt_id)
21844                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21845                {
21846                    let buffer_snapshot = buffer.read(cx).snapshot();
21847                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21848                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21849                    } else {
21850                        buffer_snapshot.clip_point(*position, Bias::Left)
21851                    };
21852                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21853                    new_selections_by_buffer.insert(
21854                        buffer,
21855                        (
21856                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
21857                            Some(*line_offset_from_top),
21858                        ),
21859                    );
21860                }
21861            }
21862            Some(JumpData::MultiBufferRow {
21863                row,
21864                line_offset_from_top,
21865            }) => {
21866                let point = MultiBufferPoint::new(row.0, 0);
21867                if let Some((buffer, buffer_point, _)) =
21868                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21869                {
21870                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21871                    new_selections_by_buffer
21872                        .entry(buffer)
21873                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21874                        .0
21875                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
21876                }
21877            }
21878            None => {
21879                let selections = self
21880                    .selections
21881                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
21882                let multi_buffer = self.buffer.read(cx);
21883                for selection in selections {
21884                    for (snapshot, range, _, anchor) in multi_buffer
21885                        .snapshot(cx)
21886                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21887                    {
21888                        if let Some(anchor) = anchor {
21889                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21890                            else {
21891                                continue;
21892                            };
21893                            let offset = text::ToOffset::to_offset(
21894                                &anchor.text_anchor,
21895                                &buffer_handle.read(cx).snapshot(),
21896                            );
21897                            let range = BufferOffset(offset)..BufferOffset(offset);
21898                            new_selections_by_buffer
21899                                .entry(buffer_handle)
21900                                .or_insert((Vec::new(), None))
21901                                .0
21902                                .push(range)
21903                        } else {
21904                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21905                            else {
21906                                continue;
21907                            };
21908                            new_selections_by_buffer
21909                                .entry(buffer_handle)
21910                                .or_insert((Vec::new(), None))
21911                                .0
21912                                .push(range)
21913                        }
21914                    }
21915                }
21916            }
21917        }
21918
21919        new_selections_by_buffer
21920            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21921
21922        if new_selections_by_buffer.is_empty() {
21923            return;
21924        }
21925
21926        // We defer the pane interaction because we ourselves are a workspace item
21927        // and activating a new item causes the pane to call a method on us reentrantly,
21928        // which panics if we're on the stack.
21929        window.defer(cx, move |window, cx| {
21930            workspace.update(cx, |workspace, cx| {
21931                let pane = if split {
21932                    workspace.adjacent_pane(window, cx)
21933                } else {
21934                    workspace.active_pane().clone()
21935                };
21936
21937                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21938                    let editor = buffer
21939                        .read(cx)
21940                        .file()
21941                        .is_none()
21942                        .then(|| {
21943                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21944                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21945                            // Instead, we try to activate the existing editor in the pane first.
21946                            let (editor, pane_item_index) =
21947                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21948                                    let editor = item.downcast::<Editor>()?;
21949                                    let singleton_buffer =
21950                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21951                                    if singleton_buffer == buffer {
21952                                        Some((editor, i))
21953                                    } else {
21954                                        None
21955                                    }
21956                                })?;
21957                            pane.update(cx, |pane, cx| {
21958                                pane.activate_item(pane_item_index, true, true, window, cx)
21959                            });
21960                            Some(editor)
21961                        })
21962                        .flatten()
21963                        .unwrap_or_else(|| {
21964                            workspace.open_project_item::<Self>(
21965                                pane.clone(),
21966                                buffer,
21967                                true,
21968                                true,
21969                                window,
21970                                cx,
21971                            )
21972                        });
21973
21974                    editor.update(cx, |editor, cx| {
21975                        let autoscroll = match scroll_offset {
21976                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21977                            None => Autoscroll::newest(),
21978                        };
21979                        let nav_history = editor.nav_history.take();
21980                        editor.change_selections(
21981                            SelectionEffects::scroll(autoscroll),
21982                            window,
21983                            cx,
21984                            |s| {
21985                                s.select_ranges(ranges.into_iter().map(|range| {
21986                                    // we checked that the editor is a singleton editor so the offsets are valid
21987                                    MultiBufferOffset(range.start.0)..MultiBufferOffset(range.end.0)
21988                                }));
21989                            },
21990                        );
21991                        editor.nav_history = nav_history;
21992                    });
21993                }
21994            })
21995        });
21996    }
21997
21998    // For now, don't allow opening excerpts in buffers that aren't backed by
21999    // regular project files.
22000    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
22001        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
22002    }
22003
22004    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22005        let snapshot = self.buffer.read(cx).read(cx);
22006        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22007        Some(
22008            ranges
22009                .iter()
22010                .map(move |range| {
22011                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22012                })
22013                .collect(),
22014        )
22015    }
22016
22017    fn selection_replacement_ranges(
22018        &self,
22019        range: Range<MultiBufferOffsetUtf16>,
22020        cx: &mut App,
22021    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22022        let selections = self
22023            .selections
22024            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22025        let newest_selection = selections
22026            .iter()
22027            .max_by_key(|selection| selection.id)
22028            .unwrap();
22029        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22030        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22031        let snapshot = self.buffer.read(cx).read(cx);
22032        selections
22033            .into_iter()
22034            .map(|mut selection| {
22035                selection.start.0.0 =
22036                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22037                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22038                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22039                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22040            })
22041            .collect()
22042    }
22043
22044    fn report_editor_event(
22045        &self,
22046        reported_event: ReportEditorEvent,
22047        file_extension: Option<String>,
22048        cx: &App,
22049    ) {
22050        if cfg!(any(test, feature = "test-support")) {
22051            return;
22052        }
22053
22054        let Some(project) = &self.project else { return };
22055
22056        // If None, we are in a file without an extension
22057        let file = self
22058            .buffer
22059            .read(cx)
22060            .as_singleton()
22061            .and_then(|b| b.read(cx).file());
22062        let file_extension = file_extension.or(file
22063            .as_ref()
22064            .and_then(|file| Path::new(file.file_name(cx)).extension())
22065            .and_then(|e| e.to_str())
22066            .map(|a| a.to_string()));
22067
22068        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22069            .map(|vim_mode| vim_mode.0)
22070            .unwrap_or(false);
22071
22072        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22073        let copilot_enabled = edit_predictions_provider
22074            == language::language_settings::EditPredictionProvider::Copilot;
22075        let copilot_enabled_for_language = self
22076            .buffer
22077            .read(cx)
22078            .language_settings(cx)
22079            .show_edit_predictions;
22080
22081        let project = project.read(cx);
22082        let event_type = reported_event.event_type();
22083
22084        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22085            telemetry::event!(
22086                event_type,
22087                type = if auto_saved {"autosave"} else {"manual"},
22088                file_extension,
22089                vim_mode,
22090                copilot_enabled,
22091                copilot_enabled_for_language,
22092                edit_predictions_provider,
22093                is_via_ssh = project.is_via_remote_server(),
22094            );
22095        } else {
22096            telemetry::event!(
22097                event_type,
22098                file_extension,
22099                vim_mode,
22100                copilot_enabled,
22101                copilot_enabled_for_language,
22102                edit_predictions_provider,
22103                is_via_ssh = project.is_via_remote_server(),
22104            );
22105        };
22106    }
22107
22108    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22109    /// with each line being an array of {text, highlight} objects.
22110    fn copy_highlight_json(
22111        &mut self,
22112        _: &CopyHighlightJson,
22113        window: &mut Window,
22114        cx: &mut Context<Self>,
22115    ) {
22116        #[derive(Serialize)]
22117        struct Chunk<'a> {
22118            text: String,
22119            highlight: Option<&'a str>,
22120        }
22121
22122        let snapshot = self.buffer.read(cx).snapshot(cx);
22123        let range = self
22124            .selected_text_range(false, window, cx)
22125            .and_then(|selection| {
22126                if selection.range.is_empty() {
22127                    None
22128                } else {
22129                    Some(
22130                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22131                            selection.range.start,
22132                        )))
22133                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22134                                selection.range.end,
22135                            ))),
22136                    )
22137                }
22138            })
22139            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22140
22141        let chunks = snapshot.chunks(range, true);
22142        let mut lines = Vec::new();
22143        let mut line: VecDeque<Chunk> = VecDeque::new();
22144
22145        let Some(style) = self.style.as_ref() else {
22146            return;
22147        };
22148
22149        for chunk in chunks {
22150            let highlight = chunk
22151                .syntax_highlight_id
22152                .and_then(|id| id.name(&style.syntax));
22153            let mut chunk_lines = chunk.text.split('\n').peekable();
22154            while let Some(text) = chunk_lines.next() {
22155                let mut merged_with_last_token = false;
22156                if let Some(last_token) = line.back_mut()
22157                    && last_token.highlight == highlight
22158                {
22159                    last_token.text.push_str(text);
22160                    merged_with_last_token = true;
22161                }
22162
22163                if !merged_with_last_token {
22164                    line.push_back(Chunk {
22165                        text: text.into(),
22166                        highlight,
22167                    });
22168                }
22169
22170                if chunk_lines.peek().is_some() {
22171                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22172                        line.pop_front();
22173                    }
22174                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22175                        line.pop_back();
22176                    }
22177
22178                    lines.push(mem::take(&mut line));
22179                }
22180            }
22181        }
22182
22183        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22184            return;
22185        };
22186        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22187    }
22188
22189    pub fn open_context_menu(
22190        &mut self,
22191        _: &OpenContextMenu,
22192        window: &mut Window,
22193        cx: &mut Context<Self>,
22194    ) {
22195        self.request_autoscroll(Autoscroll::newest(), cx);
22196        let position = self
22197            .selections
22198            .newest_display(&self.display_snapshot(cx))
22199            .start;
22200        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22201    }
22202
22203    pub fn replay_insert_event(
22204        &mut self,
22205        text: &str,
22206        relative_utf16_range: Option<Range<isize>>,
22207        window: &mut Window,
22208        cx: &mut Context<Self>,
22209    ) {
22210        if !self.input_enabled {
22211            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22212            return;
22213        }
22214        if let Some(relative_utf16_range) = relative_utf16_range {
22215            let selections = self
22216                .selections
22217                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22218            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22219                let new_ranges = selections.into_iter().map(|range| {
22220                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22221                        range
22222                            .head()
22223                            .0
22224                            .0
22225                            .saturating_add_signed(relative_utf16_range.start),
22226                    ));
22227                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22228                        range
22229                            .head()
22230                            .0
22231                            .0
22232                            .saturating_add_signed(relative_utf16_range.end),
22233                    ));
22234                    start..end
22235                });
22236                s.select_ranges(new_ranges);
22237            });
22238        }
22239
22240        self.handle_input(text, window, cx);
22241    }
22242
22243    pub fn is_focused(&self, window: &Window) -> bool {
22244        self.focus_handle.is_focused(window)
22245    }
22246
22247    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22248        cx.emit(EditorEvent::Focused);
22249
22250        if let Some(descendant) = self
22251            .last_focused_descendant
22252            .take()
22253            .and_then(|descendant| descendant.upgrade())
22254        {
22255            window.focus(&descendant);
22256        } else {
22257            if let Some(blame) = self.blame.as_ref() {
22258                blame.update(cx, GitBlame::focus)
22259            }
22260
22261            self.blink_manager.update(cx, BlinkManager::enable);
22262            self.show_cursor_names(window, cx);
22263            self.buffer.update(cx, |buffer, cx| {
22264                buffer.finalize_last_transaction(cx);
22265                if self.leader_id.is_none() {
22266                    buffer.set_active_selections(
22267                        &self.selections.disjoint_anchors_arc(),
22268                        self.selections.line_mode(),
22269                        self.cursor_shape,
22270                        cx,
22271                    );
22272                }
22273            });
22274
22275            if let Some(position_map) = self.last_position_map.clone() {
22276                EditorElement::mouse_moved(
22277                    self,
22278                    &MouseMoveEvent {
22279                        position: window.mouse_position(),
22280                        pressed_button: None,
22281                        modifiers: window.modifiers(),
22282                    },
22283                    &position_map,
22284                    window,
22285                    cx,
22286                );
22287            }
22288        }
22289    }
22290
22291    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22292        cx.emit(EditorEvent::FocusedIn)
22293    }
22294
22295    fn handle_focus_out(
22296        &mut self,
22297        event: FocusOutEvent,
22298        _window: &mut Window,
22299        cx: &mut Context<Self>,
22300    ) {
22301        if event.blurred != self.focus_handle {
22302            self.last_focused_descendant = Some(event.blurred);
22303        }
22304        self.selection_drag_state = SelectionDragState::None;
22305        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22306    }
22307
22308    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22309        self.blink_manager.update(cx, BlinkManager::disable);
22310        self.buffer
22311            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22312
22313        if let Some(blame) = self.blame.as_ref() {
22314            blame.update(cx, GitBlame::blur)
22315        }
22316        if !self.hover_state.focused(window, cx) {
22317            hide_hover(self, cx);
22318        }
22319        if !self
22320            .context_menu
22321            .borrow()
22322            .as_ref()
22323            .is_some_and(|context_menu| context_menu.focused(window, cx))
22324        {
22325            self.hide_context_menu(window, cx);
22326        }
22327        self.take_active_edit_prediction(cx);
22328        cx.emit(EditorEvent::Blurred);
22329        cx.notify();
22330    }
22331
22332    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22333        let mut pending: String = window
22334            .pending_input_keystrokes()
22335            .into_iter()
22336            .flatten()
22337            .filter_map(|keystroke| keystroke.key_char.clone())
22338            .collect();
22339
22340        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22341            pending = "".to_string();
22342        }
22343
22344        let existing_pending = self
22345            .text_highlights::<PendingInput>(cx)
22346            .map(|(_, ranges)| ranges.to_vec());
22347        if existing_pending.is_none() && pending.is_empty() {
22348            return;
22349        }
22350        let transaction =
22351            self.transact(window, cx, |this, window, cx| {
22352                let selections = this
22353                    .selections
22354                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22355                let edits = selections
22356                    .iter()
22357                    .map(|selection| (selection.end..selection.end, pending.clone()));
22358                this.edit(edits, cx);
22359                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22360                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22361                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22362                    }));
22363                });
22364                if let Some(existing_ranges) = existing_pending {
22365                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22366                    this.edit(edits, cx);
22367                }
22368            });
22369
22370        let snapshot = self.snapshot(window, cx);
22371        let ranges = self
22372            .selections
22373            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22374            .into_iter()
22375            .map(|selection| {
22376                snapshot.buffer_snapshot().anchor_after(selection.end)
22377                    ..snapshot
22378                        .buffer_snapshot()
22379                        .anchor_before(selection.end + pending.len())
22380            })
22381            .collect();
22382
22383        if pending.is_empty() {
22384            self.clear_highlights::<PendingInput>(cx);
22385        } else {
22386            self.highlight_text::<PendingInput>(
22387                ranges,
22388                HighlightStyle {
22389                    underline: Some(UnderlineStyle {
22390                        thickness: px(1.),
22391                        color: None,
22392                        wavy: false,
22393                    }),
22394                    ..Default::default()
22395                },
22396                cx,
22397            );
22398        }
22399
22400        self.ime_transaction = self.ime_transaction.or(transaction);
22401        if let Some(transaction) = self.ime_transaction {
22402            self.buffer.update(cx, |buffer, cx| {
22403                buffer.group_until_transaction(transaction, cx);
22404            });
22405        }
22406
22407        if self.text_highlights::<PendingInput>(cx).is_none() {
22408            self.ime_transaction.take();
22409        }
22410    }
22411
22412    pub fn register_action_renderer(
22413        &mut self,
22414        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22415    ) -> Subscription {
22416        let id = self.next_editor_action_id.post_inc();
22417        self.editor_actions
22418            .borrow_mut()
22419            .insert(id, Box::new(listener));
22420
22421        let editor_actions = self.editor_actions.clone();
22422        Subscription::new(move || {
22423            editor_actions.borrow_mut().remove(&id);
22424        })
22425    }
22426
22427    pub fn register_action<A: Action>(
22428        &mut self,
22429        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22430    ) -> Subscription {
22431        let id = self.next_editor_action_id.post_inc();
22432        let listener = Arc::new(listener);
22433        self.editor_actions.borrow_mut().insert(
22434            id,
22435            Box::new(move |_, window, _| {
22436                let listener = listener.clone();
22437                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22438                    let action = action.downcast_ref().unwrap();
22439                    if phase == DispatchPhase::Bubble {
22440                        listener(action, window, cx)
22441                    }
22442                })
22443            }),
22444        );
22445
22446        let editor_actions = self.editor_actions.clone();
22447        Subscription::new(move || {
22448            editor_actions.borrow_mut().remove(&id);
22449        })
22450    }
22451
22452    pub fn file_header_size(&self) -> u32 {
22453        FILE_HEADER_HEIGHT
22454    }
22455
22456    pub fn restore(
22457        &mut self,
22458        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22459        window: &mut Window,
22460        cx: &mut Context<Self>,
22461    ) {
22462        let workspace = self.workspace();
22463        let project = self.project();
22464        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22465            let mut tasks = Vec::new();
22466            for (buffer_id, changes) in revert_changes {
22467                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22468                    buffer.update(cx, |buffer, cx| {
22469                        buffer.edit(
22470                            changes
22471                                .into_iter()
22472                                .map(|(range, text)| (range, text.to_string())),
22473                            None,
22474                            cx,
22475                        );
22476                    });
22477
22478                    if let Some(project) =
22479                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22480                    {
22481                        project.update(cx, |project, cx| {
22482                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22483                        })
22484                    }
22485                }
22486            }
22487            tasks
22488        });
22489        cx.spawn_in(window, async move |_, cx| {
22490            for (buffer, task) in save_tasks {
22491                let result = task.await;
22492                if result.is_err() {
22493                    let Some(path) = buffer
22494                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22495                        .ok()
22496                    else {
22497                        continue;
22498                    };
22499                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22500                        let Some(task) = cx
22501                            .update_window_entity(workspace, |workspace, window, cx| {
22502                                workspace
22503                                    .open_path_preview(path, None, false, false, false, window, cx)
22504                            })
22505                            .ok()
22506                        else {
22507                            continue;
22508                        };
22509                        task.await.log_err();
22510                    }
22511                }
22512            }
22513        })
22514        .detach();
22515        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22516            selections.refresh()
22517        });
22518    }
22519
22520    pub fn to_pixel_point(
22521        &self,
22522        source: multi_buffer::Anchor,
22523        editor_snapshot: &EditorSnapshot,
22524        window: &mut Window,
22525    ) -> Option<gpui::Point<Pixels>> {
22526        let source_point = source.to_display_point(editor_snapshot);
22527        self.display_to_pixel_point(source_point, editor_snapshot, window)
22528    }
22529
22530    pub fn display_to_pixel_point(
22531        &self,
22532        source: DisplayPoint,
22533        editor_snapshot: &EditorSnapshot,
22534        window: &mut Window,
22535    ) -> Option<gpui::Point<Pixels>> {
22536        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22537        let text_layout_details = self.text_layout_details(window);
22538        let scroll_top = text_layout_details
22539            .scroll_anchor
22540            .scroll_position(editor_snapshot)
22541            .y;
22542
22543        if source.row().as_f64() < scroll_top.floor() {
22544            return None;
22545        }
22546        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22547        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22548        Some(gpui::Point::new(source_x, source_y))
22549    }
22550
22551    pub fn has_visible_completions_menu(&self) -> bool {
22552        !self.edit_prediction_preview_is_active()
22553            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22554                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22555            })
22556    }
22557
22558    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22559        if self.mode.is_minimap() {
22560            return;
22561        }
22562        self.addons
22563            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22564    }
22565
22566    pub fn unregister_addon<T: Addon>(&mut self) {
22567        self.addons.remove(&std::any::TypeId::of::<T>());
22568    }
22569
22570    pub fn addon<T: Addon>(&self) -> Option<&T> {
22571        let type_id = std::any::TypeId::of::<T>();
22572        self.addons
22573            .get(&type_id)
22574            .and_then(|item| item.to_any().downcast_ref::<T>())
22575    }
22576
22577    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22578        let type_id = std::any::TypeId::of::<T>();
22579        self.addons
22580            .get_mut(&type_id)
22581            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22582    }
22583
22584    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22585        let text_layout_details = self.text_layout_details(window);
22586        let style = &text_layout_details.editor_style;
22587        let font_id = window.text_system().resolve_font(&style.text.font());
22588        let font_size = style.text.font_size.to_pixels(window.rem_size());
22589        let line_height = style.text.line_height_in_pixels(window.rem_size());
22590        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22591        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22592
22593        CharacterDimensions {
22594            em_width,
22595            em_advance,
22596            line_height,
22597        }
22598    }
22599
22600    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22601        self.load_diff_task.clone()
22602    }
22603
22604    fn read_metadata_from_db(
22605        &mut self,
22606        item_id: u64,
22607        workspace_id: WorkspaceId,
22608        window: &mut Window,
22609        cx: &mut Context<Editor>,
22610    ) {
22611        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22612            && !self.mode.is_minimap()
22613            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22614        {
22615            let buffer_snapshot = OnceCell::new();
22616
22617            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22618                && !folds.is_empty()
22619            {
22620                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22621                self.fold_ranges(
22622                    folds
22623                        .into_iter()
22624                        .map(|(start, end)| {
22625                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22626                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22627                        })
22628                        .collect(),
22629                    false,
22630                    window,
22631                    cx,
22632                );
22633            }
22634
22635            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22636                && !selections.is_empty()
22637            {
22638                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22639                // skip adding the initial selection to selection history
22640                self.selection_history.mode = SelectionHistoryMode::Skipping;
22641                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22642                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22643                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22644                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22645                    }));
22646                });
22647                self.selection_history.mode = SelectionHistoryMode::Normal;
22648            };
22649        }
22650
22651        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22652    }
22653
22654    fn update_lsp_data(
22655        &mut self,
22656        for_buffer: Option<BufferId>,
22657        window: &mut Window,
22658        cx: &mut Context<'_, Self>,
22659    ) {
22660        self.pull_diagnostics(for_buffer, window, cx);
22661        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22662    }
22663
22664    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22665        if self.ignore_lsp_data() {
22666            return;
22667        }
22668        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
22669            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22670        }
22671    }
22672
22673    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22674        if self.ignore_lsp_data() {
22675            return;
22676        }
22677
22678        if !self.registered_buffers.contains_key(&buffer_id)
22679            && let Some(project) = self.project.as_ref()
22680        {
22681            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22682                project.update(cx, |project, cx| {
22683                    self.registered_buffers.insert(
22684                        buffer_id,
22685                        project.register_buffer_with_language_servers(&buffer, cx),
22686                    );
22687                });
22688            } else {
22689                self.registered_buffers.remove(&buffer_id);
22690            }
22691        }
22692    }
22693
22694    fn ignore_lsp_data(&self) -> bool {
22695        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22696        // skip any LSP updates for it.
22697        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22698    }
22699}
22700
22701fn edit_for_markdown_paste<'a>(
22702    buffer: &MultiBufferSnapshot,
22703    range: Range<MultiBufferOffset>,
22704    to_insert: &'a str,
22705    url: Option<url::Url>,
22706) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
22707    if url.is_none() {
22708        return (range, Cow::Borrowed(to_insert));
22709    };
22710
22711    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22712
22713    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22714        Cow::Borrowed(to_insert)
22715    } else {
22716        Cow::Owned(format!("[{old_text}]({to_insert})"))
22717    };
22718    (range, new_text)
22719}
22720
22721fn process_completion_for_edit(
22722    completion: &Completion,
22723    intent: CompletionIntent,
22724    buffer: &Entity<Buffer>,
22725    cursor_position: &text::Anchor,
22726    cx: &mut Context<Editor>,
22727) -> CompletionEdit {
22728    let buffer = buffer.read(cx);
22729    let buffer_snapshot = buffer.snapshot();
22730    let (snippet, new_text) = if completion.is_snippet() {
22731        let mut snippet_source = completion.new_text.clone();
22732        // Workaround for typescript language server issues so that methods don't expand within
22733        // strings and functions with type expressions. The previous point is used because the query
22734        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22735        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22736        let previous_point = if previous_point.column > 0 {
22737            cursor_position.to_previous_offset(&buffer_snapshot)
22738        } else {
22739            cursor_position.to_offset(&buffer_snapshot)
22740        };
22741        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22742            && scope.prefers_label_for_snippet_in_completion()
22743            && let Some(label) = completion.label()
22744            && matches!(
22745                completion.kind(),
22746                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22747            )
22748        {
22749            snippet_source = label;
22750        }
22751        match Snippet::parse(&snippet_source).log_err() {
22752            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22753            None => (None, completion.new_text.clone()),
22754        }
22755    } else {
22756        (None, completion.new_text.clone())
22757    };
22758
22759    let mut range_to_replace = {
22760        let replace_range = &completion.replace_range;
22761        if let CompletionSource::Lsp {
22762            insert_range: Some(insert_range),
22763            ..
22764        } = &completion.source
22765        {
22766            debug_assert_eq!(
22767                insert_range.start, replace_range.start,
22768                "insert_range and replace_range should start at the same position"
22769            );
22770            debug_assert!(
22771                insert_range
22772                    .start
22773                    .cmp(cursor_position, &buffer_snapshot)
22774                    .is_le(),
22775                "insert_range should start before or at cursor position"
22776            );
22777            debug_assert!(
22778                replace_range
22779                    .start
22780                    .cmp(cursor_position, &buffer_snapshot)
22781                    .is_le(),
22782                "replace_range should start before or at cursor position"
22783            );
22784
22785            let should_replace = match intent {
22786                CompletionIntent::CompleteWithInsert => false,
22787                CompletionIntent::CompleteWithReplace => true,
22788                CompletionIntent::Complete | CompletionIntent::Compose => {
22789                    let insert_mode =
22790                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22791                            .completions
22792                            .lsp_insert_mode;
22793                    match insert_mode {
22794                        LspInsertMode::Insert => false,
22795                        LspInsertMode::Replace => true,
22796                        LspInsertMode::ReplaceSubsequence => {
22797                            let mut text_to_replace = buffer.chars_for_range(
22798                                buffer.anchor_before(replace_range.start)
22799                                    ..buffer.anchor_after(replace_range.end),
22800                            );
22801                            let mut current_needle = text_to_replace.next();
22802                            for haystack_ch in completion.label.text.chars() {
22803                                if let Some(needle_ch) = current_needle
22804                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22805                                {
22806                                    current_needle = text_to_replace.next();
22807                                }
22808                            }
22809                            current_needle.is_none()
22810                        }
22811                        LspInsertMode::ReplaceSuffix => {
22812                            if replace_range
22813                                .end
22814                                .cmp(cursor_position, &buffer_snapshot)
22815                                .is_gt()
22816                            {
22817                                let range_after_cursor = *cursor_position..replace_range.end;
22818                                let text_after_cursor = buffer
22819                                    .text_for_range(
22820                                        buffer.anchor_before(range_after_cursor.start)
22821                                            ..buffer.anchor_after(range_after_cursor.end),
22822                                    )
22823                                    .collect::<String>()
22824                                    .to_ascii_lowercase();
22825                                completion
22826                                    .label
22827                                    .text
22828                                    .to_ascii_lowercase()
22829                                    .ends_with(&text_after_cursor)
22830                            } else {
22831                                true
22832                            }
22833                        }
22834                    }
22835                }
22836            };
22837
22838            if should_replace {
22839                replace_range.clone()
22840            } else {
22841                insert_range.clone()
22842            }
22843        } else {
22844            replace_range.clone()
22845        }
22846    };
22847
22848    if range_to_replace
22849        .end
22850        .cmp(cursor_position, &buffer_snapshot)
22851        .is_lt()
22852    {
22853        range_to_replace.end = *cursor_position;
22854    }
22855
22856    let replace_range = range_to_replace.to_offset(buffer);
22857    CompletionEdit {
22858        new_text,
22859        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
22860        snippet,
22861    }
22862}
22863
22864struct CompletionEdit {
22865    new_text: String,
22866    replace_range: Range<BufferOffset>,
22867    snippet: Option<Snippet>,
22868}
22869
22870fn insert_extra_newline_brackets(
22871    buffer: &MultiBufferSnapshot,
22872    range: Range<MultiBufferOffset>,
22873    language: &language::LanguageScope,
22874) -> bool {
22875    let leading_whitespace_len = buffer
22876        .reversed_chars_at(range.start)
22877        .take_while(|c| c.is_whitespace() && *c != '\n')
22878        .map(|c| c.len_utf8())
22879        .sum::<usize>();
22880    let trailing_whitespace_len = buffer
22881        .chars_at(range.end)
22882        .take_while(|c| c.is_whitespace() && *c != '\n')
22883        .map(|c| c.len_utf8())
22884        .sum::<usize>();
22885    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22886
22887    language.brackets().any(|(pair, enabled)| {
22888        let pair_start = pair.start.trim_end();
22889        let pair_end = pair.end.trim_start();
22890
22891        enabled
22892            && pair.newline
22893            && buffer.contains_str_at(range.end, pair_end)
22894            && buffer.contains_str_at(
22895                range.start.saturating_sub_usize(pair_start.len()),
22896                pair_start,
22897            )
22898    })
22899}
22900
22901fn insert_extra_newline_tree_sitter(
22902    buffer: &MultiBufferSnapshot,
22903    range: Range<MultiBufferOffset>,
22904) -> bool {
22905    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22906        [(buffer, range, _)] => (*buffer, range.clone()),
22907        _ => return false,
22908    };
22909    let pair = {
22910        let mut result: Option<BracketMatch<usize>> = None;
22911
22912        for pair in buffer
22913            .all_bracket_ranges(range.start.0..range.end.0)
22914            .filter(move |pair| {
22915                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
22916            })
22917        {
22918            let len = pair.close_range.end - pair.open_range.start;
22919
22920            if let Some(existing) = &result {
22921                let existing_len = existing.close_range.end - existing.open_range.start;
22922                if len > existing_len {
22923                    continue;
22924                }
22925            }
22926
22927            result = Some(pair);
22928        }
22929
22930        result
22931    };
22932    let Some(pair) = pair else {
22933        return false;
22934    };
22935    pair.newline_only
22936        && buffer
22937            .chars_for_range(pair.open_range.end..range.start.0)
22938            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
22939            .all(|c| c.is_whitespace() && c != '\n')
22940}
22941
22942fn update_uncommitted_diff_for_buffer(
22943    editor: Entity<Editor>,
22944    project: &Entity<Project>,
22945    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22946    buffer: Entity<MultiBuffer>,
22947    cx: &mut App,
22948) -> Task<()> {
22949    let mut tasks = Vec::new();
22950    project.update(cx, |project, cx| {
22951        for buffer in buffers {
22952            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22953                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22954            }
22955        }
22956    });
22957    cx.spawn(async move |cx| {
22958        let diffs = future::join_all(tasks).await;
22959        if editor
22960            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22961            .unwrap_or(false)
22962        {
22963            return;
22964        }
22965
22966        buffer
22967            .update(cx, |buffer, cx| {
22968                for diff in diffs.into_iter().flatten() {
22969                    buffer.add_diff(diff, cx);
22970                }
22971            })
22972            .ok();
22973    })
22974}
22975
22976fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22977    let tab_size = tab_size.get() as usize;
22978    let mut width = offset;
22979
22980    for ch in text.chars() {
22981        width += if ch == '\t' {
22982            tab_size - (width % tab_size)
22983        } else {
22984            1
22985        };
22986    }
22987
22988    width - offset
22989}
22990
22991#[cfg(test)]
22992mod tests {
22993    use super::*;
22994
22995    #[test]
22996    fn test_string_size_with_expanded_tabs() {
22997        let nz = |val| NonZeroU32::new(val).unwrap();
22998        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22999        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
23000        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
23001        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
23002        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
23003        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
23004        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
23005        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
23006    }
23007}
23008
23009/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
23010struct WordBreakingTokenizer<'a> {
23011    input: &'a str,
23012}
23013
23014impl<'a> WordBreakingTokenizer<'a> {
23015    fn new(input: &'a str) -> Self {
23016        Self { input }
23017    }
23018}
23019
23020fn is_char_ideographic(ch: char) -> bool {
23021    use unicode_script::Script::*;
23022    use unicode_script::UnicodeScript;
23023    matches!(ch.script(), Han | Tangut | Yi)
23024}
23025
23026fn is_grapheme_ideographic(text: &str) -> bool {
23027    text.chars().any(is_char_ideographic)
23028}
23029
23030fn is_grapheme_whitespace(text: &str) -> bool {
23031    text.chars().any(|x| x.is_whitespace())
23032}
23033
23034fn should_stay_with_preceding_ideograph(text: &str) -> bool {
23035    text.chars()
23036        .next()
23037        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
23038}
23039
23040#[derive(PartialEq, Eq, Debug, Clone, Copy)]
23041enum WordBreakToken<'a> {
23042    Word { token: &'a str, grapheme_len: usize },
23043    InlineWhitespace { token: &'a str, grapheme_len: usize },
23044    Newline,
23045}
23046
23047impl<'a> Iterator for WordBreakingTokenizer<'a> {
23048    /// Yields a span, the count of graphemes in the token, and whether it was
23049    /// whitespace. Note that it also breaks at word boundaries.
23050    type Item = WordBreakToken<'a>;
23051
23052    fn next(&mut self) -> Option<Self::Item> {
23053        use unicode_segmentation::UnicodeSegmentation;
23054        if self.input.is_empty() {
23055            return None;
23056        }
23057
23058        let mut iter = self.input.graphemes(true).peekable();
23059        let mut offset = 0;
23060        let mut grapheme_len = 0;
23061        if let Some(first_grapheme) = iter.next() {
23062            let is_newline = first_grapheme == "\n";
23063            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23064            offset += first_grapheme.len();
23065            grapheme_len += 1;
23066            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
23067                if let Some(grapheme) = iter.peek().copied()
23068                    && should_stay_with_preceding_ideograph(grapheme)
23069                {
23070                    offset += grapheme.len();
23071                    grapheme_len += 1;
23072                }
23073            } else {
23074                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23075                let mut next_word_bound = words.peek().copied();
23076                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23077                    next_word_bound = words.next();
23078                }
23079                while let Some(grapheme) = iter.peek().copied() {
23080                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23081                        break;
23082                    };
23083                    if is_grapheme_whitespace(grapheme) != is_whitespace
23084                        || (grapheme == "\n") != is_newline
23085                    {
23086                        break;
23087                    };
23088                    offset += grapheme.len();
23089                    grapheme_len += 1;
23090                    iter.next();
23091                }
23092            }
23093            let token = &self.input[..offset];
23094            self.input = &self.input[offset..];
23095            if token == "\n" {
23096                Some(WordBreakToken::Newline)
23097            } else if is_whitespace {
23098                Some(WordBreakToken::InlineWhitespace {
23099                    token,
23100                    grapheme_len,
23101                })
23102            } else {
23103                Some(WordBreakToken::Word {
23104                    token,
23105                    grapheme_len,
23106                })
23107            }
23108        } else {
23109            None
23110        }
23111    }
23112}
23113
23114#[test]
23115fn test_word_breaking_tokenizer() {
23116    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23117        ("", &[]),
23118        ("  ", &[whitespace("  ", 2)]),
23119        ("Ʒ", &[word("Ʒ", 1)]),
23120        ("Ǽ", &[word("Ǽ", 1)]),
23121        ("", &[word("", 1)]),
23122        ("⋑⋑", &[word("⋑⋑", 2)]),
23123        (
23124            "原理,进而",
23125            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23126        ),
23127        (
23128            "hello world",
23129            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23130        ),
23131        (
23132            "hello, world",
23133            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23134        ),
23135        (
23136            "  hello world",
23137            &[
23138                whitespace("  ", 2),
23139                word("hello", 5),
23140                whitespace(" ", 1),
23141                word("world", 5),
23142            ],
23143        ),
23144        (
23145            "这是什么 \n 钢笔",
23146            &[
23147                word("", 1),
23148                word("", 1),
23149                word("", 1),
23150                word("", 1),
23151                whitespace(" ", 1),
23152                newline(),
23153                whitespace(" ", 1),
23154                word("", 1),
23155                word("", 1),
23156            ],
23157        ),
23158        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23159    ];
23160
23161    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23162        WordBreakToken::Word {
23163            token,
23164            grapheme_len,
23165        }
23166    }
23167
23168    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23169        WordBreakToken::InlineWhitespace {
23170            token,
23171            grapheme_len,
23172        }
23173    }
23174
23175    fn newline() -> WordBreakToken<'static> {
23176        WordBreakToken::Newline
23177    }
23178
23179    for (input, result) in tests {
23180        assert_eq!(
23181            WordBreakingTokenizer::new(input)
23182                .collect::<Vec<_>>()
23183                .as_slice(),
23184            *result,
23185        );
23186    }
23187}
23188
23189fn wrap_with_prefix(
23190    first_line_prefix: String,
23191    subsequent_lines_prefix: String,
23192    unwrapped_text: String,
23193    wrap_column: usize,
23194    tab_size: NonZeroU32,
23195    preserve_existing_whitespace: bool,
23196) -> String {
23197    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23198    let subsequent_lines_prefix_len =
23199        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23200    let mut wrapped_text = String::new();
23201    let mut current_line = first_line_prefix;
23202    let mut is_first_line = true;
23203
23204    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23205    let mut current_line_len = first_line_prefix_len;
23206    let mut in_whitespace = false;
23207    for token in tokenizer {
23208        let have_preceding_whitespace = in_whitespace;
23209        match token {
23210            WordBreakToken::Word {
23211                token,
23212                grapheme_len,
23213            } => {
23214                in_whitespace = false;
23215                let current_prefix_len = if is_first_line {
23216                    first_line_prefix_len
23217                } else {
23218                    subsequent_lines_prefix_len
23219                };
23220                if current_line_len + grapheme_len > wrap_column
23221                    && current_line_len != current_prefix_len
23222                {
23223                    wrapped_text.push_str(current_line.trim_end());
23224                    wrapped_text.push('\n');
23225                    is_first_line = false;
23226                    current_line = subsequent_lines_prefix.clone();
23227                    current_line_len = subsequent_lines_prefix_len;
23228                }
23229                current_line.push_str(token);
23230                current_line_len += grapheme_len;
23231            }
23232            WordBreakToken::InlineWhitespace {
23233                mut token,
23234                mut grapheme_len,
23235            } => {
23236                in_whitespace = true;
23237                if have_preceding_whitespace && !preserve_existing_whitespace {
23238                    continue;
23239                }
23240                if !preserve_existing_whitespace {
23241                    // Keep a single whitespace grapheme as-is
23242                    if let Some(first) =
23243                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23244                    {
23245                        token = first;
23246                    } else {
23247                        token = " ";
23248                    }
23249                    grapheme_len = 1;
23250                }
23251                let current_prefix_len = if is_first_line {
23252                    first_line_prefix_len
23253                } else {
23254                    subsequent_lines_prefix_len
23255                };
23256                if current_line_len + grapheme_len > wrap_column {
23257                    wrapped_text.push_str(current_line.trim_end());
23258                    wrapped_text.push('\n');
23259                    is_first_line = false;
23260                    current_line = subsequent_lines_prefix.clone();
23261                    current_line_len = subsequent_lines_prefix_len;
23262                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23263                    current_line.push_str(token);
23264                    current_line_len += grapheme_len;
23265                }
23266            }
23267            WordBreakToken::Newline => {
23268                in_whitespace = true;
23269                let current_prefix_len = if is_first_line {
23270                    first_line_prefix_len
23271                } else {
23272                    subsequent_lines_prefix_len
23273                };
23274                if preserve_existing_whitespace {
23275                    wrapped_text.push_str(current_line.trim_end());
23276                    wrapped_text.push('\n');
23277                    is_first_line = false;
23278                    current_line = subsequent_lines_prefix.clone();
23279                    current_line_len = subsequent_lines_prefix_len;
23280                } else if have_preceding_whitespace {
23281                    continue;
23282                } else if current_line_len + 1 > wrap_column
23283                    && current_line_len != current_prefix_len
23284                {
23285                    wrapped_text.push_str(current_line.trim_end());
23286                    wrapped_text.push('\n');
23287                    is_first_line = false;
23288                    current_line = subsequent_lines_prefix.clone();
23289                    current_line_len = subsequent_lines_prefix_len;
23290                } else if current_line_len != current_prefix_len {
23291                    current_line.push(' ');
23292                    current_line_len += 1;
23293                }
23294            }
23295        }
23296    }
23297
23298    if !current_line.is_empty() {
23299        wrapped_text.push_str(&current_line);
23300    }
23301    wrapped_text
23302}
23303
23304#[test]
23305fn test_wrap_with_prefix() {
23306    assert_eq!(
23307        wrap_with_prefix(
23308            "# ".to_string(),
23309            "# ".to_string(),
23310            "abcdefg".to_string(),
23311            4,
23312            NonZeroU32::new(4).unwrap(),
23313            false,
23314        ),
23315        "# abcdefg"
23316    );
23317    assert_eq!(
23318        wrap_with_prefix(
23319            "".to_string(),
23320            "".to_string(),
23321            "\thello world".to_string(),
23322            8,
23323            NonZeroU32::new(4).unwrap(),
23324            false,
23325        ),
23326        "hello\nworld"
23327    );
23328    assert_eq!(
23329        wrap_with_prefix(
23330            "// ".to_string(),
23331            "// ".to_string(),
23332            "xx \nyy zz aa bb cc".to_string(),
23333            12,
23334            NonZeroU32::new(4).unwrap(),
23335            false,
23336        ),
23337        "// xx yy zz\n// aa bb cc"
23338    );
23339    assert_eq!(
23340        wrap_with_prefix(
23341            String::new(),
23342            String::new(),
23343            "这是什么 \n 钢笔".to_string(),
23344            3,
23345            NonZeroU32::new(4).unwrap(),
23346            false,
23347        ),
23348        "这是什\n么 钢\n"
23349    );
23350    assert_eq!(
23351        wrap_with_prefix(
23352            String::new(),
23353            String::new(),
23354            format!("foo{}bar", '\u{2009}'), // thin space
23355            80,
23356            NonZeroU32::new(4).unwrap(),
23357            false,
23358        ),
23359        format!("foo{}bar", '\u{2009}')
23360    );
23361}
23362
23363pub trait CollaborationHub {
23364    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23365    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23366    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23367}
23368
23369impl CollaborationHub for Entity<Project> {
23370    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23371        self.read(cx).collaborators()
23372    }
23373
23374    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23375        self.read(cx).user_store().read(cx).participant_indices()
23376    }
23377
23378    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23379        let this = self.read(cx);
23380        let user_ids = this.collaborators().values().map(|c| c.user_id);
23381        this.user_store().read(cx).participant_names(user_ids, cx)
23382    }
23383}
23384
23385pub trait SemanticsProvider {
23386    fn hover(
23387        &self,
23388        buffer: &Entity<Buffer>,
23389        position: text::Anchor,
23390        cx: &mut App,
23391    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23392
23393    fn inline_values(
23394        &self,
23395        buffer_handle: Entity<Buffer>,
23396        range: Range<text::Anchor>,
23397        cx: &mut App,
23398    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23399
23400    fn applicable_inlay_chunks(
23401        &self,
23402        buffer: &Entity<Buffer>,
23403        ranges: &[Range<text::Anchor>],
23404        cx: &mut App,
23405    ) -> Vec<Range<BufferRow>>;
23406
23407    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23408
23409    fn inlay_hints(
23410        &self,
23411        invalidate: InvalidationStrategy,
23412        buffer: Entity<Buffer>,
23413        ranges: Vec<Range<text::Anchor>>,
23414        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23415        cx: &mut App,
23416    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23417
23418    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23419
23420    fn document_highlights(
23421        &self,
23422        buffer: &Entity<Buffer>,
23423        position: text::Anchor,
23424        cx: &mut App,
23425    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23426
23427    fn definitions(
23428        &self,
23429        buffer: &Entity<Buffer>,
23430        position: text::Anchor,
23431        kind: GotoDefinitionKind,
23432        cx: &mut App,
23433    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23434
23435    fn range_for_rename(
23436        &self,
23437        buffer: &Entity<Buffer>,
23438        position: text::Anchor,
23439        cx: &mut App,
23440    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23441
23442    fn perform_rename(
23443        &self,
23444        buffer: &Entity<Buffer>,
23445        position: text::Anchor,
23446        new_name: String,
23447        cx: &mut App,
23448    ) -> Option<Task<Result<ProjectTransaction>>>;
23449}
23450
23451pub trait CompletionProvider {
23452    fn completions(
23453        &self,
23454        excerpt_id: ExcerptId,
23455        buffer: &Entity<Buffer>,
23456        buffer_position: text::Anchor,
23457        trigger: CompletionContext,
23458        window: &mut Window,
23459        cx: &mut Context<Editor>,
23460    ) -> Task<Result<Vec<CompletionResponse>>>;
23461
23462    fn resolve_completions(
23463        &self,
23464        _buffer: Entity<Buffer>,
23465        _completion_indices: Vec<usize>,
23466        _completions: Rc<RefCell<Box<[Completion]>>>,
23467        _cx: &mut Context<Editor>,
23468    ) -> Task<Result<bool>> {
23469        Task::ready(Ok(false))
23470    }
23471
23472    fn apply_additional_edits_for_completion(
23473        &self,
23474        _buffer: Entity<Buffer>,
23475        _completions: Rc<RefCell<Box<[Completion]>>>,
23476        _completion_index: usize,
23477        _push_to_history: bool,
23478        _cx: &mut Context<Editor>,
23479    ) -> Task<Result<Option<language::Transaction>>> {
23480        Task::ready(Ok(None))
23481    }
23482
23483    fn is_completion_trigger(
23484        &self,
23485        buffer: &Entity<Buffer>,
23486        position: language::Anchor,
23487        text: &str,
23488        trigger_in_words: bool,
23489        menu_is_open: bool,
23490        cx: &mut Context<Editor>,
23491    ) -> bool;
23492
23493    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23494
23495    fn sort_completions(&self) -> bool {
23496        true
23497    }
23498
23499    fn filter_completions(&self) -> bool {
23500        true
23501    }
23502
23503    fn show_snippets(&self) -> bool {
23504        false
23505    }
23506}
23507
23508pub trait CodeActionProvider {
23509    fn id(&self) -> Arc<str>;
23510
23511    fn code_actions(
23512        &self,
23513        buffer: &Entity<Buffer>,
23514        range: Range<text::Anchor>,
23515        window: &mut Window,
23516        cx: &mut App,
23517    ) -> Task<Result<Vec<CodeAction>>>;
23518
23519    fn apply_code_action(
23520        &self,
23521        buffer_handle: Entity<Buffer>,
23522        action: CodeAction,
23523        excerpt_id: ExcerptId,
23524        push_to_history: bool,
23525        window: &mut Window,
23526        cx: &mut App,
23527    ) -> Task<Result<ProjectTransaction>>;
23528}
23529
23530impl CodeActionProvider for Entity<Project> {
23531    fn id(&self) -> Arc<str> {
23532        "project".into()
23533    }
23534
23535    fn code_actions(
23536        &self,
23537        buffer: &Entity<Buffer>,
23538        range: Range<text::Anchor>,
23539        _window: &mut Window,
23540        cx: &mut App,
23541    ) -> Task<Result<Vec<CodeAction>>> {
23542        self.update(cx, |project, cx| {
23543            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23544            let code_actions = project.code_actions(buffer, range, None, cx);
23545            cx.background_spawn(async move {
23546                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23547                Ok(code_lens_actions
23548                    .context("code lens fetch")?
23549                    .into_iter()
23550                    .flatten()
23551                    .chain(
23552                        code_actions
23553                            .context("code action fetch")?
23554                            .into_iter()
23555                            .flatten(),
23556                    )
23557                    .collect())
23558            })
23559        })
23560    }
23561
23562    fn apply_code_action(
23563        &self,
23564        buffer_handle: Entity<Buffer>,
23565        action: CodeAction,
23566        _excerpt_id: ExcerptId,
23567        push_to_history: bool,
23568        _window: &mut Window,
23569        cx: &mut App,
23570    ) -> Task<Result<ProjectTransaction>> {
23571        self.update(cx, |project, cx| {
23572            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23573        })
23574    }
23575}
23576
23577fn snippet_completions(
23578    project: &Project,
23579    buffer: &Entity<Buffer>,
23580    buffer_anchor: text::Anchor,
23581    classifier: CharClassifier,
23582    cx: &mut App,
23583) -> Task<Result<CompletionResponse>> {
23584    let languages = buffer.read(cx).languages_at(buffer_anchor);
23585    let snippet_store = project.snippets().read(cx);
23586
23587    let scopes: Vec<_> = languages
23588        .iter()
23589        .filter_map(|language| {
23590            let language_name = language.lsp_id();
23591            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23592
23593            if snippets.is_empty() {
23594                None
23595            } else {
23596                Some((language.default_scope(), snippets))
23597            }
23598        })
23599        .collect();
23600
23601    if scopes.is_empty() {
23602        return Task::ready(Ok(CompletionResponse {
23603            completions: vec![],
23604            display_options: CompletionDisplayOptions::default(),
23605            is_incomplete: false,
23606        }));
23607    }
23608
23609    let snapshot = buffer.read(cx).text_snapshot();
23610    let executor = cx.background_executor().clone();
23611
23612    cx.background_spawn(async move {
23613        let is_word_char = |c| classifier.is_word(c);
23614
23615        let mut is_incomplete = false;
23616        let mut completions: Vec<Completion> = Vec::new();
23617
23618        const MAX_PREFIX_LEN: usize = 128;
23619        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
23620        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
23621        let window_start = snapshot.clip_offset(window_start, Bias::Left);
23622
23623        let max_buffer_window: String = snapshot
23624            .text_for_range(window_start..buffer_offset)
23625            .collect();
23626
23627        if max_buffer_window.is_empty() {
23628            return Ok(CompletionResponse {
23629                completions: vec![],
23630                display_options: CompletionDisplayOptions::default(),
23631                is_incomplete: true,
23632            });
23633        }
23634
23635        for (_scope, snippets) in scopes.into_iter() {
23636            // Sort snippets by word count to match longer snippet prefixes first.
23637            let mut sorted_snippet_candidates = snippets
23638                .iter()
23639                .enumerate()
23640                .flat_map(|(snippet_ix, snippet)| {
23641                    snippet
23642                        .prefix
23643                        .iter()
23644                        .enumerate()
23645                        .map(move |(prefix_ix, prefix)| {
23646                            let word_count =
23647                                snippet_candidate_suffixes(prefix, is_word_char).count();
23648                            ((snippet_ix, prefix_ix), prefix, word_count)
23649                        })
23650                })
23651                .collect_vec();
23652            sorted_snippet_candidates
23653                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
23654
23655            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
23656
23657            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
23658                .take(
23659                    sorted_snippet_candidates
23660                        .first()
23661                        .map(|(_, _, word_count)| *word_count)
23662                        .unwrap_or_default(),
23663                )
23664                .collect_vec();
23665
23666            const MAX_RESULTS: usize = 100;
23667            // Each match also remembers how many characters from the buffer it consumed
23668            let mut matches: Vec<(StringMatch, usize)> = vec![];
23669
23670            let mut snippet_list_cutoff_index = 0;
23671            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
23672                let word_count = buffer_index + 1;
23673                // Increase `snippet_list_cutoff_index` until we have all of the
23674                // snippets with sufficiently many words.
23675                while sorted_snippet_candidates
23676                    .get(snippet_list_cutoff_index)
23677                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
23678                        *snippet_word_count >= word_count
23679                    })
23680                {
23681                    snippet_list_cutoff_index += 1;
23682                }
23683
23684                // Take only the candidates with at least `word_count` many words
23685                let snippet_candidates_at_word_len =
23686                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
23687
23688                let candidates = snippet_candidates_at_word_len
23689                    .iter()
23690                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
23691                    .enumerate() // index in `sorted_snippet_candidates`
23692                    // First char must match
23693                    .filter(|(_ix, prefix)| {
23694                        itertools::equal(
23695                            prefix
23696                                .chars()
23697                                .next()
23698                                .into_iter()
23699                                .flat_map(|c| c.to_lowercase()),
23700                            buffer_window
23701                                .chars()
23702                                .next()
23703                                .into_iter()
23704                                .flat_map(|c| c.to_lowercase()),
23705                        )
23706                    })
23707                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
23708                    .collect::<Vec<StringMatchCandidate>>();
23709
23710                matches.extend(
23711                    fuzzy::match_strings(
23712                        &candidates,
23713                        &buffer_window,
23714                        buffer_window.chars().any(|c| c.is_uppercase()),
23715                        true,
23716                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
23717                        &Default::default(),
23718                        executor.clone(),
23719                    )
23720                    .await
23721                    .into_iter()
23722                    .map(|string_match| (string_match, buffer_window.len())),
23723                );
23724
23725                if matches.len() >= MAX_RESULTS {
23726                    break;
23727                }
23728            }
23729
23730            let to_lsp = |point: &text::Anchor| {
23731                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23732                point_to_lsp(end)
23733            };
23734            let lsp_end = to_lsp(&buffer_anchor);
23735
23736            if matches.len() >= MAX_RESULTS {
23737                is_incomplete = true;
23738            }
23739
23740            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
23741                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
23742                    sorted_snippet_candidates[string_match.candidate_id];
23743                let snippet = &snippets[snippet_index];
23744                let start = buffer_offset - buffer_window_len;
23745                let start = snapshot.anchor_before(start);
23746                let range = start..buffer_anchor;
23747                let lsp_start = to_lsp(&start);
23748                let lsp_range = lsp::Range {
23749                    start: lsp_start,
23750                    end: lsp_end,
23751                };
23752                Completion {
23753                    replace_range: range,
23754                    new_text: snippet.body.clone(),
23755                    source: CompletionSource::Lsp {
23756                        insert_range: None,
23757                        server_id: LanguageServerId(usize::MAX),
23758                        resolved: true,
23759                        lsp_completion: Box::new(lsp::CompletionItem {
23760                            label: snippet.prefix.first().unwrap().clone(),
23761                            kind: Some(CompletionItemKind::SNIPPET),
23762                            label_details: snippet.description.as_ref().map(|description| {
23763                                lsp::CompletionItemLabelDetails {
23764                                    detail: Some(description.clone()),
23765                                    description: None,
23766                                }
23767                            }),
23768                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23769                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23770                                lsp::InsertReplaceEdit {
23771                                    new_text: snippet.body.clone(),
23772                                    insert: lsp_range,
23773                                    replace: lsp_range,
23774                                },
23775                            )),
23776                            filter_text: Some(snippet.body.clone()),
23777                            sort_text: Some(char::MAX.to_string()),
23778                            ..lsp::CompletionItem::default()
23779                        }),
23780                        lsp_defaults: None,
23781                    },
23782                    label: CodeLabel {
23783                        text: matching_prefix.clone(),
23784                        runs: Vec::new(),
23785                        filter_range: 0..matching_prefix.len(),
23786                    },
23787                    icon_path: None,
23788                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23789                        single_line: snippet.name.clone().into(),
23790                        plain_text: snippet
23791                            .description
23792                            .clone()
23793                            .map(|description| description.into()),
23794                    }),
23795                    insert_text_mode: None,
23796                    confirm: None,
23797                    match_start: Some(start),
23798                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
23799                }
23800            }));
23801        }
23802
23803        Ok(CompletionResponse {
23804            completions,
23805            display_options: CompletionDisplayOptions::default(),
23806            is_incomplete,
23807        })
23808    })
23809}
23810
23811impl CompletionProvider for Entity<Project> {
23812    fn completions(
23813        &self,
23814        _excerpt_id: ExcerptId,
23815        buffer: &Entity<Buffer>,
23816        buffer_position: text::Anchor,
23817        options: CompletionContext,
23818        _window: &mut Window,
23819        cx: &mut Context<Editor>,
23820    ) -> Task<Result<Vec<CompletionResponse>>> {
23821        self.update(cx, |project, cx| {
23822            let task = project.completions(buffer, buffer_position, options, cx);
23823            cx.background_spawn(task)
23824        })
23825    }
23826
23827    fn resolve_completions(
23828        &self,
23829        buffer: Entity<Buffer>,
23830        completion_indices: Vec<usize>,
23831        completions: Rc<RefCell<Box<[Completion]>>>,
23832        cx: &mut Context<Editor>,
23833    ) -> Task<Result<bool>> {
23834        self.update(cx, |project, cx| {
23835            project.lsp_store().update(cx, |lsp_store, cx| {
23836                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23837            })
23838        })
23839    }
23840
23841    fn apply_additional_edits_for_completion(
23842        &self,
23843        buffer: Entity<Buffer>,
23844        completions: Rc<RefCell<Box<[Completion]>>>,
23845        completion_index: usize,
23846        push_to_history: bool,
23847        cx: &mut Context<Editor>,
23848    ) -> Task<Result<Option<language::Transaction>>> {
23849        self.update(cx, |project, cx| {
23850            project.lsp_store().update(cx, |lsp_store, cx| {
23851                lsp_store.apply_additional_edits_for_completion(
23852                    buffer,
23853                    completions,
23854                    completion_index,
23855                    push_to_history,
23856                    cx,
23857                )
23858            })
23859        })
23860    }
23861
23862    fn is_completion_trigger(
23863        &self,
23864        buffer: &Entity<Buffer>,
23865        position: language::Anchor,
23866        text: &str,
23867        trigger_in_words: bool,
23868        menu_is_open: bool,
23869        cx: &mut Context<Editor>,
23870    ) -> bool {
23871        let mut chars = text.chars();
23872        let char = if let Some(char) = chars.next() {
23873            char
23874        } else {
23875            return false;
23876        };
23877        if chars.next().is_some() {
23878            return false;
23879        }
23880
23881        let buffer = buffer.read(cx);
23882        let snapshot = buffer.snapshot();
23883        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23884            return false;
23885        }
23886        let classifier = snapshot
23887            .char_classifier_at(position)
23888            .scope_context(Some(CharScopeContext::Completion));
23889        if trigger_in_words && classifier.is_word(char) {
23890            return true;
23891        }
23892
23893        buffer.completion_triggers().contains(text)
23894    }
23895
23896    fn show_snippets(&self) -> bool {
23897        true
23898    }
23899}
23900
23901impl SemanticsProvider for Entity<Project> {
23902    fn hover(
23903        &self,
23904        buffer: &Entity<Buffer>,
23905        position: text::Anchor,
23906        cx: &mut App,
23907    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23908        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23909    }
23910
23911    fn document_highlights(
23912        &self,
23913        buffer: &Entity<Buffer>,
23914        position: text::Anchor,
23915        cx: &mut App,
23916    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23917        Some(self.update(cx, |project, cx| {
23918            project.document_highlights(buffer, position, cx)
23919        }))
23920    }
23921
23922    fn definitions(
23923        &self,
23924        buffer: &Entity<Buffer>,
23925        position: text::Anchor,
23926        kind: GotoDefinitionKind,
23927        cx: &mut App,
23928    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23929        Some(self.update(cx, |project, cx| match kind {
23930            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23931            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23932            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23933            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23934        }))
23935    }
23936
23937    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23938        self.update(cx, |project, cx| {
23939            if project
23940                .active_debug_session(cx)
23941                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23942            {
23943                return true;
23944            }
23945
23946            buffer.update(cx, |buffer, cx| {
23947                project.any_language_server_supports_inlay_hints(buffer, cx)
23948            })
23949        })
23950    }
23951
23952    fn inline_values(
23953        &self,
23954        buffer_handle: Entity<Buffer>,
23955        range: Range<text::Anchor>,
23956        cx: &mut App,
23957    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23958        self.update(cx, |project, cx| {
23959            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23960
23961            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23962        })
23963    }
23964
23965    fn applicable_inlay_chunks(
23966        &self,
23967        buffer: &Entity<Buffer>,
23968        ranges: &[Range<text::Anchor>],
23969        cx: &mut App,
23970    ) -> Vec<Range<BufferRow>> {
23971        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23972            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23973        })
23974    }
23975
23976    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23977        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23978            lsp_store.invalidate_inlay_hints(for_buffers)
23979        });
23980    }
23981
23982    fn inlay_hints(
23983        &self,
23984        invalidate: InvalidationStrategy,
23985        buffer: Entity<Buffer>,
23986        ranges: Vec<Range<text::Anchor>>,
23987        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23988        cx: &mut App,
23989    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23990        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23991            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23992        }))
23993    }
23994
23995    fn range_for_rename(
23996        &self,
23997        buffer: &Entity<Buffer>,
23998        position: text::Anchor,
23999        cx: &mut App,
24000    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
24001        Some(self.update(cx, |project, cx| {
24002            let buffer = buffer.clone();
24003            let task = project.prepare_rename(buffer.clone(), position, cx);
24004            cx.spawn(async move |_, cx| {
24005                Ok(match task.await? {
24006                    PrepareRenameResponse::Success(range) => Some(range),
24007                    PrepareRenameResponse::InvalidPosition => None,
24008                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
24009                        // Fallback on using TreeSitter info to determine identifier range
24010                        buffer.read_with(cx, |buffer, _| {
24011                            let snapshot = buffer.snapshot();
24012                            let (range, kind) = snapshot.surrounding_word(position, None);
24013                            if kind != Some(CharKind::Word) {
24014                                return None;
24015                            }
24016                            Some(
24017                                snapshot.anchor_before(range.start)
24018                                    ..snapshot.anchor_after(range.end),
24019                            )
24020                        })?
24021                    }
24022                })
24023            })
24024        }))
24025    }
24026
24027    fn perform_rename(
24028        &self,
24029        buffer: &Entity<Buffer>,
24030        position: text::Anchor,
24031        new_name: String,
24032        cx: &mut App,
24033    ) -> Option<Task<Result<ProjectTransaction>>> {
24034        Some(self.update(cx, |project, cx| {
24035            project.perform_rename(buffer.clone(), position, new_name, cx)
24036        }))
24037    }
24038}
24039
24040fn consume_contiguous_rows(
24041    contiguous_row_selections: &mut Vec<Selection<Point>>,
24042    selection: &Selection<Point>,
24043    display_map: &DisplaySnapshot,
24044    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
24045) -> (MultiBufferRow, MultiBufferRow) {
24046    contiguous_row_selections.push(selection.clone());
24047    let start_row = starting_row(selection, display_map);
24048    let mut end_row = ending_row(selection, display_map);
24049
24050    while let Some(next_selection) = selections.peek() {
24051        if next_selection.start.row <= end_row.0 {
24052            end_row = ending_row(next_selection, display_map);
24053            contiguous_row_selections.push(selections.next().unwrap().clone());
24054        } else {
24055            break;
24056        }
24057    }
24058    (start_row, end_row)
24059}
24060
24061fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24062    if selection.start.column > 0 {
24063        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
24064    } else {
24065        MultiBufferRow(selection.start.row)
24066    }
24067}
24068
24069fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24070    if next_selection.end.column > 0 || next_selection.is_empty() {
24071        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
24072    } else {
24073        MultiBufferRow(next_selection.end.row)
24074    }
24075}
24076
24077impl EditorSnapshot {
24078    pub fn remote_selections_in_range<'a>(
24079        &'a self,
24080        range: &'a Range<Anchor>,
24081        collaboration_hub: &dyn CollaborationHub,
24082        cx: &'a App,
24083    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24084        let participant_names = collaboration_hub.user_names(cx);
24085        let participant_indices = collaboration_hub.user_participant_indices(cx);
24086        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24087        let collaborators_by_replica_id = collaborators_by_peer_id
24088            .values()
24089            .map(|collaborator| (collaborator.replica_id, collaborator))
24090            .collect::<HashMap<_, _>>();
24091        self.buffer_snapshot()
24092            .selections_in_range(range, false)
24093            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24094                if replica_id == ReplicaId::AGENT {
24095                    Some(RemoteSelection {
24096                        replica_id,
24097                        selection,
24098                        cursor_shape,
24099                        line_mode,
24100                        collaborator_id: CollaboratorId::Agent,
24101                        user_name: Some("Agent".into()),
24102                        color: cx.theme().players().agent(),
24103                    })
24104                } else {
24105                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24106                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24107                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24108                    Some(RemoteSelection {
24109                        replica_id,
24110                        selection,
24111                        cursor_shape,
24112                        line_mode,
24113                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24114                        user_name,
24115                        color: if let Some(index) = participant_index {
24116                            cx.theme().players().color_for_participant(index.0)
24117                        } else {
24118                            cx.theme().players().absent()
24119                        },
24120                    })
24121                }
24122            })
24123    }
24124
24125    pub fn hunks_for_ranges(
24126        &self,
24127        ranges: impl IntoIterator<Item = Range<Point>>,
24128    ) -> Vec<MultiBufferDiffHunk> {
24129        let mut hunks = Vec::new();
24130        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24131            HashMap::default();
24132        for query_range in ranges {
24133            let query_rows =
24134                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24135            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24136                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24137            ) {
24138                // Include deleted hunks that are adjacent to the query range, because
24139                // otherwise they would be missed.
24140                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24141                if hunk.status().is_deleted() {
24142                    intersects_range |= hunk.row_range.start == query_rows.end;
24143                    intersects_range |= hunk.row_range.end == query_rows.start;
24144                }
24145                if intersects_range {
24146                    if !processed_buffer_rows
24147                        .entry(hunk.buffer_id)
24148                        .or_default()
24149                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24150                    {
24151                        continue;
24152                    }
24153                    hunks.push(hunk);
24154                }
24155            }
24156        }
24157
24158        hunks
24159    }
24160
24161    fn display_diff_hunks_for_rows<'a>(
24162        &'a self,
24163        display_rows: Range<DisplayRow>,
24164        folded_buffers: &'a HashSet<BufferId>,
24165    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24166        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24167        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24168
24169        self.buffer_snapshot()
24170            .diff_hunks_in_range(buffer_start..buffer_end)
24171            .filter_map(|hunk| {
24172                if folded_buffers.contains(&hunk.buffer_id) {
24173                    return None;
24174                }
24175
24176                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24177                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24178
24179                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24180                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24181
24182                let display_hunk = if hunk_display_start.column() != 0 {
24183                    DisplayDiffHunk::Folded {
24184                        display_row: hunk_display_start.row(),
24185                    }
24186                } else {
24187                    let mut end_row = hunk_display_end.row();
24188                    if hunk_display_end.column() > 0 {
24189                        end_row.0 += 1;
24190                    }
24191                    let is_created_file = hunk.is_created_file();
24192
24193                    DisplayDiffHunk::Unfolded {
24194                        status: hunk.status(),
24195                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24196                            ..hunk.diff_base_byte_range.end.0,
24197                        word_diffs: hunk.word_diffs,
24198                        display_row_range: hunk_display_start.row()..end_row,
24199                        multi_buffer_range: Anchor::range_in_buffer(
24200                            hunk.excerpt_id,
24201                            hunk.buffer_range,
24202                        ),
24203                        is_created_file,
24204                    }
24205                };
24206
24207                Some(display_hunk)
24208            })
24209    }
24210
24211    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24212        self.display_snapshot
24213            .buffer_snapshot()
24214            .language_at(position)
24215    }
24216
24217    pub fn is_focused(&self) -> bool {
24218        self.is_focused
24219    }
24220
24221    pub fn placeholder_text(&self) -> Option<String> {
24222        self.placeholder_display_snapshot
24223            .as_ref()
24224            .map(|display_map| display_map.text())
24225    }
24226
24227    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24228        self.scroll_anchor.scroll_position(&self.display_snapshot)
24229    }
24230
24231    fn gutter_dimensions(
24232        &self,
24233        font_id: FontId,
24234        font_size: Pixels,
24235        max_line_number_width: Pixels,
24236        cx: &App,
24237    ) -> Option<GutterDimensions> {
24238        if !self.show_gutter {
24239            return None;
24240        }
24241
24242        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
24243        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
24244
24245        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24246            matches!(
24247                ProjectSettings::get_global(cx).git.git_gutter,
24248                GitGutterSetting::TrackedFiles
24249            )
24250        });
24251        let gutter_settings = EditorSettings::get_global(cx).gutter;
24252        let show_line_numbers = self
24253            .show_line_numbers
24254            .unwrap_or(gutter_settings.line_numbers);
24255        let line_gutter_width = if show_line_numbers {
24256            // Avoid flicker-like gutter resizes when the line number gains another digit by
24257            // only resizing the gutter on files with > 10**min_line_number_digits lines.
24258            let min_width_for_number_on_gutter =
24259                ch_advance * gutter_settings.min_line_number_digits as f32;
24260            max_line_number_width.max(min_width_for_number_on_gutter)
24261        } else {
24262            0.0.into()
24263        };
24264
24265        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24266        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24267
24268        let git_blame_entries_width =
24269            self.git_blame_gutter_max_author_length
24270                .map(|max_author_length| {
24271                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24272                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24273
24274                    /// The number of characters to dedicate to gaps and margins.
24275                    const SPACING_WIDTH: usize = 4;
24276
24277                    let max_char_count = max_author_length.min(renderer.max_author_length())
24278                        + ::git::SHORT_SHA_LENGTH
24279                        + MAX_RELATIVE_TIMESTAMP.len()
24280                        + SPACING_WIDTH;
24281
24282                    ch_advance * max_char_count
24283                });
24284
24285        let is_singleton = self.buffer_snapshot().is_singleton();
24286
24287        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24288        left_padding += if !is_singleton {
24289            ch_width * 4.0
24290        } else if show_runnables || show_breakpoints {
24291            ch_width * 3.0
24292        } else if show_git_gutter && show_line_numbers {
24293            ch_width * 2.0
24294        } else if show_git_gutter || show_line_numbers {
24295            ch_width
24296        } else {
24297            px(0.)
24298        };
24299
24300        let shows_folds = is_singleton && gutter_settings.folds;
24301
24302        let right_padding = if shows_folds && show_line_numbers {
24303            ch_width * 4.0
24304        } else if shows_folds || (!is_singleton && show_line_numbers) {
24305            ch_width * 3.0
24306        } else if show_line_numbers {
24307            ch_width
24308        } else {
24309            px(0.)
24310        };
24311
24312        Some(GutterDimensions {
24313            left_padding,
24314            right_padding,
24315            width: line_gutter_width + left_padding + right_padding,
24316            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24317            git_blame_entries_width,
24318        })
24319    }
24320
24321    pub fn render_crease_toggle(
24322        &self,
24323        buffer_row: MultiBufferRow,
24324        row_contains_cursor: bool,
24325        editor: Entity<Editor>,
24326        window: &mut Window,
24327        cx: &mut App,
24328    ) -> Option<AnyElement> {
24329        let folded = self.is_line_folded(buffer_row);
24330        let mut is_foldable = false;
24331
24332        if let Some(crease) = self
24333            .crease_snapshot
24334            .query_row(buffer_row, self.buffer_snapshot())
24335        {
24336            is_foldable = true;
24337            match crease {
24338                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24339                    if let Some(render_toggle) = render_toggle {
24340                        let toggle_callback =
24341                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24342                                if folded {
24343                                    editor.update(cx, |editor, cx| {
24344                                        editor.fold_at(buffer_row, window, cx)
24345                                    });
24346                                } else {
24347                                    editor.update(cx, |editor, cx| {
24348                                        editor.unfold_at(buffer_row, window, cx)
24349                                    });
24350                                }
24351                            });
24352                        return Some((render_toggle)(
24353                            buffer_row,
24354                            folded,
24355                            toggle_callback,
24356                            window,
24357                            cx,
24358                        ));
24359                    }
24360                }
24361            }
24362        }
24363
24364        is_foldable |= self.starts_indent(buffer_row);
24365
24366        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24367            Some(
24368                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24369                    .toggle_state(folded)
24370                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24371                        if folded {
24372                            this.unfold_at(buffer_row, window, cx);
24373                        } else {
24374                            this.fold_at(buffer_row, window, cx);
24375                        }
24376                    }))
24377                    .into_any_element(),
24378            )
24379        } else {
24380            None
24381        }
24382    }
24383
24384    pub fn render_crease_trailer(
24385        &self,
24386        buffer_row: MultiBufferRow,
24387        window: &mut Window,
24388        cx: &mut App,
24389    ) -> Option<AnyElement> {
24390        let folded = self.is_line_folded(buffer_row);
24391        if let Crease::Inline { render_trailer, .. } = self
24392            .crease_snapshot
24393            .query_row(buffer_row, self.buffer_snapshot())?
24394        {
24395            let render_trailer = render_trailer.as_ref()?;
24396            Some(render_trailer(buffer_row, folded, window, cx))
24397        } else {
24398            None
24399        }
24400    }
24401}
24402
24403impl Deref for EditorSnapshot {
24404    type Target = DisplaySnapshot;
24405
24406    fn deref(&self) -> &Self::Target {
24407        &self.display_snapshot
24408    }
24409}
24410
24411#[derive(Clone, Debug, PartialEq, Eq)]
24412pub enum EditorEvent {
24413    InputIgnored {
24414        text: Arc<str>,
24415    },
24416    InputHandled {
24417        utf16_range_to_replace: Option<Range<isize>>,
24418        text: Arc<str>,
24419    },
24420    ExcerptsAdded {
24421        buffer: Entity<Buffer>,
24422        predecessor: ExcerptId,
24423        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24424    },
24425    ExcerptsRemoved {
24426        ids: Vec<ExcerptId>,
24427        removed_buffer_ids: Vec<BufferId>,
24428    },
24429    BufferFoldToggled {
24430        ids: Vec<ExcerptId>,
24431        folded: bool,
24432    },
24433    ExcerptsEdited {
24434        ids: Vec<ExcerptId>,
24435    },
24436    ExcerptsExpanded {
24437        ids: Vec<ExcerptId>,
24438    },
24439    BufferEdited,
24440    Edited {
24441        transaction_id: clock::Lamport,
24442    },
24443    Reparsed(BufferId),
24444    Focused,
24445    FocusedIn,
24446    Blurred,
24447    DirtyChanged,
24448    Saved,
24449    TitleChanged,
24450    SelectionsChanged {
24451        local: bool,
24452    },
24453    ScrollPositionChanged {
24454        local: bool,
24455        autoscroll: bool,
24456    },
24457    TransactionUndone {
24458        transaction_id: clock::Lamport,
24459    },
24460    TransactionBegun {
24461        transaction_id: clock::Lamport,
24462    },
24463    CursorShapeChanged,
24464    BreadcrumbsChanged,
24465    PushedToNavHistory {
24466        anchor: Anchor,
24467        is_deactivate: bool,
24468    },
24469}
24470
24471impl EventEmitter<EditorEvent> for Editor {}
24472
24473impl Focusable for Editor {
24474    fn focus_handle(&self, _cx: &App) -> FocusHandle {
24475        self.focus_handle.clone()
24476    }
24477}
24478
24479impl Render for Editor {
24480    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24481        let settings = ThemeSettings::get_global(cx);
24482
24483        let mut text_style = match self.mode {
24484            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24485                color: cx.theme().colors().editor_foreground,
24486                font_family: settings.ui_font.family.clone(),
24487                font_features: settings.ui_font.features.clone(),
24488                font_fallbacks: settings.ui_font.fallbacks.clone(),
24489                font_size: rems(0.875).into(),
24490                font_weight: settings.ui_font.weight,
24491                line_height: relative(settings.buffer_line_height.value()),
24492                ..Default::default()
24493            },
24494            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24495                color: cx.theme().colors().editor_foreground,
24496                font_family: settings.buffer_font.family.clone(),
24497                font_features: settings.buffer_font.features.clone(),
24498                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24499                font_size: settings.buffer_font_size(cx).into(),
24500                font_weight: settings.buffer_font.weight,
24501                line_height: relative(settings.buffer_line_height.value()),
24502                ..Default::default()
24503            },
24504        };
24505        if let Some(text_style_refinement) = &self.text_style_refinement {
24506            text_style.refine(text_style_refinement)
24507        }
24508
24509        let background = match self.mode {
24510            EditorMode::SingleLine => cx.theme().system().transparent,
24511            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24512            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24513            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24514        };
24515
24516        EditorElement::new(
24517            &cx.entity(),
24518            EditorStyle {
24519                background,
24520                border: cx.theme().colors().border,
24521                local_player: cx.theme().players().local(),
24522                text: text_style,
24523                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24524                syntax: cx.theme().syntax().clone(),
24525                status: cx.theme().status().clone(),
24526                inlay_hints_style: make_inlay_hints_style(cx),
24527                edit_prediction_styles: make_suggestion_styles(cx),
24528                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24529                show_underlines: self.diagnostics_enabled(),
24530            },
24531        )
24532    }
24533}
24534
24535impl EntityInputHandler for Editor {
24536    fn text_for_range(
24537        &mut self,
24538        range_utf16: Range<usize>,
24539        adjusted_range: &mut Option<Range<usize>>,
24540        _: &mut Window,
24541        cx: &mut Context<Self>,
24542    ) -> Option<String> {
24543        let snapshot = self.buffer.read(cx).read(cx);
24544        let start = snapshot.clip_offset_utf16(
24545            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
24546            Bias::Left,
24547        );
24548        let end = snapshot.clip_offset_utf16(
24549            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
24550            Bias::Right,
24551        );
24552        if (start.0.0..end.0.0) != range_utf16 {
24553            adjusted_range.replace(start.0.0..end.0.0);
24554        }
24555        Some(snapshot.text_for_range(start..end).collect())
24556    }
24557
24558    fn selected_text_range(
24559        &mut self,
24560        ignore_disabled_input: bool,
24561        _: &mut Window,
24562        cx: &mut Context<Self>,
24563    ) -> Option<UTF16Selection> {
24564        // Prevent the IME menu from appearing when holding down an alphabetic key
24565        // while input is disabled.
24566        if !ignore_disabled_input && !self.input_enabled {
24567            return None;
24568        }
24569
24570        let selection = self
24571            .selections
24572            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24573        let range = selection.range();
24574
24575        Some(UTF16Selection {
24576            range: range.start.0.0..range.end.0.0,
24577            reversed: selection.reversed,
24578        })
24579    }
24580
24581    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24582        let snapshot = self.buffer.read(cx).read(cx);
24583        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24584        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
24585    }
24586
24587    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24588        self.clear_highlights::<InputComposition>(cx);
24589        self.ime_transaction.take();
24590    }
24591
24592    fn replace_text_in_range(
24593        &mut self,
24594        range_utf16: Option<Range<usize>>,
24595        text: &str,
24596        window: &mut Window,
24597        cx: &mut Context<Self>,
24598    ) {
24599        if !self.input_enabled {
24600            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24601            return;
24602        }
24603
24604        self.transact(window, cx, |this, window, cx| {
24605            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24606                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24607                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24608                Some(this.selection_replacement_ranges(range_utf16, cx))
24609            } else {
24610                this.marked_text_ranges(cx)
24611            };
24612
24613            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24614                let newest_selection_id = this.selections.newest_anchor().id;
24615                this.selections
24616                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24617                    .iter()
24618                    .zip(ranges_to_replace.iter())
24619                    .find_map(|(selection, range)| {
24620                        if selection.id == newest_selection_id {
24621                            Some(
24622                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24623                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24624                            )
24625                        } else {
24626                            None
24627                        }
24628                    })
24629            });
24630
24631            cx.emit(EditorEvent::InputHandled {
24632                utf16_range_to_replace: range_to_replace,
24633                text: text.into(),
24634            });
24635
24636            if let Some(new_selected_ranges) = new_selected_ranges {
24637                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24638                    selections.select_ranges(new_selected_ranges)
24639                });
24640                this.backspace(&Default::default(), window, cx);
24641            }
24642
24643            this.handle_input(text, window, cx);
24644        });
24645
24646        if let Some(transaction) = self.ime_transaction {
24647            self.buffer.update(cx, |buffer, cx| {
24648                buffer.group_until_transaction(transaction, cx);
24649            });
24650        }
24651
24652        self.unmark_text(window, cx);
24653    }
24654
24655    fn replace_and_mark_text_in_range(
24656        &mut self,
24657        range_utf16: Option<Range<usize>>,
24658        text: &str,
24659        new_selected_range_utf16: Option<Range<usize>>,
24660        window: &mut Window,
24661        cx: &mut Context<Self>,
24662    ) {
24663        if !self.input_enabled {
24664            return;
24665        }
24666
24667        let transaction = self.transact(window, cx, |this, window, cx| {
24668            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24669                let snapshot = this.buffer.read(cx).read(cx);
24670                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24671                    for marked_range in &mut marked_ranges {
24672                        marked_range.end = marked_range.start + relative_range_utf16.end;
24673                        marked_range.start += relative_range_utf16.start;
24674                        marked_range.start =
24675                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24676                        marked_range.end =
24677                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24678                    }
24679                }
24680                Some(marked_ranges)
24681            } else if let Some(range_utf16) = range_utf16 {
24682                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24683                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24684                Some(this.selection_replacement_ranges(range_utf16, cx))
24685            } else {
24686                None
24687            };
24688
24689            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24690                let newest_selection_id = this.selections.newest_anchor().id;
24691                this.selections
24692                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24693                    .iter()
24694                    .zip(ranges_to_replace.iter())
24695                    .find_map(|(selection, range)| {
24696                        if selection.id == newest_selection_id {
24697                            Some(
24698                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24699                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24700                            )
24701                        } else {
24702                            None
24703                        }
24704                    })
24705            });
24706
24707            cx.emit(EditorEvent::InputHandled {
24708                utf16_range_to_replace: range_to_replace,
24709                text: text.into(),
24710            });
24711
24712            if let Some(ranges) = ranges_to_replace {
24713                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24714                    s.select_ranges(ranges)
24715                });
24716            }
24717
24718            let marked_ranges = {
24719                let snapshot = this.buffer.read(cx).read(cx);
24720                this.selections
24721                    .disjoint_anchors_arc()
24722                    .iter()
24723                    .map(|selection| {
24724                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24725                    })
24726                    .collect::<Vec<_>>()
24727            };
24728
24729            if text.is_empty() {
24730                this.unmark_text(window, cx);
24731            } else {
24732                this.highlight_text::<InputComposition>(
24733                    marked_ranges.clone(),
24734                    HighlightStyle {
24735                        underline: Some(UnderlineStyle {
24736                            thickness: px(1.),
24737                            color: None,
24738                            wavy: false,
24739                        }),
24740                        ..Default::default()
24741                    },
24742                    cx,
24743                );
24744            }
24745
24746            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24747            let use_autoclose = this.use_autoclose;
24748            let use_auto_surround = this.use_auto_surround;
24749            this.set_use_autoclose(false);
24750            this.set_use_auto_surround(false);
24751            this.handle_input(text, window, cx);
24752            this.set_use_autoclose(use_autoclose);
24753            this.set_use_auto_surround(use_auto_surround);
24754
24755            if let Some(new_selected_range) = new_selected_range_utf16 {
24756                let snapshot = this.buffer.read(cx).read(cx);
24757                let new_selected_ranges = marked_ranges
24758                    .into_iter()
24759                    .map(|marked_range| {
24760                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24761                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
24762                            insertion_start.0 + new_selected_range.start,
24763                        ));
24764                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
24765                            insertion_start.0 + new_selected_range.end,
24766                        ));
24767                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24768                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24769                    })
24770                    .collect::<Vec<_>>();
24771
24772                drop(snapshot);
24773                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24774                    selections.select_ranges(new_selected_ranges)
24775                });
24776            }
24777        });
24778
24779        self.ime_transaction = self.ime_transaction.or(transaction);
24780        if let Some(transaction) = self.ime_transaction {
24781            self.buffer.update(cx, |buffer, cx| {
24782                buffer.group_until_transaction(transaction, cx);
24783            });
24784        }
24785
24786        if self.text_highlights::<InputComposition>(cx).is_none() {
24787            self.ime_transaction.take();
24788        }
24789    }
24790
24791    fn bounds_for_range(
24792        &mut self,
24793        range_utf16: Range<usize>,
24794        element_bounds: gpui::Bounds<Pixels>,
24795        window: &mut Window,
24796        cx: &mut Context<Self>,
24797    ) -> Option<gpui::Bounds<Pixels>> {
24798        let text_layout_details = self.text_layout_details(window);
24799        let CharacterDimensions {
24800            em_width,
24801            em_advance,
24802            line_height,
24803        } = self.character_dimensions(window);
24804
24805        let snapshot = self.snapshot(window, cx);
24806        let scroll_position = snapshot.scroll_position();
24807        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24808
24809        let start =
24810            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
24811        let x = Pixels::from(
24812            ScrollOffset::from(
24813                snapshot.x_for_display_point(start, &text_layout_details)
24814                    + self.gutter_dimensions.full_width(),
24815            ) - scroll_left,
24816        );
24817        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24818
24819        Some(Bounds {
24820            origin: element_bounds.origin + point(x, y),
24821            size: size(em_width, line_height),
24822        })
24823    }
24824
24825    fn character_index_for_point(
24826        &mut self,
24827        point: gpui::Point<Pixels>,
24828        _window: &mut Window,
24829        _cx: &mut Context<Self>,
24830    ) -> Option<usize> {
24831        let position_map = self.last_position_map.as_ref()?;
24832        if !position_map.text_hitbox.contains(&point) {
24833            return None;
24834        }
24835        let display_point = position_map.point_for_position(point).previous_valid;
24836        let anchor = position_map
24837            .snapshot
24838            .display_point_to_anchor(display_point, Bias::Left);
24839        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24840        Some(utf16_offset.0.0)
24841    }
24842
24843    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24844        self.input_enabled
24845    }
24846}
24847
24848trait SelectionExt {
24849    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24850    fn spanned_rows(
24851        &self,
24852        include_end_if_at_line_start: bool,
24853        map: &DisplaySnapshot,
24854    ) -> Range<MultiBufferRow>;
24855}
24856
24857impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24858    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24859        let start = self
24860            .start
24861            .to_point(map.buffer_snapshot())
24862            .to_display_point(map);
24863        let end = self
24864            .end
24865            .to_point(map.buffer_snapshot())
24866            .to_display_point(map);
24867        if self.reversed {
24868            end..start
24869        } else {
24870            start..end
24871        }
24872    }
24873
24874    fn spanned_rows(
24875        &self,
24876        include_end_if_at_line_start: bool,
24877        map: &DisplaySnapshot,
24878    ) -> Range<MultiBufferRow> {
24879        let start = self.start.to_point(map.buffer_snapshot());
24880        let mut end = self.end.to_point(map.buffer_snapshot());
24881        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24882            end.row -= 1;
24883        }
24884
24885        let buffer_start = map.prev_line_boundary(start).0;
24886        let buffer_end = map.next_line_boundary(end).0;
24887        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24888    }
24889}
24890
24891impl<T: InvalidationRegion> InvalidationStack<T> {
24892    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24893    where
24894        S: Clone + ToOffset,
24895    {
24896        while let Some(region) = self.last() {
24897            let all_selections_inside_invalidation_ranges =
24898                if selections.len() == region.ranges().len() {
24899                    selections
24900                        .iter()
24901                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24902                        .all(|(selection, invalidation_range)| {
24903                            let head = selection.head().to_offset(buffer);
24904                            invalidation_range.start <= head && invalidation_range.end >= head
24905                        })
24906                } else {
24907                    false
24908                };
24909
24910            if all_selections_inside_invalidation_ranges {
24911                break;
24912            } else {
24913                self.pop();
24914            }
24915        }
24916    }
24917}
24918
24919impl<T> Default for InvalidationStack<T> {
24920    fn default() -> Self {
24921        Self(Default::default())
24922    }
24923}
24924
24925impl<T> Deref for InvalidationStack<T> {
24926    type Target = Vec<T>;
24927
24928    fn deref(&self) -> &Self::Target {
24929        &self.0
24930    }
24931}
24932
24933impl<T> DerefMut for InvalidationStack<T> {
24934    fn deref_mut(&mut self) -> &mut Self::Target {
24935        &mut self.0
24936    }
24937}
24938
24939impl InvalidationRegion for SnippetState {
24940    fn ranges(&self) -> &[Range<Anchor>] {
24941        &self.ranges[self.active_index]
24942    }
24943}
24944
24945fn edit_prediction_edit_text(
24946    current_snapshot: &BufferSnapshot,
24947    edits: &[(Range<Anchor>, impl AsRef<str>)],
24948    edit_preview: &EditPreview,
24949    include_deletions: bool,
24950    cx: &App,
24951) -> HighlightedText {
24952    let edits = edits
24953        .iter()
24954        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24955        .collect::<Vec<_>>();
24956
24957    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24958}
24959
24960fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24961    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24962    // Just show the raw edit text with basic styling
24963    let mut text = String::new();
24964    let mut highlights = Vec::new();
24965
24966    let insertion_highlight_style = HighlightStyle {
24967        color: Some(cx.theme().colors().text),
24968        ..Default::default()
24969    };
24970
24971    for (_, edit_text) in edits {
24972        let start_offset = text.len();
24973        text.push_str(edit_text);
24974        let end_offset = text.len();
24975
24976        if start_offset < end_offset {
24977            highlights.push((start_offset..end_offset, insertion_highlight_style));
24978        }
24979    }
24980
24981    HighlightedText {
24982        text: text.into(),
24983        highlights,
24984    }
24985}
24986
24987pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24988    match severity {
24989        lsp::DiagnosticSeverity::ERROR => colors.error,
24990        lsp::DiagnosticSeverity::WARNING => colors.warning,
24991        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24992        lsp::DiagnosticSeverity::HINT => colors.info,
24993        _ => colors.ignored,
24994    }
24995}
24996
24997pub fn styled_runs_for_code_label<'a>(
24998    label: &'a CodeLabel,
24999    syntax_theme: &'a theme::SyntaxTheme,
25000    local_player: &'a theme::PlayerColor,
25001) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
25002    let fade_out = HighlightStyle {
25003        fade_out: Some(0.35),
25004        ..Default::default()
25005    };
25006
25007    let mut prev_end = label.filter_range.end;
25008    label
25009        .runs
25010        .iter()
25011        .enumerate()
25012        .flat_map(move |(ix, (range, highlight_id))| {
25013            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
25014                HighlightStyle {
25015                    color: Some(local_player.cursor),
25016                    ..Default::default()
25017                }
25018            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
25019                HighlightStyle {
25020                    background_color: Some(local_player.selection),
25021                    ..Default::default()
25022                }
25023            } else if let Some(style) = highlight_id.style(syntax_theme) {
25024                style
25025            } else {
25026                return Default::default();
25027            };
25028            let muted_style = style.highlight(fade_out);
25029
25030            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
25031            if range.start >= label.filter_range.end {
25032                if range.start > prev_end {
25033                    runs.push((prev_end..range.start, fade_out));
25034                }
25035                runs.push((range.clone(), muted_style));
25036            } else if range.end <= label.filter_range.end {
25037                runs.push((range.clone(), style));
25038            } else {
25039                runs.push((range.start..label.filter_range.end, style));
25040                runs.push((label.filter_range.end..range.end, muted_style));
25041            }
25042            prev_end = cmp::max(prev_end, range.end);
25043
25044            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
25045                runs.push((prev_end..label.text.len(), fade_out));
25046            }
25047
25048            runs
25049        })
25050}
25051
25052pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
25053    let mut prev_index = 0;
25054    let mut prev_codepoint: Option<char> = None;
25055    text.char_indices()
25056        .chain([(text.len(), '\0')])
25057        .filter_map(move |(index, codepoint)| {
25058            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25059            let is_boundary = index == text.len()
25060                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
25061                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
25062            if is_boundary {
25063                let chunk = &text[prev_index..index];
25064                prev_index = index;
25065                Some(chunk)
25066            } else {
25067                None
25068            }
25069        })
25070}
25071
25072/// Given a string of text immediately before the cursor, iterates over possible
25073/// strings a snippet could match to. More precisely: returns an iterator over
25074/// suffixes of `text` created by splitting at word boundaries (before & after
25075/// every non-word character).
25076///
25077/// Shorter suffixes are returned first.
25078pub(crate) fn snippet_candidate_suffixes(
25079    text: &str,
25080    is_word_char: impl Fn(char) -> bool,
25081) -> impl std::iter::Iterator<Item = &str> {
25082    let mut prev_index = text.len();
25083    let mut prev_codepoint = None;
25084    text.char_indices()
25085        .rev()
25086        .chain([(0, '\0')])
25087        .filter_map(move |(index, codepoint)| {
25088            let prev_index = std::mem::replace(&mut prev_index, index);
25089            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25090            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
25091                None
25092            } else {
25093                let chunk = &text[prev_index..]; // go to end of string
25094                Some(chunk)
25095            }
25096        })
25097}
25098
25099pub trait RangeToAnchorExt: Sized {
25100    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25101
25102    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25103        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25104        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25105    }
25106}
25107
25108impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25109    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25110        let start_offset = self.start.to_offset(snapshot);
25111        let end_offset = self.end.to_offset(snapshot);
25112        if start_offset == end_offset {
25113            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25114        } else {
25115            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25116        }
25117    }
25118}
25119
25120pub trait RowExt {
25121    fn as_f64(&self) -> f64;
25122
25123    fn next_row(&self) -> Self;
25124
25125    fn previous_row(&self) -> Self;
25126
25127    fn minus(&self, other: Self) -> u32;
25128}
25129
25130impl RowExt for DisplayRow {
25131    fn as_f64(&self) -> f64 {
25132        self.0 as _
25133    }
25134
25135    fn next_row(&self) -> Self {
25136        Self(self.0 + 1)
25137    }
25138
25139    fn previous_row(&self) -> Self {
25140        Self(self.0.saturating_sub(1))
25141    }
25142
25143    fn minus(&self, other: Self) -> u32 {
25144        self.0 - other.0
25145    }
25146}
25147
25148impl RowExt for MultiBufferRow {
25149    fn as_f64(&self) -> f64 {
25150        self.0 as _
25151    }
25152
25153    fn next_row(&self) -> Self {
25154        Self(self.0 + 1)
25155    }
25156
25157    fn previous_row(&self) -> Self {
25158        Self(self.0.saturating_sub(1))
25159    }
25160
25161    fn minus(&self, other: Self) -> u32 {
25162        self.0 - other.0
25163    }
25164}
25165
25166trait RowRangeExt {
25167    type Row;
25168
25169    fn len(&self) -> usize;
25170
25171    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25172}
25173
25174impl RowRangeExt for Range<MultiBufferRow> {
25175    type Row = MultiBufferRow;
25176
25177    fn len(&self) -> usize {
25178        (self.end.0 - self.start.0) as usize
25179    }
25180
25181    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25182        (self.start.0..self.end.0).map(MultiBufferRow)
25183    }
25184}
25185
25186impl RowRangeExt for Range<DisplayRow> {
25187    type Row = DisplayRow;
25188
25189    fn len(&self) -> usize {
25190        (self.end.0 - self.start.0) as usize
25191    }
25192
25193    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25194        (self.start.0..self.end.0).map(DisplayRow)
25195    }
25196}
25197
25198/// If select range has more than one line, we
25199/// just point the cursor to range.start.
25200fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25201    if range.start.row == range.end.row {
25202        range
25203    } else {
25204        range.start..range.start
25205    }
25206}
25207pub struct KillRing(ClipboardItem);
25208impl Global for KillRing {}
25209
25210const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25211
25212enum BreakpointPromptEditAction {
25213    Log,
25214    Condition,
25215    HitCondition,
25216}
25217
25218struct BreakpointPromptEditor {
25219    pub(crate) prompt: Entity<Editor>,
25220    editor: WeakEntity<Editor>,
25221    breakpoint_anchor: Anchor,
25222    breakpoint: Breakpoint,
25223    edit_action: BreakpointPromptEditAction,
25224    block_ids: HashSet<CustomBlockId>,
25225    editor_margins: Arc<Mutex<EditorMargins>>,
25226    _subscriptions: Vec<Subscription>,
25227}
25228
25229impl BreakpointPromptEditor {
25230    const MAX_LINES: u8 = 4;
25231
25232    fn new(
25233        editor: WeakEntity<Editor>,
25234        breakpoint_anchor: Anchor,
25235        breakpoint: Breakpoint,
25236        edit_action: BreakpointPromptEditAction,
25237        window: &mut Window,
25238        cx: &mut Context<Self>,
25239    ) -> Self {
25240        let base_text = match edit_action {
25241            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25242            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25243            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25244        }
25245        .map(|msg| msg.to_string())
25246        .unwrap_or_default();
25247
25248        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25249        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25250
25251        let prompt = cx.new(|cx| {
25252            let mut prompt = Editor::new(
25253                EditorMode::AutoHeight {
25254                    min_lines: 1,
25255                    max_lines: Some(Self::MAX_LINES as usize),
25256                },
25257                buffer,
25258                None,
25259                window,
25260                cx,
25261            );
25262            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25263            prompt.set_show_cursor_when_unfocused(false, cx);
25264            prompt.set_placeholder_text(
25265                match edit_action {
25266                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25267                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25268                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25269                },
25270                window,
25271                cx,
25272            );
25273
25274            prompt
25275        });
25276
25277        Self {
25278            prompt,
25279            editor,
25280            breakpoint_anchor,
25281            breakpoint,
25282            edit_action,
25283            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25284            block_ids: Default::default(),
25285            _subscriptions: vec![],
25286        }
25287    }
25288
25289    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25290        self.block_ids.extend(block_ids)
25291    }
25292
25293    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25294        if let Some(editor) = self.editor.upgrade() {
25295            let message = self
25296                .prompt
25297                .read(cx)
25298                .buffer
25299                .read(cx)
25300                .as_singleton()
25301                .expect("A multi buffer in breakpoint prompt isn't possible")
25302                .read(cx)
25303                .as_rope()
25304                .to_string();
25305
25306            editor.update(cx, |editor, cx| {
25307                editor.edit_breakpoint_at_anchor(
25308                    self.breakpoint_anchor,
25309                    self.breakpoint.clone(),
25310                    match self.edit_action {
25311                        BreakpointPromptEditAction::Log => {
25312                            BreakpointEditAction::EditLogMessage(message.into())
25313                        }
25314                        BreakpointPromptEditAction::Condition => {
25315                            BreakpointEditAction::EditCondition(message.into())
25316                        }
25317                        BreakpointPromptEditAction::HitCondition => {
25318                            BreakpointEditAction::EditHitCondition(message.into())
25319                        }
25320                    },
25321                    cx,
25322                );
25323
25324                editor.remove_blocks(self.block_ids.clone(), None, cx);
25325                cx.focus_self(window);
25326            });
25327        }
25328    }
25329
25330    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25331        self.editor
25332            .update(cx, |editor, cx| {
25333                editor.remove_blocks(self.block_ids.clone(), None, cx);
25334                window.focus(&editor.focus_handle);
25335            })
25336            .log_err();
25337    }
25338
25339    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25340        let settings = ThemeSettings::get_global(cx);
25341        let text_style = TextStyle {
25342            color: if self.prompt.read(cx).read_only(cx) {
25343                cx.theme().colors().text_disabled
25344            } else {
25345                cx.theme().colors().text
25346            },
25347            font_family: settings.buffer_font.family.clone(),
25348            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25349            font_size: settings.buffer_font_size(cx).into(),
25350            font_weight: settings.buffer_font.weight,
25351            line_height: relative(settings.buffer_line_height.value()),
25352            ..Default::default()
25353        };
25354        EditorElement::new(
25355            &self.prompt,
25356            EditorStyle {
25357                background: cx.theme().colors().editor_background,
25358                local_player: cx.theme().players().local(),
25359                text: text_style,
25360                ..Default::default()
25361            },
25362        )
25363    }
25364}
25365
25366impl Render for BreakpointPromptEditor {
25367    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25368        let editor_margins = *self.editor_margins.lock();
25369        let gutter_dimensions = editor_margins.gutter;
25370        h_flex()
25371            .key_context("Editor")
25372            .bg(cx.theme().colors().editor_background)
25373            .border_y_1()
25374            .border_color(cx.theme().status().info_border)
25375            .size_full()
25376            .py(window.line_height() / 2.5)
25377            .on_action(cx.listener(Self::confirm))
25378            .on_action(cx.listener(Self::cancel))
25379            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25380            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25381    }
25382}
25383
25384impl Focusable for BreakpointPromptEditor {
25385    fn focus_handle(&self, cx: &App) -> FocusHandle {
25386        self.prompt.focus_handle(cx)
25387    }
25388}
25389
25390fn all_edits_insertions_or_deletions(
25391    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25392    snapshot: &MultiBufferSnapshot,
25393) -> bool {
25394    let mut all_insertions = true;
25395    let mut all_deletions = true;
25396
25397    for (range, new_text) in edits.iter() {
25398        let range_is_empty = range.to_offset(snapshot).is_empty();
25399        let text_is_empty = new_text.is_empty();
25400
25401        if range_is_empty != text_is_empty {
25402            if range_is_empty {
25403                all_deletions = false;
25404            } else {
25405                all_insertions = false;
25406            }
25407        } else {
25408            return false;
25409        }
25410
25411        if !all_insertions && !all_deletions {
25412            return false;
25413        }
25414    }
25415    all_insertions || all_deletions
25416}
25417
25418struct MissingEditPredictionKeybindingTooltip;
25419
25420impl Render for MissingEditPredictionKeybindingTooltip {
25421    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25422        ui::tooltip_container(cx, |container, cx| {
25423            container
25424                .flex_shrink_0()
25425                .max_w_80()
25426                .min_h(rems_from_px(124.))
25427                .justify_between()
25428                .child(
25429                    v_flex()
25430                        .flex_1()
25431                        .text_ui_sm(cx)
25432                        .child(Label::new("Conflict with Accept Keybinding"))
25433                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25434                )
25435                .child(
25436                    h_flex()
25437                        .pb_1()
25438                        .gap_1()
25439                        .items_end()
25440                        .w_full()
25441                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25442                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25443                        }))
25444                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25445                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25446                        })),
25447                )
25448        })
25449    }
25450}
25451
25452#[derive(Debug, Clone, Copy, PartialEq)]
25453pub struct LineHighlight {
25454    pub background: Background,
25455    pub border: Option<gpui::Hsla>,
25456    pub include_gutter: bool,
25457    pub type_id: Option<TypeId>,
25458}
25459
25460struct LineManipulationResult {
25461    pub new_text: String,
25462    pub line_count_before: usize,
25463    pub line_count_after: usize,
25464}
25465
25466fn render_diff_hunk_controls(
25467    row: u32,
25468    status: &DiffHunkStatus,
25469    hunk_range: Range<Anchor>,
25470    is_created_file: bool,
25471    line_height: Pixels,
25472    editor: &Entity<Editor>,
25473    _window: &mut Window,
25474    cx: &mut App,
25475) -> AnyElement {
25476    h_flex()
25477        .h(line_height)
25478        .mr_1()
25479        .gap_1()
25480        .px_0p5()
25481        .pb_1()
25482        .border_x_1()
25483        .border_b_1()
25484        .border_color(cx.theme().colors().border_variant)
25485        .rounded_b_lg()
25486        .bg(cx.theme().colors().editor_background)
25487        .gap_1()
25488        .block_mouse_except_scroll()
25489        .shadow_md()
25490        .child(if status.has_secondary_hunk() {
25491            Button::new(("stage", row as u64), "Stage")
25492                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25493                .tooltip({
25494                    let focus_handle = editor.focus_handle(cx);
25495                    move |_window, cx| {
25496                        Tooltip::for_action_in(
25497                            "Stage Hunk",
25498                            &::git::ToggleStaged,
25499                            &focus_handle,
25500                            cx,
25501                        )
25502                    }
25503                })
25504                .on_click({
25505                    let editor = editor.clone();
25506                    move |_event, _window, cx| {
25507                        editor.update(cx, |editor, cx| {
25508                            editor.stage_or_unstage_diff_hunks(
25509                                true,
25510                                vec![hunk_range.start..hunk_range.start],
25511                                cx,
25512                            );
25513                        });
25514                    }
25515                })
25516        } else {
25517            Button::new(("unstage", row as u64), "Unstage")
25518                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25519                .tooltip({
25520                    let focus_handle = editor.focus_handle(cx);
25521                    move |_window, cx| {
25522                        Tooltip::for_action_in(
25523                            "Unstage Hunk",
25524                            &::git::ToggleStaged,
25525                            &focus_handle,
25526                            cx,
25527                        )
25528                    }
25529                })
25530                .on_click({
25531                    let editor = editor.clone();
25532                    move |_event, _window, cx| {
25533                        editor.update(cx, |editor, cx| {
25534                            editor.stage_or_unstage_diff_hunks(
25535                                false,
25536                                vec![hunk_range.start..hunk_range.start],
25537                                cx,
25538                            );
25539                        });
25540                    }
25541                })
25542        })
25543        .child(
25544            Button::new(("restore", row as u64), "Restore")
25545                .tooltip({
25546                    let focus_handle = editor.focus_handle(cx);
25547                    move |_window, cx| {
25548                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25549                    }
25550                })
25551                .on_click({
25552                    let editor = editor.clone();
25553                    move |_event, window, cx| {
25554                        editor.update(cx, |editor, cx| {
25555                            let snapshot = editor.snapshot(window, cx);
25556                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25557                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25558                        });
25559                    }
25560                })
25561                .disabled(is_created_file),
25562        )
25563        .when(
25564            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25565            |el| {
25566                el.child(
25567                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25568                        .shape(IconButtonShape::Square)
25569                        .icon_size(IconSize::Small)
25570                        // .disabled(!has_multiple_hunks)
25571                        .tooltip({
25572                            let focus_handle = editor.focus_handle(cx);
25573                            move |_window, cx| {
25574                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25575                            }
25576                        })
25577                        .on_click({
25578                            let editor = editor.clone();
25579                            move |_event, window, cx| {
25580                                editor.update(cx, |editor, cx| {
25581                                    let snapshot = editor.snapshot(window, cx);
25582                                    let position =
25583                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25584                                    editor.go_to_hunk_before_or_after_position(
25585                                        &snapshot,
25586                                        position,
25587                                        Direction::Next,
25588                                        window,
25589                                        cx,
25590                                    );
25591                                    editor.expand_selected_diff_hunks(cx);
25592                                });
25593                            }
25594                        }),
25595                )
25596                .child(
25597                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25598                        .shape(IconButtonShape::Square)
25599                        .icon_size(IconSize::Small)
25600                        // .disabled(!has_multiple_hunks)
25601                        .tooltip({
25602                            let focus_handle = editor.focus_handle(cx);
25603                            move |_window, cx| {
25604                                Tooltip::for_action_in(
25605                                    "Previous Hunk",
25606                                    &GoToPreviousHunk,
25607                                    &focus_handle,
25608                                    cx,
25609                                )
25610                            }
25611                        })
25612                        .on_click({
25613                            let editor = editor.clone();
25614                            move |_event, window, cx| {
25615                                editor.update(cx, |editor, cx| {
25616                                    let snapshot = editor.snapshot(window, cx);
25617                                    let point =
25618                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25619                                    editor.go_to_hunk_before_or_after_position(
25620                                        &snapshot,
25621                                        point,
25622                                        Direction::Prev,
25623                                        window,
25624                                        cx,
25625                                    );
25626                                    editor.expand_selected_diff_hunks(cx);
25627                                });
25628                            }
25629                        }),
25630                )
25631            },
25632        )
25633        .into_any_element()
25634}
25635
25636pub fn multibuffer_context_lines(cx: &App) -> u32 {
25637    EditorSettings::try_get(cx)
25638        .map(|settings| settings.excerpt_context_lines)
25639        .unwrap_or(2)
25640        .min(32)
25641}