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 menu_is_open = matches!(
 5513            self.context_menu.borrow().as_ref(),
 5514            Some(CodeContextMenu::Completions(_))
 5515        );
 5516
 5517        let language = buffer_snapshot
 5518            .language_at(buffer_position.text_anchor)
 5519            .map(|language| language.name());
 5520
 5521        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5522        let completion_settings = language_settings.completions.clone();
 5523
 5524        if !menu_is_open && trigger.is_some() && !language_settings.show_completions_on_input {
 5525            return;
 5526        }
 5527
 5528        let query: Option<Arc<String>> =
 5529            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5530                .map(|query| query.into());
 5531
 5532        drop(multibuffer_snapshot);
 5533
 5534        // Hide the current completions menu when query is empty. Without this, cached
 5535        // completions from before the trigger char may be reused (#32774).
 5536        if query.is_none() && menu_is_open {
 5537            self.hide_context_menu(window, cx);
 5538        }
 5539
 5540        let mut ignore_word_threshold = false;
 5541        let provider = match requested_source {
 5542            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5543            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5544                ignore_word_threshold = ignore_threshold;
 5545                None
 5546            }
 5547            Some(CompletionsMenuSource::SnippetChoices)
 5548            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5549                log::error!("bug: SnippetChoices requested_source is not handled");
 5550                None
 5551            }
 5552        };
 5553
 5554        let sort_completions = provider
 5555            .as_ref()
 5556            .is_some_and(|provider| provider.sort_completions());
 5557
 5558        let filter_completions = provider
 5559            .as_ref()
 5560            .is_none_or(|provider| provider.filter_completions());
 5561
 5562        let was_snippets_only = matches!(
 5563            completions_source,
 5564            Some(CompletionsMenuSource::SnippetsOnly)
 5565        );
 5566
 5567        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5568            if filter_completions {
 5569                menu.filter(
 5570                    query.clone().unwrap_or_default(),
 5571                    buffer_position.text_anchor,
 5572                    &buffer,
 5573                    provider.clone(),
 5574                    window,
 5575                    cx,
 5576                );
 5577            }
 5578            // When `is_incomplete` is false, no need to re-query completions when the current query
 5579            // is a suffix of the initial query.
 5580            let was_complete = !menu.is_incomplete;
 5581            if was_complete && !was_snippets_only {
 5582                // If the new query is a suffix of the old query (typing more characters) and
 5583                // the previous result was complete, the existing completions can be filtered.
 5584                //
 5585                // Note that snippet completions are always complete.
 5586                let query_matches = match (&menu.initial_query, &query) {
 5587                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5588                    (None, _) => true,
 5589                    _ => false,
 5590                };
 5591                if query_matches {
 5592                    let position_matches = if menu.initial_position == position {
 5593                        true
 5594                    } else {
 5595                        let snapshot = self.buffer.read(cx).read(cx);
 5596                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5597                    };
 5598                    if position_matches {
 5599                        return;
 5600                    }
 5601                }
 5602            }
 5603        };
 5604
 5605        let Anchor {
 5606            excerpt_id: buffer_excerpt_id,
 5607            text_anchor: buffer_position,
 5608            ..
 5609        } = buffer_position;
 5610
 5611        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5612            buffer_snapshot.surrounding_word(buffer_position, None)
 5613        {
 5614            let word_to_exclude = buffer_snapshot
 5615                .text_for_range(word_range.clone())
 5616                .collect::<String>();
 5617            (
 5618                buffer_snapshot.anchor_before(word_range.start)
 5619                    ..buffer_snapshot.anchor_after(buffer_position),
 5620                Some(word_to_exclude),
 5621            )
 5622        } else {
 5623            (buffer_position..buffer_position, None)
 5624        };
 5625
 5626        let show_completion_documentation = buffer_snapshot
 5627            .settings_at(buffer_position, cx)
 5628            .show_completion_documentation;
 5629
 5630        // The document can be large, so stay in reasonable bounds when searching for words,
 5631        // otherwise completion pop-up might be slow to appear.
 5632        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5633        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5634        let min_word_search = buffer_snapshot.clip_point(
 5635            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5636            Bias::Left,
 5637        );
 5638        let max_word_search = buffer_snapshot.clip_point(
 5639            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5640            Bias::Right,
 5641        );
 5642        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5643            ..buffer_snapshot.point_to_offset(max_word_search);
 5644
 5645        let skip_digits = query
 5646            .as_ref()
 5647            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5648
 5649        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5650            trigger.as_ref().is_none_or(|trigger| {
 5651                provider.is_completion_trigger(
 5652                    &buffer,
 5653                    position.text_anchor,
 5654                    trigger,
 5655                    trigger_in_words,
 5656                    cx,
 5657                )
 5658            })
 5659        });
 5660
 5661        let provider_responses = if let Some(provider) = &provider
 5662            && load_provider_completions
 5663        {
 5664            let trigger_character =
 5665                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5666            let completion_context = CompletionContext {
 5667                trigger_kind: match &trigger_character {
 5668                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5669                    None => CompletionTriggerKind::INVOKED,
 5670                },
 5671                trigger_character,
 5672            };
 5673
 5674            provider.completions(
 5675                buffer_excerpt_id,
 5676                &buffer,
 5677                buffer_position,
 5678                completion_context,
 5679                window,
 5680                cx,
 5681            )
 5682        } else {
 5683            Task::ready(Ok(Vec::new()))
 5684        };
 5685
 5686        let load_word_completions = if !self.word_completions_enabled {
 5687            false
 5688        } else if requested_source
 5689            == Some(CompletionsMenuSource::Words {
 5690                ignore_threshold: true,
 5691            })
 5692        {
 5693            true
 5694        } else {
 5695            load_provider_completions
 5696                && completion_settings.words != WordsCompletionMode::Disabled
 5697                && (ignore_word_threshold || {
 5698                    let words_min_length = completion_settings.words_min_length;
 5699                    // check whether word has at least `words_min_length` characters
 5700                    let query_chars = query.iter().flat_map(|q| q.chars());
 5701                    query_chars.take(words_min_length).count() == words_min_length
 5702                })
 5703        };
 5704
 5705        let mut words = if load_word_completions {
 5706            cx.background_spawn({
 5707                let buffer_snapshot = buffer_snapshot.clone();
 5708                async move {
 5709                    buffer_snapshot.words_in_range(WordsQuery {
 5710                        fuzzy_contents: None,
 5711                        range: word_search_range,
 5712                        skip_digits,
 5713                    })
 5714                }
 5715            })
 5716        } else {
 5717            Task::ready(BTreeMap::default())
 5718        };
 5719
 5720        let snippets = if let Some(provider) = &provider
 5721            && provider.show_snippets()
 5722            && let Some(project) = self.project()
 5723        {
 5724            let char_classifier = buffer_snapshot
 5725                .char_classifier_at(buffer_position)
 5726                .scope_context(Some(CharScopeContext::Completion));
 5727            project.update(cx, |project, cx| {
 5728                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5729            })
 5730        } else {
 5731            Task::ready(Ok(CompletionResponse {
 5732                completions: Vec::new(),
 5733                display_options: Default::default(),
 5734                is_incomplete: false,
 5735            }))
 5736        };
 5737
 5738        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5739
 5740        let id = post_inc(&mut self.next_completion_id);
 5741        let task = cx.spawn_in(window, async move |editor, cx| {
 5742            let Ok(()) = editor.update(cx, |this, _| {
 5743                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5744            }) else {
 5745                return;
 5746            };
 5747
 5748            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5749            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5750            let mut completions = Vec::new();
 5751            let mut is_incomplete = false;
 5752            let mut display_options: Option<CompletionDisplayOptions> = None;
 5753            if let Some(provider_responses) = provider_responses.await.log_err()
 5754                && !provider_responses.is_empty()
 5755            {
 5756                for response in provider_responses {
 5757                    completions.extend(response.completions);
 5758                    is_incomplete = is_incomplete || response.is_incomplete;
 5759                    match display_options.as_mut() {
 5760                        None => {
 5761                            display_options = Some(response.display_options);
 5762                        }
 5763                        Some(options) => options.merge(&response.display_options),
 5764                    }
 5765                }
 5766                if completion_settings.words == WordsCompletionMode::Fallback {
 5767                    words = Task::ready(BTreeMap::default());
 5768                }
 5769            }
 5770            let display_options = display_options.unwrap_or_default();
 5771
 5772            let mut words = words.await;
 5773            if let Some(word_to_exclude) = &word_to_exclude {
 5774                words.remove(word_to_exclude);
 5775            }
 5776            for lsp_completion in &completions {
 5777                words.remove(&lsp_completion.new_text);
 5778            }
 5779            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5780                replace_range: word_replace_range.clone(),
 5781                new_text: word.clone(),
 5782                label: CodeLabel::plain(word, None),
 5783                match_start: None,
 5784                snippet_deduplication_key: None,
 5785                icon_path: None,
 5786                documentation: None,
 5787                source: CompletionSource::BufferWord {
 5788                    word_range,
 5789                    resolved: false,
 5790                },
 5791                insert_text_mode: Some(InsertTextMode::AS_IS),
 5792                confirm: None,
 5793            }));
 5794
 5795            completions.extend(
 5796                snippets
 5797                    .await
 5798                    .into_iter()
 5799                    .flat_map(|response| response.completions),
 5800            );
 5801
 5802            let menu = if completions.is_empty() {
 5803                None
 5804            } else {
 5805                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5806                    let languages = editor
 5807                        .workspace
 5808                        .as_ref()
 5809                        .and_then(|(workspace, _)| workspace.upgrade())
 5810                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5811                    let menu = CompletionsMenu::new(
 5812                        id,
 5813                        requested_source.unwrap_or(if load_provider_completions {
 5814                            CompletionsMenuSource::Normal
 5815                        } else {
 5816                            CompletionsMenuSource::SnippetsOnly
 5817                        }),
 5818                        sort_completions,
 5819                        show_completion_documentation,
 5820                        position,
 5821                        query.clone(),
 5822                        is_incomplete,
 5823                        buffer.clone(),
 5824                        completions.into(),
 5825                        display_options,
 5826                        snippet_sort_order,
 5827                        languages,
 5828                        language,
 5829                        cx,
 5830                    );
 5831
 5832                    let query = if filter_completions { query } else { None };
 5833                    let matches_task = menu.do_async_filtering(
 5834                        query.unwrap_or_default(),
 5835                        buffer_position,
 5836                        &buffer,
 5837                        cx,
 5838                    );
 5839                    (menu, matches_task)
 5840                }) else {
 5841                    return;
 5842                };
 5843
 5844                let matches = matches_task.await;
 5845
 5846                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5847                    // Newer menu already set, so exit.
 5848                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5849                        editor.context_menu.borrow().as_ref()
 5850                        && prev_menu.id > id
 5851                    {
 5852                        return;
 5853                    };
 5854
 5855                    // Only valid to take prev_menu because either the new menu is immediately set
 5856                    // below, or the menu is hidden.
 5857                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5858                        editor.context_menu.borrow_mut().take()
 5859                    {
 5860                        let position_matches =
 5861                            if prev_menu.initial_position == menu.initial_position {
 5862                                true
 5863                            } else {
 5864                                let snapshot = editor.buffer.read(cx).read(cx);
 5865                                prev_menu.initial_position.to_offset(&snapshot)
 5866                                    == menu.initial_position.to_offset(&snapshot)
 5867                            };
 5868                        if position_matches {
 5869                            // Preserve markdown cache before `set_filter_results` because it will
 5870                            // try to populate the documentation cache.
 5871                            menu.preserve_markdown_cache(prev_menu);
 5872                        }
 5873                    };
 5874
 5875                    menu.set_filter_results(matches, provider, window, cx);
 5876                }) else {
 5877                    return;
 5878                };
 5879
 5880                menu.visible().then_some(menu)
 5881            };
 5882
 5883            editor
 5884                .update_in(cx, |editor, window, cx| {
 5885                    if editor.focus_handle.is_focused(window)
 5886                        && let Some(menu) = menu
 5887                    {
 5888                        *editor.context_menu.borrow_mut() =
 5889                            Some(CodeContextMenu::Completions(menu));
 5890
 5891                        crate::hover_popover::hide_hover(editor, cx);
 5892                        if editor.show_edit_predictions_in_menu() {
 5893                            editor.update_visible_edit_prediction(window, cx);
 5894                        } else {
 5895                            editor.discard_edit_prediction(false, cx);
 5896                        }
 5897
 5898                        cx.notify();
 5899                        return;
 5900                    }
 5901
 5902                    if editor.completion_tasks.len() <= 1 {
 5903                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5904                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5905                        // If it was already hidden and we don't show edit predictions in the menu,
 5906                        // we should also show the edit prediction when available.
 5907                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5908                            editor.update_visible_edit_prediction(window, cx);
 5909                        }
 5910                    }
 5911                })
 5912                .ok();
 5913        });
 5914
 5915        self.completion_tasks.push((id, task));
 5916    }
 5917
 5918    #[cfg(feature = "test-support")]
 5919    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5920        let menu = self.context_menu.borrow();
 5921        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5922            let completions = menu.completions.borrow();
 5923            Some(completions.to_vec())
 5924        } else {
 5925            None
 5926        }
 5927    }
 5928
 5929    pub fn with_completions_menu_matching_id<R>(
 5930        &self,
 5931        id: CompletionId,
 5932        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5933    ) -> R {
 5934        let mut context_menu = self.context_menu.borrow_mut();
 5935        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5936            return f(None);
 5937        };
 5938        if completions_menu.id != id {
 5939            return f(None);
 5940        }
 5941        f(Some(completions_menu))
 5942    }
 5943
 5944    pub fn confirm_completion(
 5945        &mut self,
 5946        action: &ConfirmCompletion,
 5947        window: &mut Window,
 5948        cx: &mut Context<Self>,
 5949    ) -> Option<Task<Result<()>>> {
 5950        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5951        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5952    }
 5953
 5954    pub fn confirm_completion_insert(
 5955        &mut self,
 5956        _: &ConfirmCompletionInsert,
 5957        window: &mut Window,
 5958        cx: &mut Context<Self>,
 5959    ) -> Option<Task<Result<()>>> {
 5960        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5961        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5962    }
 5963
 5964    pub fn confirm_completion_replace(
 5965        &mut self,
 5966        _: &ConfirmCompletionReplace,
 5967        window: &mut Window,
 5968        cx: &mut Context<Self>,
 5969    ) -> Option<Task<Result<()>>> {
 5970        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5971        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5972    }
 5973
 5974    pub fn compose_completion(
 5975        &mut self,
 5976        action: &ComposeCompletion,
 5977        window: &mut Window,
 5978        cx: &mut Context<Self>,
 5979    ) -> Option<Task<Result<()>>> {
 5980        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5981        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5982    }
 5983
 5984    fn do_completion(
 5985        &mut self,
 5986        item_ix: Option<usize>,
 5987        intent: CompletionIntent,
 5988        window: &mut Window,
 5989        cx: &mut Context<Editor>,
 5990    ) -> Option<Task<Result<()>>> {
 5991        use language::ToOffset as _;
 5992
 5993        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5994        else {
 5995            return None;
 5996        };
 5997
 5998        let candidate_id = {
 5999            let entries = completions_menu.entries.borrow();
 6000            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6001            if self.show_edit_predictions_in_menu() {
 6002                self.discard_edit_prediction(true, cx);
 6003            }
 6004            mat.candidate_id
 6005        };
 6006
 6007        let completion = completions_menu
 6008            .completions
 6009            .borrow()
 6010            .get(candidate_id)?
 6011            .clone();
 6012        cx.stop_propagation();
 6013
 6014        let buffer_handle = completions_menu.buffer.clone();
 6015
 6016        let CompletionEdit {
 6017            new_text,
 6018            snippet,
 6019            replace_range,
 6020        } = process_completion_for_edit(
 6021            &completion,
 6022            intent,
 6023            &buffer_handle,
 6024            &completions_menu.initial_position.text_anchor,
 6025            cx,
 6026        );
 6027
 6028        let buffer = buffer_handle.read(cx);
 6029        let snapshot = self.buffer.read(cx).snapshot(cx);
 6030        let newest_anchor = self.selections.newest_anchor();
 6031        let replace_range_multibuffer = {
 6032            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6033            excerpt.map_range_from_buffer(replace_range.clone())
 6034        };
 6035        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6036            return None;
 6037        }
 6038
 6039        let old_text = buffer
 6040            .text_for_range(replace_range.clone())
 6041            .collect::<String>();
 6042        let lookbehind = newest_anchor
 6043            .start
 6044            .text_anchor
 6045            .to_offset(buffer)
 6046            .saturating_sub(replace_range.start.0);
 6047        let lookahead = replace_range
 6048            .end
 6049            .0
 6050            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6051        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6052        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6053
 6054        let selections = self
 6055            .selections
 6056            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6057        let mut ranges = Vec::new();
 6058        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6059
 6060        for selection in &selections {
 6061            let range = if selection.id == newest_anchor.id {
 6062                replace_range_multibuffer.clone()
 6063            } else {
 6064                let mut range = selection.range();
 6065
 6066                // if prefix is present, don't duplicate it
 6067                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6068                    range.start = range.start.saturating_sub_usize(lookbehind);
 6069
 6070                    // if suffix is also present, mimic the newest cursor and replace it
 6071                    if selection.id != newest_anchor.id
 6072                        && snapshot.contains_str_at(range.end, suffix)
 6073                    {
 6074                        range.end += lookahead;
 6075                    }
 6076                }
 6077                range
 6078            };
 6079
 6080            ranges.push(range.clone());
 6081
 6082            if !self.linked_edit_ranges.is_empty() {
 6083                let start_anchor = snapshot.anchor_before(range.start);
 6084                let end_anchor = snapshot.anchor_after(range.end);
 6085                if let Some(ranges) = self
 6086                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6087                {
 6088                    for (buffer, edits) in ranges {
 6089                        linked_edits
 6090                            .entry(buffer.clone())
 6091                            .or_default()
 6092                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6093                    }
 6094                }
 6095            }
 6096        }
 6097
 6098        let common_prefix_len = old_text
 6099            .chars()
 6100            .zip(new_text.chars())
 6101            .take_while(|(a, b)| a == b)
 6102            .map(|(a, _)| a.len_utf8())
 6103            .sum::<usize>();
 6104
 6105        cx.emit(EditorEvent::InputHandled {
 6106            utf16_range_to_replace: None,
 6107            text: new_text[common_prefix_len..].into(),
 6108        });
 6109
 6110        self.transact(window, cx, |editor, window, cx| {
 6111            if let Some(mut snippet) = snippet {
 6112                snippet.text = new_text.to_string();
 6113                editor
 6114                    .insert_snippet(&ranges, snippet, window, cx)
 6115                    .log_err();
 6116            } else {
 6117                editor.buffer.update(cx, |multi_buffer, cx| {
 6118                    let auto_indent = match completion.insert_text_mode {
 6119                        Some(InsertTextMode::AS_IS) => None,
 6120                        _ => editor.autoindent_mode.clone(),
 6121                    };
 6122                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6123                    multi_buffer.edit(edits, auto_indent, cx);
 6124                });
 6125            }
 6126            for (buffer, edits) in linked_edits {
 6127                buffer.update(cx, |buffer, cx| {
 6128                    let snapshot = buffer.snapshot();
 6129                    let edits = edits
 6130                        .into_iter()
 6131                        .map(|(range, text)| {
 6132                            use text::ToPoint as TP;
 6133                            let end_point = TP::to_point(&range.end, &snapshot);
 6134                            let start_point = TP::to_point(&range.start, &snapshot);
 6135                            (start_point..end_point, text)
 6136                        })
 6137                        .sorted_by_key(|(range, _)| range.start);
 6138                    buffer.edit(edits, None, cx);
 6139                })
 6140            }
 6141
 6142            editor.refresh_edit_prediction(true, false, window, cx);
 6143        });
 6144        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6145
 6146        let show_new_completions_on_confirm = completion
 6147            .confirm
 6148            .as_ref()
 6149            .is_some_and(|confirm| confirm(intent, window, cx));
 6150        if show_new_completions_on_confirm {
 6151            self.open_or_update_completions_menu(None, None, false, window, cx);
 6152        }
 6153
 6154        let provider = self.completion_provider.as_ref()?;
 6155
 6156        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6157        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6158            let CompletionSource::Lsp {
 6159                lsp_completion,
 6160                server_id,
 6161                ..
 6162            } = &completion.source
 6163            else {
 6164                return None;
 6165            };
 6166            let lsp_command = lsp_completion.command.as_ref()?;
 6167            let available_commands = lsp_store
 6168                .read(cx)
 6169                .lsp_server_capabilities
 6170                .get(server_id)
 6171                .and_then(|server_capabilities| {
 6172                    server_capabilities
 6173                        .execute_command_provider
 6174                        .as_ref()
 6175                        .map(|options| options.commands.as_slice())
 6176                })?;
 6177            if available_commands.contains(&lsp_command.command) {
 6178                Some(CodeAction {
 6179                    server_id: *server_id,
 6180                    range: language::Anchor::MIN..language::Anchor::MIN,
 6181                    lsp_action: LspAction::Command(lsp_command.clone()),
 6182                    resolved: false,
 6183                })
 6184            } else {
 6185                None
 6186            }
 6187        });
 6188
 6189        drop(completion);
 6190        let apply_edits = provider.apply_additional_edits_for_completion(
 6191            buffer_handle.clone(),
 6192            completions_menu.completions.clone(),
 6193            candidate_id,
 6194            true,
 6195            cx,
 6196        );
 6197
 6198        let editor_settings = EditorSettings::get_global(cx);
 6199        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6200            // After the code completion is finished, users often want to know what signatures are needed.
 6201            // so we should automatically call signature_help
 6202            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6203        }
 6204
 6205        Some(cx.spawn_in(window, async move |editor, cx| {
 6206            apply_edits.await?;
 6207
 6208            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6209                let title = command.lsp_action.title().to_owned();
 6210                let project_transaction = lsp_store
 6211                    .update(cx, |lsp_store, cx| {
 6212                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6213                    })?
 6214                    .await
 6215                    .context("applying post-completion command")?;
 6216                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6217                    Self::open_project_transaction(
 6218                        &editor,
 6219                        workspace.downgrade(),
 6220                        project_transaction,
 6221                        title,
 6222                        cx,
 6223                    )
 6224                    .await?;
 6225                }
 6226            }
 6227
 6228            Ok(())
 6229        }))
 6230    }
 6231
 6232    pub fn toggle_code_actions(
 6233        &mut self,
 6234        action: &ToggleCodeActions,
 6235        window: &mut Window,
 6236        cx: &mut Context<Self>,
 6237    ) {
 6238        let quick_launch = action.quick_launch;
 6239        let mut context_menu = self.context_menu.borrow_mut();
 6240        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6241            if code_actions.deployed_from == action.deployed_from {
 6242                // Toggle if we're selecting the same one
 6243                *context_menu = None;
 6244                cx.notify();
 6245                return;
 6246            } else {
 6247                // Otherwise, clear it and start a new one
 6248                *context_menu = None;
 6249                cx.notify();
 6250            }
 6251        }
 6252        drop(context_menu);
 6253        let snapshot = self.snapshot(window, cx);
 6254        let deployed_from = action.deployed_from.clone();
 6255        let action = action.clone();
 6256        self.completion_tasks.clear();
 6257        self.discard_edit_prediction(false, cx);
 6258
 6259        let multibuffer_point = match &action.deployed_from {
 6260            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6261                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6262            }
 6263            _ => self
 6264                .selections
 6265                .newest::<Point>(&snapshot.display_snapshot)
 6266                .head(),
 6267        };
 6268        let Some((buffer, buffer_row)) = snapshot
 6269            .buffer_snapshot()
 6270            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6271            .and_then(|(buffer_snapshot, range)| {
 6272                self.buffer()
 6273                    .read(cx)
 6274                    .buffer(buffer_snapshot.remote_id())
 6275                    .map(|buffer| (buffer, range.start.row))
 6276            })
 6277        else {
 6278            return;
 6279        };
 6280        let buffer_id = buffer.read(cx).remote_id();
 6281        let tasks = self
 6282            .tasks
 6283            .get(&(buffer_id, buffer_row))
 6284            .map(|t| Arc::new(t.to_owned()));
 6285
 6286        if !self.focus_handle.is_focused(window) {
 6287            return;
 6288        }
 6289        let project = self.project.clone();
 6290
 6291        let code_actions_task = match deployed_from {
 6292            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6293            _ => self.code_actions(buffer_row, window, cx),
 6294        };
 6295
 6296        let runnable_task = match deployed_from {
 6297            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6298            _ => {
 6299                let mut task_context_task = Task::ready(None);
 6300                if let Some(tasks) = &tasks
 6301                    && let Some(project) = project
 6302                {
 6303                    task_context_task =
 6304                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6305                }
 6306
 6307                cx.spawn_in(window, {
 6308                    let buffer = buffer.clone();
 6309                    async move |editor, cx| {
 6310                        let task_context = task_context_task.await;
 6311
 6312                        let resolved_tasks =
 6313                            tasks
 6314                                .zip(task_context.clone())
 6315                                .map(|(tasks, task_context)| ResolvedTasks {
 6316                                    templates: tasks.resolve(&task_context).collect(),
 6317                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6318                                        multibuffer_point.row,
 6319                                        tasks.column,
 6320                                    )),
 6321                                });
 6322                        let debug_scenarios = editor
 6323                            .update(cx, |editor, cx| {
 6324                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6325                            })?
 6326                            .await;
 6327                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6328                    }
 6329                })
 6330            }
 6331        };
 6332
 6333        cx.spawn_in(window, async move |editor, cx| {
 6334            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6335            let code_actions = code_actions_task.await;
 6336            let spawn_straight_away = quick_launch
 6337                && resolved_tasks
 6338                    .as_ref()
 6339                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6340                && code_actions
 6341                    .as_ref()
 6342                    .is_none_or(|actions| actions.is_empty())
 6343                && debug_scenarios.is_empty();
 6344
 6345            editor.update_in(cx, |editor, window, cx| {
 6346                crate::hover_popover::hide_hover(editor, cx);
 6347                let actions = CodeActionContents::new(
 6348                    resolved_tasks,
 6349                    code_actions,
 6350                    debug_scenarios,
 6351                    task_context.unwrap_or_default(),
 6352                );
 6353
 6354                // Don't show the menu if there are no actions available
 6355                if actions.is_empty() {
 6356                    cx.notify();
 6357                    return Task::ready(Ok(()));
 6358                }
 6359
 6360                *editor.context_menu.borrow_mut() =
 6361                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6362                        buffer,
 6363                        actions,
 6364                        selected_item: Default::default(),
 6365                        scroll_handle: UniformListScrollHandle::default(),
 6366                        deployed_from,
 6367                    }));
 6368                cx.notify();
 6369                if spawn_straight_away
 6370                    && let Some(task) = editor.confirm_code_action(
 6371                        &ConfirmCodeAction { item_ix: Some(0) },
 6372                        window,
 6373                        cx,
 6374                    )
 6375                {
 6376                    return task;
 6377                }
 6378
 6379                Task::ready(Ok(()))
 6380            })
 6381        })
 6382        .detach_and_log_err(cx);
 6383    }
 6384
 6385    fn debug_scenarios(
 6386        &mut self,
 6387        resolved_tasks: &Option<ResolvedTasks>,
 6388        buffer: &Entity<Buffer>,
 6389        cx: &mut App,
 6390    ) -> Task<Vec<task::DebugScenario>> {
 6391        maybe!({
 6392            let project = self.project()?;
 6393            let dap_store = project.read(cx).dap_store();
 6394            let mut scenarios = vec![];
 6395            let resolved_tasks = resolved_tasks.as_ref()?;
 6396            let buffer = buffer.read(cx);
 6397            let language = buffer.language()?;
 6398            let file = buffer.file();
 6399            let debug_adapter = language_settings(language.name().into(), file, cx)
 6400                .debuggers
 6401                .first()
 6402                .map(SharedString::from)
 6403                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6404
 6405            dap_store.update(cx, |dap_store, cx| {
 6406                for (_, task) in &resolved_tasks.templates {
 6407                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6408                        task.original_task().clone(),
 6409                        debug_adapter.clone().into(),
 6410                        task.display_label().to_owned().into(),
 6411                        cx,
 6412                    );
 6413                    scenarios.push(maybe_scenario);
 6414                }
 6415            });
 6416            Some(cx.background_spawn(async move {
 6417                futures::future::join_all(scenarios)
 6418                    .await
 6419                    .into_iter()
 6420                    .flatten()
 6421                    .collect::<Vec<_>>()
 6422            }))
 6423        })
 6424        .unwrap_or_else(|| Task::ready(vec![]))
 6425    }
 6426
 6427    fn code_actions(
 6428        &mut self,
 6429        buffer_row: u32,
 6430        window: &mut Window,
 6431        cx: &mut Context<Self>,
 6432    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6433        let mut task = self.code_actions_task.take();
 6434        cx.spawn_in(window, async move |editor, cx| {
 6435            while let Some(prev_task) = task {
 6436                prev_task.await.log_err();
 6437                task = editor
 6438                    .update(cx, |this, _| this.code_actions_task.take())
 6439                    .ok()?;
 6440            }
 6441
 6442            editor
 6443                .update(cx, |editor, cx| {
 6444                    editor
 6445                        .available_code_actions
 6446                        .clone()
 6447                        .and_then(|(location, code_actions)| {
 6448                            let snapshot = location.buffer.read(cx).snapshot();
 6449                            let point_range = location.range.to_point(&snapshot);
 6450                            let point_range = point_range.start.row..=point_range.end.row;
 6451                            if point_range.contains(&buffer_row) {
 6452                                Some(code_actions)
 6453                            } else {
 6454                                None
 6455                            }
 6456                        })
 6457                })
 6458                .ok()
 6459                .flatten()
 6460        })
 6461    }
 6462
 6463    pub fn confirm_code_action(
 6464        &mut self,
 6465        action: &ConfirmCodeAction,
 6466        window: &mut Window,
 6467        cx: &mut Context<Self>,
 6468    ) -> Option<Task<Result<()>>> {
 6469        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6470
 6471        let actions_menu =
 6472            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6473                menu
 6474            } else {
 6475                return None;
 6476            };
 6477
 6478        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6479        let action = actions_menu.actions.get(action_ix)?;
 6480        let title = action.label();
 6481        let buffer = actions_menu.buffer;
 6482        let workspace = self.workspace()?;
 6483
 6484        match action {
 6485            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6486                workspace.update(cx, |workspace, cx| {
 6487                    workspace.schedule_resolved_task(
 6488                        task_source_kind,
 6489                        resolved_task,
 6490                        false,
 6491                        window,
 6492                        cx,
 6493                    );
 6494
 6495                    Some(Task::ready(Ok(())))
 6496                })
 6497            }
 6498            CodeActionsItem::CodeAction {
 6499                excerpt_id,
 6500                action,
 6501                provider,
 6502            } => {
 6503                let apply_code_action =
 6504                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6505                let workspace = workspace.downgrade();
 6506                Some(cx.spawn_in(window, async move |editor, cx| {
 6507                    let project_transaction = apply_code_action.await?;
 6508                    Self::open_project_transaction(
 6509                        &editor,
 6510                        workspace,
 6511                        project_transaction,
 6512                        title,
 6513                        cx,
 6514                    )
 6515                    .await
 6516                }))
 6517            }
 6518            CodeActionsItem::DebugScenario(scenario) => {
 6519                let context = actions_menu.actions.context;
 6520
 6521                workspace.update(cx, |workspace, cx| {
 6522                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6523                    workspace.start_debug_session(
 6524                        scenario,
 6525                        context,
 6526                        Some(buffer),
 6527                        None,
 6528                        window,
 6529                        cx,
 6530                    );
 6531                });
 6532                Some(Task::ready(Ok(())))
 6533            }
 6534        }
 6535    }
 6536
 6537    pub async fn open_project_transaction(
 6538        editor: &WeakEntity<Editor>,
 6539        workspace: WeakEntity<Workspace>,
 6540        transaction: ProjectTransaction,
 6541        title: String,
 6542        cx: &mut AsyncWindowContext,
 6543    ) -> Result<()> {
 6544        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6545        cx.update(|_, cx| {
 6546            entries.sort_unstable_by_key(|(buffer, _)| {
 6547                buffer.read(cx).file().map(|f| f.path().clone())
 6548            });
 6549        })?;
 6550        if entries.is_empty() {
 6551            return Ok(());
 6552        }
 6553
 6554        // If the project transaction's edits are all contained within this editor, then
 6555        // avoid opening a new editor to display them.
 6556
 6557        if let [(buffer, transaction)] = &*entries {
 6558            let excerpt = editor.update(cx, |editor, cx| {
 6559                editor
 6560                    .buffer()
 6561                    .read(cx)
 6562                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6563            })?;
 6564            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6565                && excerpted_buffer == *buffer
 6566            {
 6567                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6568                    let excerpt_range = excerpt_range.to_offset(buffer);
 6569                    buffer
 6570                        .edited_ranges_for_transaction::<usize>(transaction)
 6571                        .all(|range| {
 6572                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6573                        })
 6574                })?;
 6575
 6576                if all_edits_within_excerpt {
 6577                    return Ok(());
 6578                }
 6579            }
 6580        }
 6581
 6582        let mut ranges_to_highlight = Vec::new();
 6583        let excerpt_buffer = cx.new(|cx| {
 6584            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6585            for (buffer_handle, transaction) in &entries {
 6586                let edited_ranges = buffer_handle
 6587                    .read(cx)
 6588                    .edited_ranges_for_transaction::<Point>(transaction)
 6589                    .collect::<Vec<_>>();
 6590                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6591                    PathKey::for_buffer(buffer_handle, cx),
 6592                    buffer_handle.clone(),
 6593                    edited_ranges,
 6594                    multibuffer_context_lines(cx),
 6595                    cx,
 6596                );
 6597
 6598                ranges_to_highlight.extend(ranges);
 6599            }
 6600            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6601            multibuffer
 6602        })?;
 6603
 6604        workspace.update_in(cx, |workspace, window, cx| {
 6605            let project = workspace.project().clone();
 6606            let editor =
 6607                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6608            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6609            editor.update(cx, |editor, cx| {
 6610                editor.highlight_background::<Self>(
 6611                    &ranges_to_highlight,
 6612                    |theme| theme.colors().editor_highlighted_line_background,
 6613                    cx,
 6614                );
 6615            });
 6616        })?;
 6617
 6618        Ok(())
 6619    }
 6620
 6621    pub fn clear_code_action_providers(&mut self) {
 6622        self.code_action_providers.clear();
 6623        self.available_code_actions.take();
 6624    }
 6625
 6626    pub fn add_code_action_provider(
 6627        &mut self,
 6628        provider: Rc<dyn CodeActionProvider>,
 6629        window: &mut Window,
 6630        cx: &mut Context<Self>,
 6631    ) {
 6632        if self
 6633            .code_action_providers
 6634            .iter()
 6635            .any(|existing_provider| existing_provider.id() == provider.id())
 6636        {
 6637            return;
 6638        }
 6639
 6640        self.code_action_providers.push(provider);
 6641        self.refresh_code_actions(window, cx);
 6642    }
 6643
 6644    pub fn remove_code_action_provider(
 6645        &mut self,
 6646        id: Arc<str>,
 6647        window: &mut Window,
 6648        cx: &mut Context<Self>,
 6649    ) {
 6650        self.code_action_providers
 6651            .retain(|provider| provider.id() != id);
 6652        self.refresh_code_actions(window, cx);
 6653    }
 6654
 6655    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6656        !self.code_action_providers.is_empty()
 6657            && EditorSettings::get_global(cx).toolbar.code_actions
 6658    }
 6659
 6660    pub fn has_available_code_actions(&self) -> bool {
 6661        self.available_code_actions
 6662            .as_ref()
 6663            .is_some_and(|(_, actions)| !actions.is_empty())
 6664    }
 6665
 6666    fn render_inline_code_actions(
 6667        &self,
 6668        icon_size: ui::IconSize,
 6669        display_row: DisplayRow,
 6670        is_active: bool,
 6671        cx: &mut Context<Self>,
 6672    ) -> AnyElement {
 6673        let show_tooltip = !self.context_menu_visible();
 6674        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6675            .icon_size(icon_size)
 6676            .shape(ui::IconButtonShape::Square)
 6677            .icon_color(ui::Color::Hidden)
 6678            .toggle_state(is_active)
 6679            .when(show_tooltip, |this| {
 6680                this.tooltip({
 6681                    let focus_handle = self.focus_handle.clone();
 6682                    move |_window, cx| {
 6683                        Tooltip::for_action_in(
 6684                            "Toggle Code Actions",
 6685                            &ToggleCodeActions {
 6686                                deployed_from: None,
 6687                                quick_launch: false,
 6688                            },
 6689                            &focus_handle,
 6690                            cx,
 6691                        )
 6692                    }
 6693                })
 6694            })
 6695            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6696                window.focus(&editor.focus_handle(cx));
 6697                editor.toggle_code_actions(
 6698                    &crate::actions::ToggleCodeActions {
 6699                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6700                            display_row,
 6701                        )),
 6702                        quick_launch: false,
 6703                    },
 6704                    window,
 6705                    cx,
 6706                );
 6707            }))
 6708            .into_any_element()
 6709    }
 6710
 6711    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6712        &self.context_menu
 6713    }
 6714
 6715    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6716        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6717            cx.background_executor()
 6718                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6719                .await;
 6720
 6721            let (start_buffer, start, _, end, newest_selection) = this
 6722                .update(cx, |this, cx| {
 6723                    let newest_selection = this.selections.newest_anchor().clone();
 6724                    if newest_selection.head().diff_base_anchor.is_some() {
 6725                        return None;
 6726                    }
 6727                    let display_snapshot = this.display_snapshot(cx);
 6728                    let newest_selection_adjusted =
 6729                        this.selections.newest_adjusted(&display_snapshot);
 6730                    let buffer = this.buffer.read(cx);
 6731
 6732                    let (start_buffer, start) =
 6733                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6734                    let (end_buffer, end) =
 6735                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6736
 6737                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6738                })?
 6739                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6740                .context(
 6741                    "Expected selection to lie in a single buffer when refreshing code actions",
 6742                )?;
 6743            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6744                let providers = this.code_action_providers.clone();
 6745                let tasks = this
 6746                    .code_action_providers
 6747                    .iter()
 6748                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6749                    .collect::<Vec<_>>();
 6750                (providers, tasks)
 6751            })?;
 6752
 6753            let mut actions = Vec::new();
 6754            for (provider, provider_actions) in
 6755                providers.into_iter().zip(future::join_all(tasks).await)
 6756            {
 6757                if let Some(provider_actions) = provider_actions.log_err() {
 6758                    actions.extend(provider_actions.into_iter().map(|action| {
 6759                        AvailableCodeAction {
 6760                            excerpt_id: newest_selection.start.excerpt_id,
 6761                            action,
 6762                            provider: provider.clone(),
 6763                        }
 6764                    }));
 6765                }
 6766            }
 6767
 6768            this.update(cx, |this, cx| {
 6769                this.available_code_actions = if actions.is_empty() {
 6770                    None
 6771                } else {
 6772                    Some((
 6773                        Location {
 6774                            buffer: start_buffer,
 6775                            range: start..end,
 6776                        },
 6777                        actions.into(),
 6778                    ))
 6779                };
 6780                cx.notify();
 6781            })
 6782        }));
 6783    }
 6784
 6785    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6786        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6787            self.show_git_blame_inline = false;
 6788
 6789            self.show_git_blame_inline_delay_task =
 6790                Some(cx.spawn_in(window, async move |this, cx| {
 6791                    cx.background_executor().timer(delay).await;
 6792
 6793                    this.update(cx, |this, cx| {
 6794                        this.show_git_blame_inline = true;
 6795                        cx.notify();
 6796                    })
 6797                    .log_err();
 6798                }));
 6799        }
 6800    }
 6801
 6802    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6803        let snapshot = self.snapshot(window, cx);
 6804        let cursor = self
 6805            .selections
 6806            .newest::<Point>(&snapshot.display_snapshot)
 6807            .head();
 6808        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6809        else {
 6810            return;
 6811        };
 6812
 6813        let Some(blame) = self.blame.as_ref() else {
 6814            return;
 6815        };
 6816
 6817        let row_info = RowInfo {
 6818            buffer_id: Some(buffer.remote_id()),
 6819            buffer_row: Some(point.row),
 6820            ..Default::default()
 6821        };
 6822        let Some((buffer, blame_entry)) = blame
 6823            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6824            .flatten()
 6825        else {
 6826            return;
 6827        };
 6828
 6829        let anchor = self.selections.newest_anchor().head();
 6830        let position = self.to_pixel_point(anchor, &snapshot, window);
 6831        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6832            self.show_blame_popover(
 6833                buffer,
 6834                &blame_entry,
 6835                position + last_bounds.origin,
 6836                true,
 6837                cx,
 6838            );
 6839        };
 6840    }
 6841
 6842    fn show_blame_popover(
 6843        &mut self,
 6844        buffer: BufferId,
 6845        blame_entry: &BlameEntry,
 6846        position: gpui::Point<Pixels>,
 6847        ignore_timeout: bool,
 6848        cx: &mut Context<Self>,
 6849    ) {
 6850        if let Some(state) = &mut self.inline_blame_popover {
 6851            state.hide_task.take();
 6852        } else {
 6853            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6854            let blame_entry = blame_entry.clone();
 6855            let show_task = cx.spawn(async move |editor, cx| {
 6856                if !ignore_timeout {
 6857                    cx.background_executor()
 6858                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6859                        .await;
 6860                }
 6861                editor
 6862                    .update(cx, |editor, cx| {
 6863                        editor.inline_blame_popover_show_task.take();
 6864                        let Some(blame) = editor.blame.as_ref() else {
 6865                            return;
 6866                        };
 6867                        let blame = blame.read(cx);
 6868                        let details = blame.details_for_entry(buffer, &blame_entry);
 6869                        let markdown = cx.new(|cx| {
 6870                            Markdown::new(
 6871                                details
 6872                                    .as_ref()
 6873                                    .map(|message| message.message.clone())
 6874                                    .unwrap_or_default(),
 6875                                None,
 6876                                None,
 6877                                cx,
 6878                            )
 6879                        });
 6880                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6881                            position,
 6882                            hide_task: None,
 6883                            popover_bounds: None,
 6884                            popover_state: InlineBlamePopoverState {
 6885                                scroll_handle: ScrollHandle::new(),
 6886                                commit_message: details,
 6887                                markdown,
 6888                            },
 6889                            keyboard_grace: ignore_timeout,
 6890                        });
 6891                        cx.notify();
 6892                    })
 6893                    .ok();
 6894            });
 6895            self.inline_blame_popover_show_task = Some(show_task);
 6896        }
 6897    }
 6898
 6899    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6900        self.inline_blame_popover_show_task.take();
 6901        if let Some(state) = &mut self.inline_blame_popover {
 6902            let hide_task = cx.spawn(async move |editor, cx| {
 6903                if !ignore_timeout {
 6904                    cx.background_executor()
 6905                        .timer(std::time::Duration::from_millis(100))
 6906                        .await;
 6907                }
 6908                editor
 6909                    .update(cx, |editor, cx| {
 6910                        editor.inline_blame_popover.take();
 6911                        cx.notify();
 6912                    })
 6913                    .ok();
 6914            });
 6915            state.hide_task = Some(hide_task);
 6916            true
 6917        } else {
 6918            false
 6919        }
 6920    }
 6921
 6922    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6923        if self.pending_rename.is_some() {
 6924            return None;
 6925        }
 6926
 6927        let provider = self.semantics_provider.clone()?;
 6928        let buffer = self.buffer.read(cx);
 6929        let newest_selection = self.selections.newest_anchor().clone();
 6930        let cursor_position = newest_selection.head();
 6931        let (cursor_buffer, cursor_buffer_position) =
 6932            buffer.text_anchor_for_position(cursor_position, cx)?;
 6933        let (tail_buffer, tail_buffer_position) =
 6934            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6935        if cursor_buffer != tail_buffer {
 6936            return None;
 6937        }
 6938
 6939        let snapshot = cursor_buffer.read(cx).snapshot();
 6940        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6941        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6942        if start_word_range != end_word_range {
 6943            self.document_highlights_task.take();
 6944            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6945            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6946            return None;
 6947        }
 6948
 6949        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6950        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6951            cx.background_executor()
 6952                .timer(Duration::from_millis(debounce))
 6953                .await;
 6954
 6955            let highlights = if let Some(highlights) = cx
 6956                .update(|cx| {
 6957                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6958                })
 6959                .ok()
 6960                .flatten()
 6961            {
 6962                highlights.await.log_err()
 6963            } else {
 6964                None
 6965            };
 6966
 6967            if let Some(highlights) = highlights {
 6968                this.update(cx, |this, cx| {
 6969                    if this.pending_rename.is_some() {
 6970                        return;
 6971                    }
 6972
 6973                    let buffer = this.buffer.read(cx);
 6974                    if buffer
 6975                        .text_anchor_for_position(cursor_position, cx)
 6976                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6977                    {
 6978                        return;
 6979                    }
 6980
 6981                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6982                    let mut write_ranges = Vec::new();
 6983                    let mut read_ranges = Vec::new();
 6984                    for highlight in highlights {
 6985                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6986                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6987                        {
 6988                            let start = highlight
 6989                                .range
 6990                                .start
 6991                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6992                            let end = highlight
 6993                                .range
 6994                                .end
 6995                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6996                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6997                                continue;
 6998                            }
 6999
 7000                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7001                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7002                                write_ranges.push(range);
 7003                            } else {
 7004                                read_ranges.push(range);
 7005                            }
 7006                        }
 7007                    }
 7008
 7009                    this.highlight_background::<DocumentHighlightRead>(
 7010                        &read_ranges,
 7011                        |theme| theme.colors().editor_document_highlight_read_background,
 7012                        cx,
 7013                    );
 7014                    this.highlight_background::<DocumentHighlightWrite>(
 7015                        &write_ranges,
 7016                        |theme| theme.colors().editor_document_highlight_write_background,
 7017                        cx,
 7018                    );
 7019                    cx.notify();
 7020                })
 7021                .log_err();
 7022            }
 7023        }));
 7024        None
 7025    }
 7026
 7027    fn prepare_highlight_query_from_selection(
 7028        &mut self,
 7029        window: &Window,
 7030        cx: &mut Context<Editor>,
 7031    ) -> Option<(String, Range<Anchor>)> {
 7032        if matches!(self.mode, EditorMode::SingleLine) {
 7033            return None;
 7034        }
 7035        if !EditorSettings::get_global(cx).selection_highlight {
 7036            return None;
 7037        }
 7038        if self.selections.count() != 1 || self.selections.line_mode() {
 7039            return None;
 7040        }
 7041        let snapshot = self.snapshot(window, cx);
 7042        let selection = self.selections.newest::<Point>(&snapshot);
 7043        // If the selection spans multiple rows OR it is empty
 7044        if selection.start.row != selection.end.row
 7045            || selection.start.column == selection.end.column
 7046        {
 7047            return None;
 7048        }
 7049        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7050        let query = snapshot
 7051            .buffer_snapshot()
 7052            .text_for_range(selection_anchor_range.clone())
 7053            .collect::<String>();
 7054        if query.trim().is_empty() {
 7055            return None;
 7056        }
 7057        Some((query, selection_anchor_range))
 7058    }
 7059
 7060    fn update_selection_occurrence_highlights(
 7061        &mut self,
 7062        query_text: String,
 7063        query_range: Range<Anchor>,
 7064        multi_buffer_range_to_query: Range<Point>,
 7065        use_debounce: bool,
 7066        window: &mut Window,
 7067        cx: &mut Context<Editor>,
 7068    ) -> Task<()> {
 7069        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7070        cx.spawn_in(window, async move |editor, cx| {
 7071            if use_debounce {
 7072                cx.background_executor()
 7073                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7074                    .await;
 7075            }
 7076            let match_task = cx.background_spawn(async move {
 7077                let buffer_ranges = multi_buffer_snapshot
 7078                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7079                    .into_iter()
 7080                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7081                let mut match_ranges = Vec::new();
 7082                let Ok(regex) = project::search::SearchQuery::text(
 7083                    query_text.clone(),
 7084                    false,
 7085                    false,
 7086                    false,
 7087                    Default::default(),
 7088                    Default::default(),
 7089                    false,
 7090                    None,
 7091                ) else {
 7092                    return Vec::default();
 7093                };
 7094                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7095                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7096                    match_ranges.extend(
 7097                        regex
 7098                            .search(
 7099                                buffer_snapshot,
 7100                                Some(search_range.start.0..search_range.end.0),
 7101                            )
 7102                            .await
 7103                            .into_iter()
 7104                            .filter_map(|match_range| {
 7105                                let match_start = buffer_snapshot
 7106                                    .anchor_after(search_range.start + match_range.start);
 7107                                let match_end = buffer_snapshot
 7108                                    .anchor_before(search_range.start + match_range.end);
 7109                                let match_anchor_range =
 7110                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7111                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7112                            }),
 7113                    );
 7114                }
 7115                match_ranges
 7116            });
 7117            let match_ranges = match_task.await;
 7118            editor
 7119                .update_in(cx, |editor, _, cx| {
 7120                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7121                    if !match_ranges.is_empty() {
 7122                        editor.highlight_background::<SelectedTextHighlight>(
 7123                            &match_ranges,
 7124                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7125                            cx,
 7126                        )
 7127                    }
 7128                })
 7129                .log_err();
 7130        })
 7131    }
 7132
 7133    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7134        struct NewlineFold;
 7135        let type_id = std::any::TypeId::of::<NewlineFold>();
 7136        if !self.mode.is_single_line() {
 7137            return;
 7138        }
 7139        let snapshot = self.snapshot(window, cx);
 7140        if snapshot.buffer_snapshot().max_point().row == 0 {
 7141            return;
 7142        }
 7143        let task = cx.background_spawn(async move {
 7144            let new_newlines = snapshot
 7145                .buffer_chars_at(MultiBufferOffset(0))
 7146                .filter_map(|(c, i)| {
 7147                    if c == '\n' {
 7148                        Some(
 7149                            snapshot.buffer_snapshot().anchor_after(i)
 7150                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7151                        )
 7152                    } else {
 7153                        None
 7154                    }
 7155                })
 7156                .collect::<Vec<_>>();
 7157            let existing_newlines = snapshot
 7158                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7159                .filter_map(|fold| {
 7160                    if fold.placeholder.type_tag == Some(type_id) {
 7161                        Some(fold.range.start..fold.range.end)
 7162                    } else {
 7163                        None
 7164                    }
 7165                })
 7166                .collect::<Vec<_>>();
 7167
 7168            (new_newlines, existing_newlines)
 7169        });
 7170        self.folding_newlines = cx.spawn(async move |this, cx| {
 7171            let (new_newlines, existing_newlines) = task.await;
 7172            if new_newlines == existing_newlines {
 7173                return;
 7174            }
 7175            let placeholder = FoldPlaceholder {
 7176                render: Arc::new(move |_, _, cx| {
 7177                    div()
 7178                        .bg(cx.theme().status().hint_background)
 7179                        .border_b_1()
 7180                        .size_full()
 7181                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7182                        .border_color(cx.theme().status().hint)
 7183                        .child("\\n")
 7184                        .into_any()
 7185                }),
 7186                constrain_width: false,
 7187                merge_adjacent: false,
 7188                type_tag: Some(type_id),
 7189            };
 7190            let creases = new_newlines
 7191                .into_iter()
 7192                .map(|range| Crease::simple(range, placeholder.clone()))
 7193                .collect();
 7194            this.update(cx, |this, cx| {
 7195                this.display_map.update(cx, |display_map, cx| {
 7196                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7197                    display_map.fold(creases, cx);
 7198                });
 7199            })
 7200            .ok();
 7201        });
 7202    }
 7203
 7204    fn refresh_selected_text_highlights(
 7205        &mut self,
 7206        on_buffer_edit: bool,
 7207        window: &mut Window,
 7208        cx: &mut Context<Editor>,
 7209    ) {
 7210        let Some((query_text, query_range)) =
 7211            self.prepare_highlight_query_from_selection(window, cx)
 7212        else {
 7213            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7214            self.quick_selection_highlight_task.take();
 7215            self.debounced_selection_highlight_task.take();
 7216            return;
 7217        };
 7218        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7219        if on_buffer_edit
 7220            || self
 7221                .quick_selection_highlight_task
 7222                .as_ref()
 7223                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7224        {
 7225            let multi_buffer_visible_start = self
 7226                .scroll_manager
 7227                .anchor()
 7228                .anchor
 7229                .to_point(&multi_buffer_snapshot);
 7230            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7231                multi_buffer_visible_start
 7232                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7233                Bias::Left,
 7234            );
 7235            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7236            self.quick_selection_highlight_task = Some((
 7237                query_range.clone(),
 7238                self.update_selection_occurrence_highlights(
 7239                    query_text.clone(),
 7240                    query_range.clone(),
 7241                    multi_buffer_visible_range,
 7242                    false,
 7243                    window,
 7244                    cx,
 7245                ),
 7246            ));
 7247        }
 7248        if on_buffer_edit
 7249            || self
 7250                .debounced_selection_highlight_task
 7251                .as_ref()
 7252                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7253        {
 7254            let multi_buffer_start = multi_buffer_snapshot
 7255                .anchor_before(MultiBufferOffset(0))
 7256                .to_point(&multi_buffer_snapshot);
 7257            let multi_buffer_end = multi_buffer_snapshot
 7258                .anchor_after(multi_buffer_snapshot.len())
 7259                .to_point(&multi_buffer_snapshot);
 7260            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7261            self.debounced_selection_highlight_task = Some((
 7262                query_range.clone(),
 7263                self.update_selection_occurrence_highlights(
 7264                    query_text,
 7265                    query_range,
 7266                    multi_buffer_full_range,
 7267                    true,
 7268                    window,
 7269                    cx,
 7270                ),
 7271            ));
 7272        }
 7273    }
 7274
 7275    pub fn refresh_edit_prediction(
 7276        &mut self,
 7277        debounce: bool,
 7278        user_requested: bool,
 7279        window: &mut Window,
 7280        cx: &mut Context<Self>,
 7281    ) -> Option<()> {
 7282        if DisableAiSettings::get_global(cx).disable_ai {
 7283            return None;
 7284        }
 7285
 7286        let provider = self.edit_prediction_provider()?;
 7287        let cursor = self.selections.newest_anchor().head();
 7288        let (buffer, cursor_buffer_position) =
 7289            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7290
 7291        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7292            self.discard_edit_prediction(false, cx);
 7293            return None;
 7294        }
 7295
 7296        self.update_visible_edit_prediction(window, cx);
 7297
 7298        if !user_requested
 7299            && (!self.should_show_edit_predictions()
 7300                || !self.is_focused(window)
 7301                || buffer.read(cx).is_empty())
 7302        {
 7303            self.discard_edit_prediction(false, cx);
 7304            return None;
 7305        }
 7306
 7307        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7308        Some(())
 7309    }
 7310
 7311    fn show_edit_predictions_in_menu(&self) -> bool {
 7312        match self.edit_prediction_settings {
 7313            EditPredictionSettings::Disabled => false,
 7314            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7315        }
 7316    }
 7317
 7318    pub fn edit_predictions_enabled(&self) -> bool {
 7319        match self.edit_prediction_settings {
 7320            EditPredictionSettings::Disabled => false,
 7321            EditPredictionSettings::Enabled { .. } => true,
 7322        }
 7323    }
 7324
 7325    fn edit_prediction_requires_modifier(&self) -> bool {
 7326        match self.edit_prediction_settings {
 7327            EditPredictionSettings::Disabled => false,
 7328            EditPredictionSettings::Enabled {
 7329                preview_requires_modifier,
 7330                ..
 7331            } => preview_requires_modifier,
 7332        }
 7333    }
 7334
 7335    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7336        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7337            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7338            self.discard_edit_prediction(false, cx);
 7339        } else {
 7340            let selection = self.selections.newest_anchor();
 7341            let cursor = selection.head();
 7342
 7343            if let Some((buffer, cursor_buffer_position)) =
 7344                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7345            {
 7346                self.edit_prediction_settings =
 7347                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7348            }
 7349        }
 7350    }
 7351
 7352    fn edit_prediction_settings_at_position(
 7353        &self,
 7354        buffer: &Entity<Buffer>,
 7355        buffer_position: language::Anchor,
 7356        cx: &App,
 7357    ) -> EditPredictionSettings {
 7358        if !self.mode.is_full()
 7359            || !self.show_edit_predictions_override.unwrap_or(true)
 7360            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7361        {
 7362            return EditPredictionSettings::Disabled;
 7363        }
 7364
 7365        let buffer = buffer.read(cx);
 7366
 7367        let file = buffer.file();
 7368
 7369        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7370            return EditPredictionSettings::Disabled;
 7371        };
 7372
 7373        let by_provider = matches!(
 7374            self.menu_edit_predictions_policy,
 7375            MenuEditPredictionsPolicy::ByProvider
 7376        );
 7377
 7378        let show_in_menu = by_provider
 7379            && self
 7380                .edit_prediction_provider
 7381                .as_ref()
 7382                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7383
 7384        let preview_requires_modifier =
 7385            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7386
 7387        EditPredictionSettings::Enabled {
 7388            show_in_menu,
 7389            preview_requires_modifier,
 7390        }
 7391    }
 7392
 7393    fn should_show_edit_predictions(&self) -> bool {
 7394        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7395    }
 7396
 7397    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7398        matches!(
 7399            self.edit_prediction_preview,
 7400            EditPredictionPreview::Active { .. }
 7401        )
 7402    }
 7403
 7404    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7405        let cursor = self.selections.newest_anchor().head();
 7406        if let Some((buffer, cursor_position)) =
 7407            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7408        {
 7409            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7410        } else {
 7411            false
 7412        }
 7413    }
 7414
 7415    pub fn supports_minimap(&self, cx: &App) -> bool {
 7416        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7417    }
 7418
 7419    fn edit_predictions_enabled_in_buffer(
 7420        &self,
 7421        buffer: &Entity<Buffer>,
 7422        buffer_position: language::Anchor,
 7423        cx: &App,
 7424    ) -> bool {
 7425        maybe!({
 7426            if self.read_only(cx) {
 7427                return Some(false);
 7428            }
 7429            let provider = self.edit_prediction_provider()?;
 7430            if !provider.is_enabled(buffer, buffer_position, cx) {
 7431                return Some(false);
 7432            }
 7433            let buffer = buffer.read(cx);
 7434            let Some(file) = buffer.file() else {
 7435                return Some(true);
 7436            };
 7437            let settings = all_language_settings(Some(file), cx);
 7438            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7439        })
 7440        .unwrap_or(false)
 7441    }
 7442
 7443    fn cycle_edit_prediction(
 7444        &mut self,
 7445        direction: Direction,
 7446        window: &mut Window,
 7447        cx: &mut Context<Self>,
 7448    ) -> Option<()> {
 7449        let provider = self.edit_prediction_provider()?;
 7450        let cursor = self.selections.newest_anchor().head();
 7451        let (buffer, cursor_buffer_position) =
 7452            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7453        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7454            return None;
 7455        }
 7456
 7457        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7458        self.update_visible_edit_prediction(window, cx);
 7459
 7460        Some(())
 7461    }
 7462
 7463    pub fn show_edit_prediction(
 7464        &mut self,
 7465        _: &ShowEditPrediction,
 7466        window: &mut Window,
 7467        cx: &mut Context<Self>,
 7468    ) {
 7469        if !self.has_active_edit_prediction() {
 7470            self.refresh_edit_prediction(false, true, window, cx);
 7471            return;
 7472        }
 7473
 7474        self.update_visible_edit_prediction(window, cx);
 7475    }
 7476
 7477    pub fn display_cursor_names(
 7478        &mut self,
 7479        _: &DisplayCursorNames,
 7480        window: &mut Window,
 7481        cx: &mut Context<Self>,
 7482    ) {
 7483        self.show_cursor_names(window, cx);
 7484    }
 7485
 7486    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7487        self.show_cursor_names = true;
 7488        cx.notify();
 7489        cx.spawn_in(window, async move |this, cx| {
 7490            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7491            this.update(cx, |this, cx| {
 7492                this.show_cursor_names = false;
 7493                cx.notify()
 7494            })
 7495            .ok()
 7496        })
 7497        .detach();
 7498    }
 7499
 7500    pub fn next_edit_prediction(
 7501        &mut self,
 7502        _: &NextEditPrediction,
 7503        window: &mut Window,
 7504        cx: &mut Context<Self>,
 7505    ) {
 7506        if self.has_active_edit_prediction() {
 7507            self.cycle_edit_prediction(Direction::Next, window, cx);
 7508        } else {
 7509            let is_copilot_disabled = self
 7510                .refresh_edit_prediction(false, true, window, cx)
 7511                .is_none();
 7512            if is_copilot_disabled {
 7513                cx.propagate();
 7514            }
 7515        }
 7516    }
 7517
 7518    pub fn previous_edit_prediction(
 7519        &mut self,
 7520        _: &PreviousEditPrediction,
 7521        window: &mut Window,
 7522        cx: &mut Context<Self>,
 7523    ) {
 7524        if self.has_active_edit_prediction() {
 7525            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7526        } else {
 7527            let is_copilot_disabled = self
 7528                .refresh_edit_prediction(false, true, window, cx)
 7529                .is_none();
 7530            if is_copilot_disabled {
 7531                cx.propagate();
 7532            }
 7533        }
 7534    }
 7535
 7536    pub fn accept_edit_prediction(
 7537        &mut self,
 7538        _: &AcceptEditPrediction,
 7539        window: &mut Window,
 7540        cx: &mut Context<Self>,
 7541    ) {
 7542        if self.show_edit_predictions_in_menu() {
 7543            self.hide_context_menu(window, cx);
 7544        }
 7545
 7546        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7547            return;
 7548        };
 7549
 7550        match &active_edit_prediction.completion {
 7551            EditPrediction::MoveWithin { target, .. } => {
 7552                let target = *target;
 7553
 7554                if let Some(position_map) = &self.last_position_map {
 7555                    if position_map
 7556                        .visible_row_range
 7557                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7558                        || !self.edit_prediction_requires_modifier()
 7559                    {
 7560                        self.unfold_ranges(&[target..target], true, false, cx);
 7561                        // Note that this is also done in vim's handler of the Tab action.
 7562                        self.change_selections(
 7563                            SelectionEffects::scroll(Autoscroll::newest()),
 7564                            window,
 7565                            cx,
 7566                            |selections| {
 7567                                selections.select_anchor_ranges([target..target]);
 7568                            },
 7569                        );
 7570                        self.clear_row_highlights::<EditPredictionPreview>();
 7571
 7572                        self.edit_prediction_preview
 7573                            .set_previous_scroll_position(None);
 7574                    } else {
 7575                        self.edit_prediction_preview
 7576                            .set_previous_scroll_position(Some(
 7577                                position_map.snapshot.scroll_anchor,
 7578                            ));
 7579
 7580                        self.highlight_rows::<EditPredictionPreview>(
 7581                            target..target,
 7582                            cx.theme().colors().editor_highlighted_line_background,
 7583                            RowHighlightOptions {
 7584                                autoscroll: true,
 7585                                ..Default::default()
 7586                            },
 7587                            cx,
 7588                        );
 7589                        self.request_autoscroll(Autoscroll::fit(), cx);
 7590                    }
 7591                }
 7592            }
 7593            EditPrediction::MoveOutside { snapshot, target } => {
 7594                if let Some(workspace) = self.workspace() {
 7595                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7596                        .detach_and_log_err(cx);
 7597                }
 7598            }
 7599            EditPrediction::Edit { edits, .. } => {
 7600                self.report_edit_prediction_event(
 7601                    active_edit_prediction.completion_id.clone(),
 7602                    true,
 7603                    cx,
 7604                );
 7605
 7606                if let Some(provider) = self.edit_prediction_provider() {
 7607                    provider.accept(cx);
 7608                }
 7609
 7610                // Store the transaction ID and selections before applying the edit
 7611                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7612
 7613                let snapshot = self.buffer.read(cx).snapshot(cx);
 7614                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7615
 7616                self.buffer.update(cx, |buffer, cx| {
 7617                    buffer.edit(edits.iter().cloned(), None, cx)
 7618                });
 7619
 7620                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7621                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7622                });
 7623
 7624                let selections = self.selections.disjoint_anchors_arc();
 7625                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7626                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7627                    if has_new_transaction {
 7628                        self.selection_history
 7629                            .insert_transaction(transaction_id_now, selections);
 7630                    }
 7631                }
 7632
 7633                self.update_visible_edit_prediction(window, cx);
 7634                if self.active_edit_prediction.is_none() {
 7635                    self.refresh_edit_prediction(true, true, window, cx);
 7636                }
 7637
 7638                cx.notify();
 7639            }
 7640        }
 7641
 7642        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7643    }
 7644
 7645    pub fn accept_partial_edit_prediction(
 7646        &mut self,
 7647        _: &AcceptPartialEditPrediction,
 7648        window: &mut Window,
 7649        cx: &mut Context<Self>,
 7650    ) {
 7651        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7652            return;
 7653        };
 7654        if self.selections.count() != 1 {
 7655            return;
 7656        }
 7657
 7658        match &active_edit_prediction.completion {
 7659            EditPrediction::MoveWithin { target, .. } => {
 7660                let target = *target;
 7661                self.change_selections(
 7662                    SelectionEffects::scroll(Autoscroll::newest()),
 7663                    window,
 7664                    cx,
 7665                    |selections| {
 7666                        selections.select_anchor_ranges([target..target]);
 7667                    },
 7668                );
 7669            }
 7670            EditPrediction::MoveOutside { snapshot, target } => {
 7671                if let Some(workspace) = self.workspace() {
 7672                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7673                        .detach_and_log_err(cx);
 7674                }
 7675            }
 7676            EditPrediction::Edit { edits, .. } => {
 7677                self.report_edit_prediction_event(
 7678                    active_edit_prediction.completion_id.clone(),
 7679                    true,
 7680                    cx,
 7681                );
 7682
 7683                // Find an insertion that starts at the cursor position.
 7684                let snapshot = self.buffer.read(cx).snapshot(cx);
 7685                let cursor_offset = self
 7686                    .selections
 7687                    .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7688                    .head();
 7689                let insertion = edits.iter().find_map(|(range, text)| {
 7690                    let range = range.to_offset(&snapshot);
 7691                    if range.is_empty() && range.start == cursor_offset {
 7692                        Some(text)
 7693                    } else {
 7694                        None
 7695                    }
 7696                });
 7697
 7698                if let Some(text) = insertion {
 7699                    let mut partial_completion = text
 7700                        .chars()
 7701                        .by_ref()
 7702                        .take_while(|c| c.is_alphabetic())
 7703                        .collect::<String>();
 7704                    if partial_completion.is_empty() {
 7705                        partial_completion = text
 7706                            .chars()
 7707                            .by_ref()
 7708                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7709                            .collect::<String>();
 7710                    }
 7711
 7712                    cx.emit(EditorEvent::InputHandled {
 7713                        utf16_range_to_replace: None,
 7714                        text: partial_completion.clone().into(),
 7715                    });
 7716
 7717                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7718
 7719                    self.refresh_edit_prediction(true, true, window, cx);
 7720                    cx.notify();
 7721                } else {
 7722                    self.accept_edit_prediction(&Default::default(), window, cx);
 7723                }
 7724            }
 7725        }
 7726    }
 7727
 7728    fn discard_edit_prediction(
 7729        &mut self,
 7730        should_report_edit_prediction_event: bool,
 7731        cx: &mut Context<Self>,
 7732    ) -> bool {
 7733        if should_report_edit_prediction_event {
 7734            let completion_id = self
 7735                .active_edit_prediction
 7736                .as_ref()
 7737                .and_then(|active_completion| active_completion.completion_id.clone());
 7738
 7739            self.report_edit_prediction_event(completion_id, false, cx);
 7740        }
 7741
 7742        if let Some(provider) = self.edit_prediction_provider() {
 7743            provider.discard(cx);
 7744        }
 7745
 7746        self.take_active_edit_prediction(cx)
 7747    }
 7748
 7749    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7750        let Some(provider) = self.edit_prediction_provider() else {
 7751            return;
 7752        };
 7753
 7754        let Some((_, buffer, _)) = self
 7755            .buffer
 7756            .read(cx)
 7757            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7758        else {
 7759            return;
 7760        };
 7761
 7762        let extension = buffer
 7763            .read(cx)
 7764            .file()
 7765            .and_then(|file| Some(file.path().extension()?.to_string()));
 7766
 7767        let event_type = match accepted {
 7768            true => "Edit Prediction Accepted",
 7769            false => "Edit Prediction Discarded",
 7770        };
 7771        telemetry::event!(
 7772            event_type,
 7773            provider = provider.name(),
 7774            prediction_id = id,
 7775            suggestion_accepted = accepted,
 7776            file_extension = extension,
 7777        );
 7778    }
 7779
 7780    fn open_editor_at_anchor(
 7781        snapshot: &language::BufferSnapshot,
 7782        target: language::Anchor,
 7783        workspace: &Entity<Workspace>,
 7784        window: &mut Window,
 7785        cx: &mut App,
 7786    ) -> Task<Result<()>> {
 7787        workspace.update(cx, |workspace, cx| {
 7788            let path = snapshot.file().map(|file| file.full_path(cx));
 7789            let Some(path) =
 7790                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7791            else {
 7792                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7793            };
 7794            let target = text::ToPoint::to_point(&target, snapshot);
 7795            let item = workspace.open_path(path, None, true, window, cx);
 7796            window.spawn(cx, async move |cx| {
 7797                let Some(editor) = item.await?.downcast::<Editor>() else {
 7798                    return Ok(());
 7799                };
 7800                editor
 7801                    .update_in(cx, |editor, window, cx| {
 7802                        editor.go_to_singleton_buffer_point(target, window, cx);
 7803                    })
 7804                    .ok();
 7805                anyhow::Ok(())
 7806            })
 7807        })
 7808    }
 7809
 7810    pub fn has_active_edit_prediction(&self) -> bool {
 7811        self.active_edit_prediction.is_some()
 7812    }
 7813
 7814    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7815        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7816            return false;
 7817        };
 7818
 7819        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7820        self.clear_highlights::<EditPredictionHighlight>(cx);
 7821        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7822        true
 7823    }
 7824
 7825    /// Returns true when we're displaying the edit prediction popover below the cursor
 7826    /// like we are not previewing and the LSP autocomplete menu is visible
 7827    /// or we are in `when_holding_modifier` mode.
 7828    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7829        if self.edit_prediction_preview_is_active()
 7830            || !self.show_edit_predictions_in_menu()
 7831            || !self.edit_predictions_enabled()
 7832        {
 7833            return false;
 7834        }
 7835
 7836        if self.has_visible_completions_menu() {
 7837            return true;
 7838        }
 7839
 7840        has_completion && self.edit_prediction_requires_modifier()
 7841    }
 7842
 7843    fn handle_modifiers_changed(
 7844        &mut self,
 7845        modifiers: Modifiers,
 7846        position_map: &PositionMap,
 7847        window: &mut Window,
 7848        cx: &mut Context<Self>,
 7849    ) {
 7850        // Ensure that the edit prediction preview is updated, even when not
 7851        // enabled, if there's an active edit prediction preview.
 7852        if self.show_edit_predictions_in_menu()
 7853            || matches!(
 7854                self.edit_prediction_preview,
 7855                EditPredictionPreview::Active { .. }
 7856            )
 7857        {
 7858            self.update_edit_prediction_preview(&modifiers, window, cx);
 7859        }
 7860
 7861        self.update_selection_mode(&modifiers, position_map, window, cx);
 7862
 7863        let mouse_position = window.mouse_position();
 7864        if !position_map.text_hitbox.is_hovered(window) {
 7865            return;
 7866        }
 7867
 7868        self.update_hovered_link(
 7869            position_map.point_for_position(mouse_position),
 7870            &position_map.snapshot,
 7871            modifiers,
 7872            window,
 7873            cx,
 7874        )
 7875    }
 7876
 7877    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7878        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7879            MultiCursorModifier::Alt => modifiers.secondary(),
 7880            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7881        }
 7882    }
 7883
 7884    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7885        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7886            MultiCursorModifier::Alt => modifiers.alt,
 7887            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7888        }
 7889    }
 7890
 7891    fn columnar_selection_mode(
 7892        modifiers: &Modifiers,
 7893        cx: &mut Context<Self>,
 7894    ) -> Option<ColumnarMode> {
 7895        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7896            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7897                Some(ColumnarMode::FromMouse)
 7898            } else if Self::is_alt_pressed(modifiers, cx) {
 7899                Some(ColumnarMode::FromSelection)
 7900            } else {
 7901                None
 7902            }
 7903        } else {
 7904            None
 7905        }
 7906    }
 7907
 7908    fn update_selection_mode(
 7909        &mut self,
 7910        modifiers: &Modifiers,
 7911        position_map: &PositionMap,
 7912        window: &mut Window,
 7913        cx: &mut Context<Self>,
 7914    ) {
 7915        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7916            return;
 7917        };
 7918        if self.selections.pending_anchor().is_none() {
 7919            return;
 7920        }
 7921
 7922        let mouse_position = window.mouse_position();
 7923        let point_for_position = position_map.point_for_position(mouse_position);
 7924        let position = point_for_position.previous_valid;
 7925
 7926        self.select(
 7927            SelectPhase::BeginColumnar {
 7928                position,
 7929                reset: false,
 7930                mode,
 7931                goal_column: point_for_position.exact_unclipped.column(),
 7932            },
 7933            window,
 7934            cx,
 7935        );
 7936    }
 7937
 7938    fn update_edit_prediction_preview(
 7939        &mut self,
 7940        modifiers: &Modifiers,
 7941        window: &mut Window,
 7942        cx: &mut Context<Self>,
 7943    ) {
 7944        let mut modifiers_held = false;
 7945        if let Some(accept_keystroke) = self
 7946            .accept_edit_prediction_keybind(false, window, cx)
 7947            .keystroke()
 7948        {
 7949            modifiers_held = modifiers_held
 7950                || (accept_keystroke.modifiers() == modifiers
 7951                    && accept_keystroke.modifiers().modified());
 7952        };
 7953        if let Some(accept_partial_keystroke) = self
 7954            .accept_edit_prediction_keybind(true, window, cx)
 7955            .keystroke()
 7956        {
 7957            modifiers_held = modifiers_held
 7958                || (accept_partial_keystroke.modifiers() == modifiers
 7959                    && accept_partial_keystroke.modifiers().modified());
 7960        }
 7961
 7962        if modifiers_held {
 7963            if matches!(
 7964                self.edit_prediction_preview,
 7965                EditPredictionPreview::Inactive { .. }
 7966            ) {
 7967                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 7968                    provider.provider.did_show(cx)
 7969                }
 7970
 7971                self.edit_prediction_preview = EditPredictionPreview::Active {
 7972                    previous_scroll_position: None,
 7973                    since: Instant::now(),
 7974                };
 7975
 7976                self.update_visible_edit_prediction(window, cx);
 7977                cx.notify();
 7978            }
 7979        } else if let EditPredictionPreview::Active {
 7980            previous_scroll_position,
 7981            since,
 7982        } = self.edit_prediction_preview
 7983        {
 7984            if let (Some(previous_scroll_position), Some(position_map)) =
 7985                (previous_scroll_position, self.last_position_map.as_ref())
 7986            {
 7987                self.set_scroll_position(
 7988                    previous_scroll_position
 7989                        .scroll_position(&position_map.snapshot.display_snapshot),
 7990                    window,
 7991                    cx,
 7992                );
 7993            }
 7994
 7995            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7996                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7997            };
 7998            self.clear_row_highlights::<EditPredictionPreview>();
 7999            self.update_visible_edit_prediction(window, cx);
 8000            cx.notify();
 8001        }
 8002    }
 8003
 8004    fn update_visible_edit_prediction(
 8005        &mut self,
 8006        _window: &mut Window,
 8007        cx: &mut Context<Self>,
 8008    ) -> Option<()> {
 8009        if DisableAiSettings::get_global(cx).disable_ai {
 8010            return None;
 8011        }
 8012
 8013        if self.ime_transaction.is_some() {
 8014            self.discard_edit_prediction(false, cx);
 8015            return None;
 8016        }
 8017
 8018        let selection = self.selections.newest_anchor();
 8019        let cursor = selection.head();
 8020        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8021        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8022        let excerpt_id = cursor.excerpt_id;
 8023
 8024        let show_in_menu = self.show_edit_predictions_in_menu();
 8025        let completions_menu_has_precedence = !show_in_menu
 8026            && (self.context_menu.borrow().is_some()
 8027                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8028
 8029        if completions_menu_has_precedence
 8030            || !offset_selection.is_empty()
 8031            || self
 8032                .active_edit_prediction
 8033                .as_ref()
 8034                .is_some_and(|completion| {
 8035                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8036                        return false;
 8037                    };
 8038                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8039                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8040                    !invalidation_range.contains(&offset_selection.head())
 8041                })
 8042        {
 8043            self.discard_edit_prediction(false, cx);
 8044            return None;
 8045        }
 8046
 8047        self.take_active_edit_prediction(cx);
 8048        let Some(provider) = self.edit_prediction_provider() else {
 8049            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8050            return None;
 8051        };
 8052
 8053        let (buffer, cursor_buffer_position) =
 8054            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8055
 8056        self.edit_prediction_settings =
 8057            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8058
 8059        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8060
 8061        if self.edit_prediction_indent_conflict {
 8062            let cursor_point = cursor.to_point(&multibuffer);
 8063
 8064            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 8065
 8066            if let Some((_, indent)) = indents.iter().next()
 8067                && indent.len == cursor_point.column
 8068            {
 8069                self.edit_prediction_indent_conflict = false;
 8070            }
 8071        }
 8072
 8073        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8074
 8075        let (completion_id, edits, edit_preview) = match edit_prediction {
 8076            edit_prediction::EditPrediction::Local {
 8077                id,
 8078                edits,
 8079                edit_preview,
 8080            } => (id, edits, edit_preview),
 8081            edit_prediction::EditPrediction::Jump {
 8082                id,
 8083                snapshot,
 8084                target,
 8085            } => {
 8086                self.stale_edit_prediction_in_menu = None;
 8087                self.active_edit_prediction = Some(EditPredictionState {
 8088                    inlay_ids: vec![],
 8089                    completion: EditPrediction::MoveOutside { snapshot, target },
 8090                    completion_id: id,
 8091                    invalidation_range: None,
 8092                });
 8093                cx.notify();
 8094                return Some(());
 8095            }
 8096        };
 8097
 8098        let edits = edits
 8099            .into_iter()
 8100            .flat_map(|(range, new_text)| {
 8101                Some((
 8102                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8103                    new_text,
 8104                ))
 8105            })
 8106            .collect::<Vec<_>>();
 8107        if edits.is_empty() {
 8108            return None;
 8109        }
 8110
 8111        let first_edit_start = edits.first().unwrap().0.start;
 8112        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8113        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8114
 8115        let last_edit_end = edits.last().unwrap().0.end;
 8116        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8117        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8118
 8119        let cursor_row = cursor.to_point(&multibuffer).row;
 8120
 8121        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8122
 8123        let mut inlay_ids = Vec::new();
 8124        let invalidation_row_range;
 8125        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8126            Some(cursor_row..edit_end_row)
 8127        } else if cursor_row > edit_end_row {
 8128            Some(edit_start_row..cursor_row)
 8129        } else {
 8130            None
 8131        };
 8132        let supports_jump = self
 8133            .edit_prediction_provider
 8134            .as_ref()
 8135            .map(|provider| provider.provider.supports_jump_to_edit())
 8136            .unwrap_or(true);
 8137
 8138        let is_move = supports_jump
 8139            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8140        let completion = if is_move {
 8141            invalidation_row_range =
 8142                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8143            let target = first_edit_start;
 8144            EditPrediction::MoveWithin { target, snapshot }
 8145        } else {
 8146            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8147                && !self.edit_predictions_hidden_for_vim_mode;
 8148
 8149            if show_completions_in_buffer {
 8150                if let Some(provider) = &self.edit_prediction_provider {
 8151                    provider.provider.did_show(cx);
 8152                }
 8153                if edits
 8154                    .iter()
 8155                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8156                {
 8157                    let mut inlays = Vec::new();
 8158                    for (range, new_text) in &edits {
 8159                        let inlay = Inlay::edit_prediction(
 8160                            post_inc(&mut self.next_inlay_id),
 8161                            range.start,
 8162                            new_text.as_ref(),
 8163                        );
 8164                        inlay_ids.push(inlay.id);
 8165                        inlays.push(inlay);
 8166                    }
 8167
 8168                    self.splice_inlays(&[], inlays, cx);
 8169                } else {
 8170                    let background_color = cx.theme().status().deleted_background;
 8171                    self.highlight_text::<EditPredictionHighlight>(
 8172                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8173                        HighlightStyle {
 8174                            background_color: Some(background_color),
 8175                            ..Default::default()
 8176                        },
 8177                        cx,
 8178                    );
 8179                }
 8180            }
 8181
 8182            invalidation_row_range = edit_start_row..edit_end_row;
 8183
 8184            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8185                if provider.show_tab_accept_marker() {
 8186                    EditDisplayMode::TabAccept
 8187                } else {
 8188                    EditDisplayMode::Inline
 8189                }
 8190            } else {
 8191                EditDisplayMode::DiffPopover
 8192            };
 8193
 8194            EditPrediction::Edit {
 8195                edits,
 8196                edit_preview,
 8197                display_mode,
 8198                snapshot,
 8199            }
 8200        };
 8201
 8202        let invalidation_range = multibuffer
 8203            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8204            ..multibuffer.anchor_after(Point::new(
 8205                invalidation_row_range.end,
 8206                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8207            ));
 8208
 8209        self.stale_edit_prediction_in_menu = None;
 8210        self.active_edit_prediction = Some(EditPredictionState {
 8211            inlay_ids,
 8212            completion,
 8213            completion_id,
 8214            invalidation_range: Some(invalidation_range),
 8215        });
 8216
 8217        cx.notify();
 8218
 8219        Some(())
 8220    }
 8221
 8222    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8223        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8224    }
 8225
 8226    fn clear_tasks(&mut self) {
 8227        self.tasks.clear()
 8228    }
 8229
 8230    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8231        if self.tasks.insert(key, value).is_some() {
 8232            // This case should hopefully be rare, but just in case...
 8233            log::error!(
 8234                "multiple different run targets found on a single line, only the last target will be rendered"
 8235            )
 8236        }
 8237    }
 8238
 8239    /// Get all display points of breakpoints that will be rendered within editor
 8240    ///
 8241    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8242    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8243    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8244    fn active_breakpoints(
 8245        &self,
 8246        range: Range<DisplayRow>,
 8247        window: &mut Window,
 8248        cx: &mut Context<Self>,
 8249    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8250        let mut breakpoint_display_points = HashMap::default();
 8251
 8252        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8253            return breakpoint_display_points;
 8254        };
 8255
 8256        let snapshot = self.snapshot(window, cx);
 8257
 8258        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8259        let Some(project) = self.project() else {
 8260            return breakpoint_display_points;
 8261        };
 8262
 8263        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8264            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8265
 8266        for (buffer_snapshot, range, excerpt_id) in
 8267            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8268        {
 8269            let Some(buffer) = project
 8270                .read(cx)
 8271                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8272            else {
 8273                continue;
 8274            };
 8275            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8276                &buffer,
 8277                Some(
 8278                    buffer_snapshot.anchor_before(range.start)
 8279                        ..buffer_snapshot.anchor_after(range.end),
 8280                ),
 8281                buffer_snapshot,
 8282                cx,
 8283            );
 8284            for (breakpoint, state) in breakpoints {
 8285                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8286                let position = multi_buffer_anchor
 8287                    .to_point(&multi_buffer_snapshot)
 8288                    .to_display_point(&snapshot);
 8289
 8290                breakpoint_display_points.insert(
 8291                    position.row(),
 8292                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8293                );
 8294            }
 8295        }
 8296
 8297        breakpoint_display_points
 8298    }
 8299
 8300    fn breakpoint_context_menu(
 8301        &self,
 8302        anchor: Anchor,
 8303        window: &mut Window,
 8304        cx: &mut Context<Self>,
 8305    ) -> Entity<ui::ContextMenu> {
 8306        let weak_editor = cx.weak_entity();
 8307        let focus_handle = self.focus_handle(cx);
 8308
 8309        let row = self
 8310            .buffer
 8311            .read(cx)
 8312            .snapshot(cx)
 8313            .summary_for_anchor::<Point>(&anchor)
 8314            .row;
 8315
 8316        let breakpoint = self
 8317            .breakpoint_at_row(row, window, cx)
 8318            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8319
 8320        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8321            "Edit Log Breakpoint"
 8322        } else {
 8323            "Set Log Breakpoint"
 8324        };
 8325
 8326        let condition_breakpoint_msg = if breakpoint
 8327            .as_ref()
 8328            .is_some_and(|bp| bp.1.condition.is_some())
 8329        {
 8330            "Edit Condition Breakpoint"
 8331        } else {
 8332            "Set Condition Breakpoint"
 8333        };
 8334
 8335        let hit_condition_breakpoint_msg = if breakpoint
 8336            .as_ref()
 8337            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8338        {
 8339            "Edit Hit Condition Breakpoint"
 8340        } else {
 8341            "Set Hit Condition Breakpoint"
 8342        };
 8343
 8344        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8345            "Unset Breakpoint"
 8346        } else {
 8347            "Set Breakpoint"
 8348        };
 8349
 8350        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8351
 8352        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8353            BreakpointState::Enabled => Some("Disable"),
 8354            BreakpointState::Disabled => Some("Enable"),
 8355        });
 8356
 8357        let (anchor, breakpoint) =
 8358            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8359
 8360        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8361            menu.on_blur_subscription(Subscription::new(|| {}))
 8362                .context(focus_handle)
 8363                .when(run_to_cursor, |this| {
 8364                    let weak_editor = weak_editor.clone();
 8365                    this.entry("Run to cursor", None, move |window, cx| {
 8366                        weak_editor
 8367                            .update(cx, |editor, cx| {
 8368                                editor.change_selections(
 8369                                    SelectionEffects::no_scroll(),
 8370                                    window,
 8371                                    cx,
 8372                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8373                                );
 8374                            })
 8375                            .ok();
 8376
 8377                        window.dispatch_action(Box::new(RunToCursor), cx);
 8378                    })
 8379                    .separator()
 8380                })
 8381                .when_some(toggle_state_msg, |this, msg| {
 8382                    this.entry(msg, None, {
 8383                        let weak_editor = weak_editor.clone();
 8384                        let breakpoint = breakpoint.clone();
 8385                        move |_window, cx| {
 8386                            weak_editor
 8387                                .update(cx, |this, cx| {
 8388                                    this.edit_breakpoint_at_anchor(
 8389                                        anchor,
 8390                                        breakpoint.as_ref().clone(),
 8391                                        BreakpointEditAction::InvertState,
 8392                                        cx,
 8393                                    );
 8394                                })
 8395                                .log_err();
 8396                        }
 8397                    })
 8398                })
 8399                .entry(set_breakpoint_msg, None, {
 8400                    let weak_editor = weak_editor.clone();
 8401                    let breakpoint = breakpoint.clone();
 8402                    move |_window, cx| {
 8403                        weak_editor
 8404                            .update(cx, |this, cx| {
 8405                                this.edit_breakpoint_at_anchor(
 8406                                    anchor,
 8407                                    breakpoint.as_ref().clone(),
 8408                                    BreakpointEditAction::Toggle,
 8409                                    cx,
 8410                                );
 8411                            })
 8412                            .log_err();
 8413                    }
 8414                })
 8415                .entry(log_breakpoint_msg, None, {
 8416                    let breakpoint = breakpoint.clone();
 8417                    let weak_editor = weak_editor.clone();
 8418                    move |window, cx| {
 8419                        weak_editor
 8420                            .update(cx, |this, cx| {
 8421                                this.add_edit_breakpoint_block(
 8422                                    anchor,
 8423                                    breakpoint.as_ref(),
 8424                                    BreakpointPromptEditAction::Log,
 8425                                    window,
 8426                                    cx,
 8427                                );
 8428                            })
 8429                            .log_err();
 8430                    }
 8431                })
 8432                .entry(condition_breakpoint_msg, None, {
 8433                    let breakpoint = breakpoint.clone();
 8434                    let weak_editor = weak_editor.clone();
 8435                    move |window, cx| {
 8436                        weak_editor
 8437                            .update(cx, |this, cx| {
 8438                                this.add_edit_breakpoint_block(
 8439                                    anchor,
 8440                                    breakpoint.as_ref(),
 8441                                    BreakpointPromptEditAction::Condition,
 8442                                    window,
 8443                                    cx,
 8444                                );
 8445                            })
 8446                            .log_err();
 8447                    }
 8448                })
 8449                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8450                    weak_editor
 8451                        .update(cx, |this, cx| {
 8452                            this.add_edit_breakpoint_block(
 8453                                anchor,
 8454                                breakpoint.as_ref(),
 8455                                BreakpointPromptEditAction::HitCondition,
 8456                                window,
 8457                                cx,
 8458                            );
 8459                        })
 8460                        .log_err();
 8461                })
 8462        })
 8463    }
 8464
 8465    fn render_breakpoint(
 8466        &self,
 8467        position: Anchor,
 8468        row: DisplayRow,
 8469        breakpoint: &Breakpoint,
 8470        state: Option<BreakpointSessionState>,
 8471        cx: &mut Context<Self>,
 8472    ) -> IconButton {
 8473        let is_rejected = state.is_some_and(|s| !s.verified);
 8474        // Is it a breakpoint that shows up when hovering over gutter?
 8475        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8476            (false, false),
 8477            |PhantomBreakpointIndicator {
 8478                 is_active,
 8479                 display_row,
 8480                 collides_with_existing_breakpoint,
 8481             }| {
 8482                (
 8483                    is_active && display_row == row,
 8484                    collides_with_existing_breakpoint,
 8485                )
 8486            },
 8487        );
 8488
 8489        let (color, icon) = {
 8490            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8491                (false, false) => ui::IconName::DebugBreakpoint,
 8492                (true, false) => ui::IconName::DebugLogBreakpoint,
 8493                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8494                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8495            };
 8496
 8497            let color = cx.theme().colors();
 8498
 8499            let color = if is_phantom {
 8500                if collides_with_existing {
 8501                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8502                } else {
 8503                    Color::Hint
 8504                }
 8505            } else if is_rejected {
 8506                Color::Disabled
 8507            } else {
 8508                Color::Debugger
 8509            };
 8510
 8511            (color, icon)
 8512        };
 8513
 8514        let breakpoint = Arc::from(breakpoint.clone());
 8515
 8516        let alt_as_text = gpui::Keystroke {
 8517            modifiers: Modifiers::secondary_key(),
 8518            ..Default::default()
 8519        };
 8520        let primary_action_text = if breakpoint.is_disabled() {
 8521            "Enable breakpoint"
 8522        } else if is_phantom && !collides_with_existing {
 8523            "Set breakpoint"
 8524        } else {
 8525            "Unset breakpoint"
 8526        };
 8527        let focus_handle = self.focus_handle.clone();
 8528
 8529        let meta = if is_rejected {
 8530            SharedString::from("No executable code is associated with this line.")
 8531        } else if collides_with_existing && !breakpoint.is_disabled() {
 8532            SharedString::from(format!(
 8533                "{alt_as_text}-click to disable,\nright-click for more options."
 8534            ))
 8535        } else {
 8536            SharedString::from("Right-click for more options.")
 8537        };
 8538        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8539            .icon_size(IconSize::XSmall)
 8540            .size(ui::ButtonSize::None)
 8541            .when(is_rejected, |this| {
 8542                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8543            })
 8544            .icon_color(color)
 8545            .style(ButtonStyle::Transparent)
 8546            .on_click(cx.listener({
 8547                move |editor, event: &ClickEvent, window, cx| {
 8548                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8549                        BreakpointEditAction::InvertState
 8550                    } else {
 8551                        BreakpointEditAction::Toggle
 8552                    };
 8553
 8554                    window.focus(&editor.focus_handle(cx));
 8555                    editor.edit_breakpoint_at_anchor(
 8556                        position,
 8557                        breakpoint.as_ref().clone(),
 8558                        edit_action,
 8559                        cx,
 8560                    );
 8561                }
 8562            }))
 8563            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8564                editor.set_breakpoint_context_menu(
 8565                    row,
 8566                    Some(position),
 8567                    event.position(),
 8568                    window,
 8569                    cx,
 8570                );
 8571            }))
 8572            .tooltip(move |_window, cx| {
 8573                Tooltip::with_meta_in(
 8574                    primary_action_text,
 8575                    Some(&ToggleBreakpoint),
 8576                    meta.clone(),
 8577                    &focus_handle,
 8578                    cx,
 8579                )
 8580            })
 8581    }
 8582
 8583    fn build_tasks_context(
 8584        project: &Entity<Project>,
 8585        buffer: &Entity<Buffer>,
 8586        buffer_row: u32,
 8587        tasks: &Arc<RunnableTasks>,
 8588        cx: &mut Context<Self>,
 8589    ) -> Task<Option<task::TaskContext>> {
 8590        let position = Point::new(buffer_row, tasks.column);
 8591        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8592        let location = Location {
 8593            buffer: buffer.clone(),
 8594            range: range_start..range_start,
 8595        };
 8596        // Fill in the environmental variables from the tree-sitter captures
 8597        let mut captured_task_variables = TaskVariables::default();
 8598        for (capture_name, value) in tasks.extra_variables.clone() {
 8599            captured_task_variables.insert(
 8600                task::VariableName::Custom(capture_name.into()),
 8601                value.clone(),
 8602            );
 8603        }
 8604        project.update(cx, |project, cx| {
 8605            project.task_store().update(cx, |task_store, cx| {
 8606                task_store.task_context_for_location(captured_task_variables, location, cx)
 8607            })
 8608        })
 8609    }
 8610
 8611    pub fn spawn_nearest_task(
 8612        &mut self,
 8613        action: &SpawnNearestTask,
 8614        window: &mut Window,
 8615        cx: &mut Context<Self>,
 8616    ) {
 8617        let Some((workspace, _)) = self.workspace.clone() else {
 8618            return;
 8619        };
 8620        let Some(project) = self.project.clone() else {
 8621            return;
 8622        };
 8623
 8624        // Try to find a closest, enclosing node using tree-sitter that has a task
 8625        let Some((buffer, buffer_row, tasks)) = self
 8626            .find_enclosing_node_task(cx)
 8627            // Or find the task that's closest in row-distance.
 8628            .or_else(|| self.find_closest_task(cx))
 8629        else {
 8630            return;
 8631        };
 8632
 8633        let reveal_strategy = action.reveal;
 8634        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8635        cx.spawn_in(window, async move |_, cx| {
 8636            let context = task_context.await?;
 8637            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8638
 8639            let resolved = &mut resolved_task.resolved;
 8640            resolved.reveal = reveal_strategy;
 8641
 8642            workspace
 8643                .update_in(cx, |workspace, window, cx| {
 8644                    workspace.schedule_resolved_task(
 8645                        task_source_kind,
 8646                        resolved_task,
 8647                        false,
 8648                        window,
 8649                        cx,
 8650                    );
 8651                })
 8652                .ok()
 8653        })
 8654        .detach();
 8655    }
 8656
 8657    fn find_closest_task(
 8658        &mut self,
 8659        cx: &mut Context<Self>,
 8660    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8661        let cursor_row = self
 8662            .selections
 8663            .newest_adjusted(&self.display_snapshot(cx))
 8664            .head()
 8665            .row;
 8666
 8667        let ((buffer_id, row), tasks) = self
 8668            .tasks
 8669            .iter()
 8670            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8671
 8672        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8673        let tasks = Arc::new(tasks.to_owned());
 8674        Some((buffer, *row, tasks))
 8675    }
 8676
 8677    fn find_enclosing_node_task(
 8678        &mut self,
 8679        cx: &mut Context<Self>,
 8680    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8681        let snapshot = self.buffer.read(cx).snapshot(cx);
 8682        let offset = self
 8683            .selections
 8684            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8685            .head();
 8686        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8687        let offset = excerpt.map_offset_to_buffer(offset);
 8688        let buffer_id = excerpt.buffer().remote_id();
 8689
 8690        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8691        let mut cursor = layer.node().walk();
 8692
 8693        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8694            if cursor.node().end_byte() == offset.0 {
 8695                cursor.goto_next_sibling();
 8696            }
 8697        }
 8698
 8699        // Ascend to the smallest ancestor that contains the range and has a task.
 8700        loop {
 8701            let node = cursor.node();
 8702            let node_range = node.byte_range();
 8703            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8704
 8705            // Check if this node contains our offset
 8706            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8707                // If it contains offset, check for task
 8708                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8709                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8710                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8711                }
 8712            }
 8713
 8714            if !cursor.goto_parent() {
 8715                break;
 8716            }
 8717        }
 8718        None
 8719    }
 8720
 8721    fn render_run_indicator(
 8722        &self,
 8723        _style: &EditorStyle,
 8724        is_active: bool,
 8725        row: DisplayRow,
 8726        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8727        cx: &mut Context<Self>,
 8728    ) -> IconButton {
 8729        let color = Color::Muted;
 8730        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8731
 8732        IconButton::new(
 8733            ("run_indicator", row.0 as usize),
 8734            ui::IconName::PlayOutlined,
 8735        )
 8736        .shape(ui::IconButtonShape::Square)
 8737        .icon_size(IconSize::XSmall)
 8738        .icon_color(color)
 8739        .toggle_state(is_active)
 8740        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8741            let quick_launch = match e {
 8742                ClickEvent::Keyboard(_) => true,
 8743                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8744            };
 8745
 8746            window.focus(&editor.focus_handle(cx));
 8747            editor.toggle_code_actions(
 8748                &ToggleCodeActions {
 8749                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8750                    quick_launch,
 8751                },
 8752                window,
 8753                cx,
 8754            );
 8755        }))
 8756        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8757            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8758        }))
 8759    }
 8760
 8761    pub fn context_menu_visible(&self) -> bool {
 8762        !self.edit_prediction_preview_is_active()
 8763            && self
 8764                .context_menu
 8765                .borrow()
 8766                .as_ref()
 8767                .is_some_and(|menu| menu.visible())
 8768    }
 8769
 8770    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8771        self.context_menu
 8772            .borrow()
 8773            .as_ref()
 8774            .map(|menu| menu.origin())
 8775    }
 8776
 8777    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8778        self.context_menu_options = Some(options);
 8779    }
 8780
 8781    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8782    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8783
 8784    fn render_edit_prediction_popover(
 8785        &mut self,
 8786        text_bounds: &Bounds<Pixels>,
 8787        content_origin: gpui::Point<Pixels>,
 8788        right_margin: Pixels,
 8789        editor_snapshot: &EditorSnapshot,
 8790        visible_row_range: Range<DisplayRow>,
 8791        scroll_top: ScrollOffset,
 8792        scroll_bottom: ScrollOffset,
 8793        line_layouts: &[LineWithInvisibles],
 8794        line_height: Pixels,
 8795        scroll_position: gpui::Point<ScrollOffset>,
 8796        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8797        newest_selection_head: Option<DisplayPoint>,
 8798        editor_width: Pixels,
 8799        style: &EditorStyle,
 8800        window: &mut Window,
 8801        cx: &mut App,
 8802    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8803        if self.mode().is_minimap() {
 8804            return None;
 8805        }
 8806        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8807
 8808        if self.edit_prediction_visible_in_cursor_popover(true) {
 8809            return None;
 8810        }
 8811
 8812        match &active_edit_prediction.completion {
 8813            EditPrediction::MoveWithin { target, .. } => {
 8814                let target_display_point = target.to_display_point(editor_snapshot);
 8815
 8816                if self.edit_prediction_requires_modifier() {
 8817                    if !self.edit_prediction_preview_is_active() {
 8818                        return None;
 8819                    }
 8820
 8821                    self.render_edit_prediction_modifier_jump_popover(
 8822                        text_bounds,
 8823                        content_origin,
 8824                        visible_row_range,
 8825                        line_layouts,
 8826                        line_height,
 8827                        scroll_pixel_position,
 8828                        newest_selection_head,
 8829                        target_display_point,
 8830                        window,
 8831                        cx,
 8832                    )
 8833                } else {
 8834                    self.render_edit_prediction_eager_jump_popover(
 8835                        text_bounds,
 8836                        content_origin,
 8837                        editor_snapshot,
 8838                        visible_row_range,
 8839                        scroll_top,
 8840                        scroll_bottom,
 8841                        line_height,
 8842                        scroll_pixel_position,
 8843                        target_display_point,
 8844                        editor_width,
 8845                        window,
 8846                        cx,
 8847                    )
 8848                }
 8849            }
 8850            EditPrediction::Edit {
 8851                display_mode: EditDisplayMode::Inline,
 8852                ..
 8853            } => None,
 8854            EditPrediction::Edit {
 8855                display_mode: EditDisplayMode::TabAccept,
 8856                edits,
 8857                ..
 8858            } => {
 8859                let range = &edits.first()?.0;
 8860                let target_display_point = range.end.to_display_point(editor_snapshot);
 8861
 8862                self.render_edit_prediction_end_of_line_popover(
 8863                    "Accept",
 8864                    editor_snapshot,
 8865                    visible_row_range,
 8866                    target_display_point,
 8867                    line_height,
 8868                    scroll_pixel_position,
 8869                    content_origin,
 8870                    editor_width,
 8871                    window,
 8872                    cx,
 8873                )
 8874            }
 8875            EditPrediction::Edit {
 8876                edits,
 8877                edit_preview,
 8878                display_mode: EditDisplayMode::DiffPopover,
 8879                snapshot,
 8880            } => self.render_edit_prediction_diff_popover(
 8881                text_bounds,
 8882                content_origin,
 8883                right_margin,
 8884                editor_snapshot,
 8885                visible_row_range,
 8886                line_layouts,
 8887                line_height,
 8888                scroll_position,
 8889                scroll_pixel_position,
 8890                newest_selection_head,
 8891                editor_width,
 8892                style,
 8893                edits,
 8894                edit_preview,
 8895                snapshot,
 8896                window,
 8897                cx,
 8898            ),
 8899            EditPrediction::MoveOutside { snapshot, .. } => {
 8900                let mut element = self
 8901                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 8902                    .into_any();
 8903
 8904                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8905                let origin_x = text_bounds.size.width - size.width - px(30.);
 8906                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 8907                element.prepaint_at(origin, window, cx);
 8908
 8909                Some((element, origin))
 8910            }
 8911        }
 8912    }
 8913
 8914    fn render_edit_prediction_modifier_jump_popover(
 8915        &mut self,
 8916        text_bounds: &Bounds<Pixels>,
 8917        content_origin: gpui::Point<Pixels>,
 8918        visible_row_range: Range<DisplayRow>,
 8919        line_layouts: &[LineWithInvisibles],
 8920        line_height: Pixels,
 8921        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8922        newest_selection_head: Option<DisplayPoint>,
 8923        target_display_point: DisplayPoint,
 8924        window: &mut Window,
 8925        cx: &mut App,
 8926    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8927        let scrolled_content_origin =
 8928            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8929
 8930        const SCROLL_PADDING_Y: Pixels = px(12.);
 8931
 8932        if target_display_point.row() < visible_row_range.start {
 8933            return self.render_edit_prediction_scroll_popover(
 8934                |_| SCROLL_PADDING_Y,
 8935                IconName::ArrowUp,
 8936                visible_row_range,
 8937                line_layouts,
 8938                newest_selection_head,
 8939                scrolled_content_origin,
 8940                window,
 8941                cx,
 8942            );
 8943        } else if target_display_point.row() >= visible_row_range.end {
 8944            return self.render_edit_prediction_scroll_popover(
 8945                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8946                IconName::ArrowDown,
 8947                visible_row_range,
 8948                line_layouts,
 8949                newest_selection_head,
 8950                scrolled_content_origin,
 8951                window,
 8952                cx,
 8953            );
 8954        }
 8955
 8956        const POLE_WIDTH: Pixels = px(2.);
 8957
 8958        let line_layout =
 8959            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8960        let target_column = target_display_point.column() as usize;
 8961
 8962        let target_x = line_layout.x_for_index(target_column);
 8963        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8964            - scroll_pixel_position.y;
 8965
 8966        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8967
 8968        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8969        border_color.l += 0.001;
 8970
 8971        let mut element = v_flex()
 8972            .items_end()
 8973            .when(flag_on_right, |el| el.items_start())
 8974            .child(if flag_on_right {
 8975                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8976                    .rounded_bl(px(0.))
 8977                    .rounded_tl(px(0.))
 8978                    .border_l_2()
 8979                    .border_color(border_color)
 8980            } else {
 8981                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8982                    .rounded_br(px(0.))
 8983                    .rounded_tr(px(0.))
 8984                    .border_r_2()
 8985                    .border_color(border_color)
 8986            })
 8987            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8988            .into_any();
 8989
 8990        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8991
 8992        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8993            - point(
 8994                if flag_on_right {
 8995                    POLE_WIDTH
 8996                } else {
 8997                    size.width - POLE_WIDTH
 8998                },
 8999                size.height - line_height,
 9000            );
 9001
 9002        origin.x = origin.x.max(content_origin.x);
 9003
 9004        element.prepaint_at(origin, window, cx);
 9005
 9006        Some((element, origin))
 9007    }
 9008
 9009    fn render_edit_prediction_scroll_popover(
 9010        &mut self,
 9011        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9012        scroll_icon: IconName,
 9013        visible_row_range: Range<DisplayRow>,
 9014        line_layouts: &[LineWithInvisibles],
 9015        newest_selection_head: Option<DisplayPoint>,
 9016        scrolled_content_origin: gpui::Point<Pixels>,
 9017        window: &mut Window,
 9018        cx: &mut App,
 9019    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9020        let mut element = self
 9021            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9022            .into_any();
 9023
 9024        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9025
 9026        let cursor = newest_selection_head?;
 9027        let cursor_row_layout =
 9028            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9029        let cursor_column = cursor.column() as usize;
 9030
 9031        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9032
 9033        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9034
 9035        element.prepaint_at(origin, window, cx);
 9036        Some((element, origin))
 9037    }
 9038
 9039    fn render_edit_prediction_eager_jump_popover(
 9040        &mut self,
 9041        text_bounds: &Bounds<Pixels>,
 9042        content_origin: gpui::Point<Pixels>,
 9043        editor_snapshot: &EditorSnapshot,
 9044        visible_row_range: Range<DisplayRow>,
 9045        scroll_top: ScrollOffset,
 9046        scroll_bottom: ScrollOffset,
 9047        line_height: Pixels,
 9048        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9049        target_display_point: DisplayPoint,
 9050        editor_width: Pixels,
 9051        window: &mut Window,
 9052        cx: &mut App,
 9053    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9054        if target_display_point.row().as_f64() < scroll_top {
 9055            let mut element = self
 9056                .render_edit_prediction_line_popover(
 9057                    "Jump to Edit",
 9058                    Some(IconName::ArrowUp),
 9059                    window,
 9060                    cx,
 9061                )
 9062                .into_any();
 9063
 9064            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9065            let offset = point(
 9066                (text_bounds.size.width - size.width) / 2.,
 9067                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9068            );
 9069
 9070            let origin = text_bounds.origin + offset;
 9071            element.prepaint_at(origin, window, cx);
 9072            Some((element, origin))
 9073        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9074            let mut element = self
 9075                .render_edit_prediction_line_popover(
 9076                    "Jump to Edit",
 9077                    Some(IconName::ArrowDown),
 9078                    window,
 9079                    cx,
 9080                )
 9081                .into_any();
 9082
 9083            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9084            let offset = point(
 9085                (text_bounds.size.width - size.width) / 2.,
 9086                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9087            );
 9088
 9089            let origin = text_bounds.origin + offset;
 9090            element.prepaint_at(origin, window, cx);
 9091            Some((element, origin))
 9092        } else {
 9093            self.render_edit_prediction_end_of_line_popover(
 9094                "Jump to Edit",
 9095                editor_snapshot,
 9096                visible_row_range,
 9097                target_display_point,
 9098                line_height,
 9099                scroll_pixel_position,
 9100                content_origin,
 9101                editor_width,
 9102                window,
 9103                cx,
 9104            )
 9105        }
 9106    }
 9107
 9108    fn render_edit_prediction_end_of_line_popover(
 9109        self: &mut Editor,
 9110        label: &'static str,
 9111        editor_snapshot: &EditorSnapshot,
 9112        visible_row_range: Range<DisplayRow>,
 9113        target_display_point: DisplayPoint,
 9114        line_height: Pixels,
 9115        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9116        content_origin: gpui::Point<Pixels>,
 9117        editor_width: Pixels,
 9118        window: &mut Window,
 9119        cx: &mut App,
 9120    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9121        let target_line_end = DisplayPoint::new(
 9122            target_display_point.row(),
 9123            editor_snapshot.line_len(target_display_point.row()),
 9124        );
 9125
 9126        let mut element = self
 9127            .render_edit_prediction_line_popover(label, None, window, cx)
 9128            .into_any();
 9129
 9130        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9131
 9132        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9133
 9134        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9135        let mut origin = start_point
 9136            + line_origin
 9137            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9138        origin.x = origin.x.max(content_origin.x);
 9139
 9140        let max_x = content_origin.x + editor_width - size.width;
 9141
 9142        if origin.x > max_x {
 9143            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9144
 9145            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9146                origin.y += offset;
 9147                IconName::ArrowUp
 9148            } else {
 9149                origin.y -= offset;
 9150                IconName::ArrowDown
 9151            };
 9152
 9153            element = self
 9154                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9155                .into_any();
 9156
 9157            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9158
 9159            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9160        }
 9161
 9162        element.prepaint_at(origin, window, cx);
 9163        Some((element, origin))
 9164    }
 9165
 9166    fn render_edit_prediction_diff_popover(
 9167        self: &Editor,
 9168        text_bounds: &Bounds<Pixels>,
 9169        content_origin: gpui::Point<Pixels>,
 9170        right_margin: Pixels,
 9171        editor_snapshot: &EditorSnapshot,
 9172        visible_row_range: Range<DisplayRow>,
 9173        line_layouts: &[LineWithInvisibles],
 9174        line_height: Pixels,
 9175        scroll_position: gpui::Point<ScrollOffset>,
 9176        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9177        newest_selection_head: Option<DisplayPoint>,
 9178        editor_width: Pixels,
 9179        style: &EditorStyle,
 9180        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9181        edit_preview: &Option<language::EditPreview>,
 9182        snapshot: &language::BufferSnapshot,
 9183        window: &mut Window,
 9184        cx: &mut App,
 9185    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9186        let edit_start = edits
 9187            .first()
 9188            .unwrap()
 9189            .0
 9190            .start
 9191            .to_display_point(editor_snapshot);
 9192        let edit_end = edits
 9193            .last()
 9194            .unwrap()
 9195            .0
 9196            .end
 9197            .to_display_point(editor_snapshot);
 9198
 9199        let is_visible = visible_row_range.contains(&edit_start.row())
 9200            || visible_row_range.contains(&edit_end.row());
 9201        if !is_visible {
 9202            return None;
 9203        }
 9204
 9205        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9206            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9207        } else {
 9208            // Fallback for providers without edit_preview
 9209            crate::edit_prediction_fallback_text(edits, cx)
 9210        };
 9211
 9212        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9213        let line_count = highlighted_edits.text.lines().count();
 9214
 9215        const BORDER_WIDTH: Pixels = px(1.);
 9216
 9217        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9218        let has_keybind = keybind.is_some();
 9219
 9220        let mut element = h_flex()
 9221            .items_start()
 9222            .child(
 9223                h_flex()
 9224                    .bg(cx.theme().colors().editor_background)
 9225                    .border(BORDER_WIDTH)
 9226                    .shadow_xs()
 9227                    .border_color(cx.theme().colors().border)
 9228                    .rounded_l_lg()
 9229                    .when(line_count > 1, |el| el.rounded_br_lg())
 9230                    .pr_1()
 9231                    .child(styled_text),
 9232            )
 9233            .child(
 9234                h_flex()
 9235                    .h(line_height + BORDER_WIDTH * 2.)
 9236                    .px_1p5()
 9237                    .gap_1()
 9238                    // Workaround: For some reason, there's a gap if we don't do this
 9239                    .ml(-BORDER_WIDTH)
 9240                    .shadow(vec![gpui::BoxShadow {
 9241                        color: gpui::black().opacity(0.05),
 9242                        offset: point(px(1.), px(1.)),
 9243                        blur_radius: px(2.),
 9244                        spread_radius: px(0.),
 9245                    }])
 9246                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9247                    .border(BORDER_WIDTH)
 9248                    .border_color(cx.theme().colors().border)
 9249                    .rounded_r_lg()
 9250                    .id("edit_prediction_diff_popover_keybind")
 9251                    .when(!has_keybind, |el| {
 9252                        let status_colors = cx.theme().status();
 9253
 9254                        el.bg(status_colors.error_background)
 9255                            .border_color(status_colors.error.opacity(0.6))
 9256                            .child(Icon::new(IconName::Info).color(Color::Error))
 9257                            .cursor_default()
 9258                            .hoverable_tooltip(move |_window, cx| {
 9259                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9260                            })
 9261                    })
 9262                    .children(keybind),
 9263            )
 9264            .into_any();
 9265
 9266        let longest_row =
 9267            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9268        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9269            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9270        } else {
 9271            layout_line(
 9272                longest_row,
 9273                editor_snapshot,
 9274                style,
 9275                editor_width,
 9276                |_| false,
 9277                window,
 9278                cx,
 9279            )
 9280            .width
 9281        };
 9282
 9283        let viewport_bounds =
 9284            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9285                right: -right_margin,
 9286                ..Default::default()
 9287            });
 9288
 9289        let x_after_longest = Pixels::from(
 9290            ScrollPixelOffset::from(
 9291                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9292            ) - scroll_pixel_position.x,
 9293        );
 9294
 9295        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9296
 9297        // Fully visible if it can be displayed within the window (allow overlapping other
 9298        // panes). However, this is only allowed if the popover starts within text_bounds.
 9299        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9300            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9301
 9302        let mut origin = if can_position_to_the_right {
 9303            point(
 9304                x_after_longest,
 9305                text_bounds.origin.y
 9306                    + Pixels::from(
 9307                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9308                            - scroll_pixel_position.y,
 9309                    ),
 9310            )
 9311        } else {
 9312            let cursor_row = newest_selection_head.map(|head| head.row());
 9313            let above_edit = edit_start
 9314                .row()
 9315                .0
 9316                .checked_sub(line_count as u32)
 9317                .map(DisplayRow);
 9318            let below_edit = Some(edit_end.row() + 1);
 9319            let above_cursor =
 9320                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9321            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9322
 9323            // Place the edit popover adjacent to the edit if there is a location
 9324            // available that is onscreen and does not obscure the cursor. Otherwise,
 9325            // place it adjacent to the cursor.
 9326            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9327                .into_iter()
 9328                .flatten()
 9329                .find(|&start_row| {
 9330                    let end_row = start_row + line_count as u32;
 9331                    visible_row_range.contains(&start_row)
 9332                        && visible_row_range.contains(&end_row)
 9333                        && cursor_row
 9334                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9335                })?;
 9336
 9337            content_origin
 9338                + point(
 9339                    Pixels::from(-scroll_pixel_position.x),
 9340                    Pixels::from(
 9341                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9342                    ),
 9343                )
 9344        };
 9345
 9346        origin.x -= BORDER_WIDTH;
 9347
 9348        window.defer_draw(element, origin, 1);
 9349
 9350        // Do not return an element, since it will already be drawn due to defer_draw.
 9351        None
 9352    }
 9353
 9354    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9355        px(30.)
 9356    }
 9357
 9358    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9359        if self.read_only(cx) {
 9360            cx.theme().players().read_only()
 9361        } else {
 9362            self.style.as_ref().unwrap().local_player
 9363        }
 9364    }
 9365
 9366    fn render_edit_prediction_accept_keybind(
 9367        &self,
 9368        window: &mut Window,
 9369        cx: &mut App,
 9370    ) -> Option<AnyElement> {
 9371        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9372        let accept_keystroke = accept_binding.keystroke()?;
 9373
 9374        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9375
 9376        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9377            Color::Accent
 9378        } else {
 9379            Color::Muted
 9380        };
 9381
 9382        h_flex()
 9383            .px_0p5()
 9384            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9385            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9386            .text_size(TextSize::XSmall.rems(cx))
 9387            .child(h_flex().children(ui::render_modifiers(
 9388                accept_keystroke.modifiers(),
 9389                PlatformStyle::platform(),
 9390                Some(modifiers_color),
 9391                Some(IconSize::XSmall.rems().into()),
 9392                true,
 9393            )))
 9394            .when(is_platform_style_mac, |parent| {
 9395                parent.child(accept_keystroke.key().to_string())
 9396            })
 9397            .when(!is_platform_style_mac, |parent| {
 9398                parent.child(
 9399                    Key::new(
 9400                        util::capitalize(accept_keystroke.key()),
 9401                        Some(Color::Default),
 9402                    )
 9403                    .size(Some(IconSize::XSmall.rems().into())),
 9404                )
 9405            })
 9406            .into_any()
 9407            .into()
 9408    }
 9409
 9410    fn render_edit_prediction_line_popover(
 9411        &self,
 9412        label: impl Into<SharedString>,
 9413        icon: Option<IconName>,
 9414        window: &mut Window,
 9415        cx: &mut App,
 9416    ) -> Stateful<Div> {
 9417        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9418
 9419        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9420        let has_keybind = keybind.is_some();
 9421
 9422        h_flex()
 9423            .id("ep-line-popover")
 9424            .py_0p5()
 9425            .pl_1()
 9426            .pr(padding_right)
 9427            .gap_1()
 9428            .rounded_md()
 9429            .border_1()
 9430            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9431            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9432            .shadow_xs()
 9433            .when(!has_keybind, |el| {
 9434                let status_colors = cx.theme().status();
 9435
 9436                el.bg(status_colors.error_background)
 9437                    .border_color(status_colors.error.opacity(0.6))
 9438                    .pl_2()
 9439                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9440                    .cursor_default()
 9441                    .hoverable_tooltip(move |_window, cx| {
 9442                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9443                    })
 9444            })
 9445            .children(keybind)
 9446            .child(
 9447                Label::new(label)
 9448                    .size(LabelSize::Small)
 9449                    .when(!has_keybind, |el| {
 9450                        el.color(cx.theme().status().error.into()).strikethrough()
 9451                    }),
 9452            )
 9453            .when(!has_keybind, |el| {
 9454                el.child(
 9455                    h_flex().ml_1().child(
 9456                        Icon::new(IconName::Info)
 9457                            .size(IconSize::Small)
 9458                            .color(cx.theme().status().error.into()),
 9459                    ),
 9460                )
 9461            })
 9462            .when_some(icon, |element, icon| {
 9463                element.child(
 9464                    div()
 9465                        .mt(px(1.5))
 9466                        .child(Icon::new(icon).size(IconSize::Small)),
 9467                )
 9468            })
 9469    }
 9470
 9471    fn render_edit_prediction_jump_outside_popover(
 9472        &self,
 9473        snapshot: &BufferSnapshot,
 9474        window: &mut Window,
 9475        cx: &mut App,
 9476    ) -> Stateful<Div> {
 9477        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9478        let has_keybind = keybind.is_some();
 9479
 9480        let file_name = snapshot
 9481            .file()
 9482            .map(|file| SharedString::new(file.file_name(cx)))
 9483            .unwrap_or(SharedString::new_static("untitled"));
 9484
 9485        h_flex()
 9486            .id("ep-jump-outside-popover")
 9487            .py_1()
 9488            .px_2()
 9489            .gap_1()
 9490            .rounded_md()
 9491            .border_1()
 9492            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9493            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9494            .shadow_xs()
 9495            .when(!has_keybind, |el| {
 9496                let status_colors = cx.theme().status();
 9497
 9498                el.bg(status_colors.error_background)
 9499                    .border_color(status_colors.error.opacity(0.6))
 9500                    .pl_2()
 9501                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9502                    .cursor_default()
 9503                    .hoverable_tooltip(move |_window, cx| {
 9504                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9505                    })
 9506            })
 9507            .children(keybind)
 9508            .child(
 9509                Label::new(file_name)
 9510                    .size(LabelSize::Small)
 9511                    .buffer_font(cx)
 9512                    .when(!has_keybind, |el| {
 9513                        el.color(cx.theme().status().error.into()).strikethrough()
 9514                    }),
 9515            )
 9516            .when(!has_keybind, |el| {
 9517                el.child(
 9518                    h_flex().ml_1().child(
 9519                        Icon::new(IconName::Info)
 9520                            .size(IconSize::Small)
 9521                            .color(cx.theme().status().error.into()),
 9522                    ),
 9523                )
 9524            })
 9525            .child(
 9526                div()
 9527                    .mt(px(1.5))
 9528                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9529            )
 9530    }
 9531
 9532    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9533        let accent_color = cx.theme().colors().text_accent;
 9534        let editor_bg_color = cx.theme().colors().editor_background;
 9535        editor_bg_color.blend(accent_color.opacity(0.1))
 9536    }
 9537
 9538    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9539        let accent_color = cx.theme().colors().text_accent;
 9540        let editor_bg_color = cx.theme().colors().editor_background;
 9541        editor_bg_color.blend(accent_color.opacity(0.6))
 9542    }
 9543    fn get_prediction_provider_icon_name(
 9544        provider: &Option<RegisteredEditPredictionProvider>,
 9545    ) -> IconName {
 9546        match provider {
 9547            Some(provider) => match provider.provider.name() {
 9548                "copilot" => IconName::Copilot,
 9549                "supermaven" => IconName::Supermaven,
 9550                _ => IconName::ZedPredict,
 9551            },
 9552            None => IconName::ZedPredict,
 9553        }
 9554    }
 9555
 9556    fn render_edit_prediction_cursor_popover(
 9557        &self,
 9558        min_width: Pixels,
 9559        max_width: Pixels,
 9560        cursor_point: Point,
 9561        style: &EditorStyle,
 9562        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9563        _window: &Window,
 9564        cx: &mut Context<Editor>,
 9565    ) -> Option<AnyElement> {
 9566        let provider = self.edit_prediction_provider.as_ref()?;
 9567        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9568
 9569        let is_refreshing = provider.provider.is_refreshing(cx);
 9570
 9571        fn pending_completion_container(icon: IconName) -> Div {
 9572            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9573        }
 9574
 9575        let completion = match &self.active_edit_prediction {
 9576            Some(prediction) => {
 9577                if !self.has_visible_completions_menu() {
 9578                    const RADIUS: Pixels = px(6.);
 9579                    const BORDER_WIDTH: Pixels = px(1.);
 9580
 9581                    return Some(
 9582                        h_flex()
 9583                            .elevation_2(cx)
 9584                            .border(BORDER_WIDTH)
 9585                            .border_color(cx.theme().colors().border)
 9586                            .when(accept_keystroke.is_none(), |el| {
 9587                                el.border_color(cx.theme().status().error)
 9588                            })
 9589                            .rounded(RADIUS)
 9590                            .rounded_tl(px(0.))
 9591                            .overflow_hidden()
 9592                            .child(div().px_1p5().child(match &prediction.completion {
 9593                                EditPrediction::MoveWithin { target, snapshot } => {
 9594                                    use text::ToPoint as _;
 9595                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9596                                    {
 9597                                        Icon::new(IconName::ZedPredictDown)
 9598                                    } else {
 9599                                        Icon::new(IconName::ZedPredictUp)
 9600                                    }
 9601                                }
 9602                                EditPrediction::MoveOutside { .. } => {
 9603                                    // TODO [zeta2] custom icon for external jump?
 9604                                    Icon::new(provider_icon)
 9605                                }
 9606                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9607                            }))
 9608                            .child(
 9609                                h_flex()
 9610                                    .gap_1()
 9611                                    .py_1()
 9612                                    .px_2()
 9613                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9614                                    .border_l_1()
 9615                                    .border_color(cx.theme().colors().border)
 9616                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9617                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9618                                        el.child(
 9619                                            Label::new("Hold")
 9620                                                .size(LabelSize::Small)
 9621                                                .when(accept_keystroke.is_none(), |el| {
 9622                                                    el.strikethrough()
 9623                                                })
 9624                                                .line_height_style(LineHeightStyle::UiLabel),
 9625                                        )
 9626                                    })
 9627                                    .id("edit_prediction_cursor_popover_keybind")
 9628                                    .when(accept_keystroke.is_none(), |el| {
 9629                                        let status_colors = cx.theme().status();
 9630
 9631                                        el.bg(status_colors.error_background)
 9632                                            .border_color(status_colors.error.opacity(0.6))
 9633                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9634                                            .cursor_default()
 9635                                            .hoverable_tooltip(move |_window, cx| {
 9636                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9637                                                    .into()
 9638                                            })
 9639                                    })
 9640                                    .when_some(
 9641                                        accept_keystroke.as_ref(),
 9642                                        |el, accept_keystroke| {
 9643                                            el.child(h_flex().children(ui::render_modifiers(
 9644                                                accept_keystroke.modifiers(),
 9645                                                PlatformStyle::platform(),
 9646                                                Some(Color::Default),
 9647                                                Some(IconSize::XSmall.rems().into()),
 9648                                                false,
 9649                                            )))
 9650                                        },
 9651                                    ),
 9652                            )
 9653                            .into_any(),
 9654                    );
 9655                }
 9656
 9657                self.render_edit_prediction_cursor_popover_preview(
 9658                    prediction,
 9659                    cursor_point,
 9660                    style,
 9661                    cx,
 9662                )?
 9663            }
 9664
 9665            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9666                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9667                    stale_completion,
 9668                    cursor_point,
 9669                    style,
 9670                    cx,
 9671                )?,
 9672
 9673                None => pending_completion_container(provider_icon)
 9674                    .child(Label::new("...").size(LabelSize::Small)),
 9675            },
 9676
 9677            None => pending_completion_container(provider_icon)
 9678                .child(Label::new("...").size(LabelSize::Small)),
 9679        };
 9680
 9681        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9682            completion
 9683                .with_animation(
 9684                    "loading-completion",
 9685                    Animation::new(Duration::from_secs(2))
 9686                        .repeat()
 9687                        .with_easing(pulsating_between(0.4, 0.8)),
 9688                    |label, delta| label.opacity(delta),
 9689                )
 9690                .into_any_element()
 9691        } else {
 9692            completion.into_any_element()
 9693        };
 9694
 9695        let has_completion = self.active_edit_prediction.is_some();
 9696
 9697        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9698        Some(
 9699            h_flex()
 9700                .min_w(min_width)
 9701                .max_w(max_width)
 9702                .flex_1()
 9703                .elevation_2(cx)
 9704                .border_color(cx.theme().colors().border)
 9705                .child(
 9706                    div()
 9707                        .flex_1()
 9708                        .py_1()
 9709                        .px_2()
 9710                        .overflow_hidden()
 9711                        .child(completion),
 9712                )
 9713                .when_some(accept_keystroke, |el, accept_keystroke| {
 9714                    if !accept_keystroke.modifiers().modified() {
 9715                        return el;
 9716                    }
 9717
 9718                    el.child(
 9719                        h_flex()
 9720                            .h_full()
 9721                            .border_l_1()
 9722                            .rounded_r_lg()
 9723                            .border_color(cx.theme().colors().border)
 9724                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9725                            .gap_1()
 9726                            .py_1()
 9727                            .px_2()
 9728                            .child(
 9729                                h_flex()
 9730                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9731                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9732                                    .child(h_flex().children(ui::render_modifiers(
 9733                                        accept_keystroke.modifiers(),
 9734                                        PlatformStyle::platform(),
 9735                                        Some(if !has_completion {
 9736                                            Color::Muted
 9737                                        } else {
 9738                                            Color::Default
 9739                                        }),
 9740                                        None,
 9741                                        false,
 9742                                    ))),
 9743                            )
 9744                            .child(Label::new("Preview").into_any_element())
 9745                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9746                    )
 9747                })
 9748                .into_any(),
 9749        )
 9750    }
 9751
 9752    fn render_edit_prediction_cursor_popover_preview(
 9753        &self,
 9754        completion: &EditPredictionState,
 9755        cursor_point: Point,
 9756        style: &EditorStyle,
 9757        cx: &mut Context<Editor>,
 9758    ) -> Option<Div> {
 9759        use text::ToPoint as _;
 9760
 9761        fn render_relative_row_jump(
 9762            prefix: impl Into<String>,
 9763            current_row: u32,
 9764            target_row: u32,
 9765        ) -> Div {
 9766            let (row_diff, arrow) = if target_row < current_row {
 9767                (current_row - target_row, IconName::ArrowUp)
 9768            } else {
 9769                (target_row - current_row, IconName::ArrowDown)
 9770            };
 9771
 9772            h_flex()
 9773                .child(
 9774                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9775                        .color(Color::Muted)
 9776                        .size(LabelSize::Small),
 9777                )
 9778                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9779        }
 9780
 9781        let supports_jump = self
 9782            .edit_prediction_provider
 9783            .as_ref()
 9784            .map(|provider| provider.provider.supports_jump_to_edit())
 9785            .unwrap_or(true);
 9786
 9787        match &completion.completion {
 9788            EditPrediction::MoveWithin {
 9789                target, snapshot, ..
 9790            } => {
 9791                if !supports_jump {
 9792                    return None;
 9793                }
 9794
 9795                Some(
 9796                    h_flex()
 9797                        .px_2()
 9798                        .gap_2()
 9799                        .flex_1()
 9800                        .child(
 9801                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9802                                Icon::new(IconName::ZedPredictDown)
 9803                            } else {
 9804                                Icon::new(IconName::ZedPredictUp)
 9805                            },
 9806                        )
 9807                        .child(Label::new("Jump to Edit")),
 9808                )
 9809            }
 9810            EditPrediction::MoveOutside { snapshot, .. } => {
 9811                let file_name = snapshot
 9812                    .file()
 9813                    .map(|file| file.file_name(cx))
 9814                    .unwrap_or("untitled");
 9815                Some(
 9816                    h_flex()
 9817                        .px_2()
 9818                        .gap_2()
 9819                        .flex_1()
 9820                        .child(Icon::new(IconName::ZedPredict))
 9821                        .child(Label::new(format!("Jump to {file_name}"))),
 9822                )
 9823            }
 9824            EditPrediction::Edit {
 9825                edits,
 9826                edit_preview,
 9827                snapshot,
 9828                display_mode: _,
 9829            } => {
 9830                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9831
 9832                let (highlighted_edits, has_more_lines) =
 9833                    if let Some(edit_preview) = edit_preview.as_ref() {
 9834                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9835                            .first_line_preview()
 9836                    } else {
 9837                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9838                    };
 9839
 9840                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9841                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9842
 9843                let preview = h_flex()
 9844                    .gap_1()
 9845                    .min_w_16()
 9846                    .child(styled_text)
 9847                    .when(has_more_lines, |parent| parent.child(""));
 9848
 9849                let left = if supports_jump && first_edit_row != cursor_point.row {
 9850                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9851                        .into_any_element()
 9852                } else {
 9853                    let icon_name =
 9854                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9855                    Icon::new(icon_name).into_any_element()
 9856                };
 9857
 9858                Some(
 9859                    h_flex()
 9860                        .h_full()
 9861                        .flex_1()
 9862                        .gap_2()
 9863                        .pr_1()
 9864                        .overflow_x_hidden()
 9865                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9866                        .child(left)
 9867                        .child(preview),
 9868                )
 9869            }
 9870        }
 9871    }
 9872
 9873    pub fn render_context_menu(
 9874        &self,
 9875        style: &EditorStyle,
 9876        max_height_in_lines: u32,
 9877        window: &mut Window,
 9878        cx: &mut Context<Editor>,
 9879    ) -> Option<AnyElement> {
 9880        let menu = self.context_menu.borrow();
 9881        let menu = menu.as_ref()?;
 9882        if !menu.visible() {
 9883            return None;
 9884        };
 9885        Some(menu.render(style, max_height_in_lines, window, cx))
 9886    }
 9887
 9888    fn render_context_menu_aside(
 9889        &mut self,
 9890        max_size: Size<Pixels>,
 9891        window: &mut Window,
 9892        cx: &mut Context<Editor>,
 9893    ) -> Option<AnyElement> {
 9894        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9895            if menu.visible() {
 9896                menu.render_aside(max_size, window, cx)
 9897            } else {
 9898                None
 9899            }
 9900        })
 9901    }
 9902
 9903    fn hide_context_menu(
 9904        &mut self,
 9905        window: &mut Window,
 9906        cx: &mut Context<Self>,
 9907    ) -> Option<CodeContextMenu> {
 9908        cx.notify();
 9909        self.completion_tasks.clear();
 9910        let context_menu = self.context_menu.borrow_mut().take();
 9911        self.stale_edit_prediction_in_menu.take();
 9912        self.update_visible_edit_prediction(window, cx);
 9913        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9914            && let Some(completion_provider) = &self.completion_provider
 9915        {
 9916            completion_provider.selection_changed(None, window, cx);
 9917        }
 9918        context_menu
 9919    }
 9920
 9921    fn show_snippet_choices(
 9922        &mut self,
 9923        choices: &Vec<String>,
 9924        selection: Range<Anchor>,
 9925        cx: &mut Context<Self>,
 9926    ) {
 9927        let Some((_, buffer, _)) = self
 9928            .buffer()
 9929            .read(cx)
 9930            .excerpt_containing(selection.start, cx)
 9931        else {
 9932            return;
 9933        };
 9934        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9935        else {
 9936            return;
 9937        };
 9938        if buffer != end_buffer {
 9939            log::error!("expected anchor range to have matching buffer IDs");
 9940            return;
 9941        }
 9942
 9943        let id = post_inc(&mut self.next_completion_id);
 9944        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9945        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9946            CompletionsMenu::new_snippet_choices(
 9947                id,
 9948                true,
 9949                choices,
 9950                selection,
 9951                buffer,
 9952                snippet_sort_order,
 9953            ),
 9954        ));
 9955    }
 9956
 9957    pub fn insert_snippet(
 9958        &mut self,
 9959        insertion_ranges: &[Range<MultiBufferOffset>],
 9960        snippet: Snippet,
 9961        window: &mut Window,
 9962        cx: &mut Context<Self>,
 9963    ) -> Result<()> {
 9964        struct Tabstop<T> {
 9965            is_end_tabstop: bool,
 9966            ranges: Vec<Range<T>>,
 9967            choices: Option<Vec<String>>,
 9968        }
 9969
 9970        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9971            let snippet_text: Arc<str> = snippet.text.clone().into();
 9972            let edits = insertion_ranges
 9973                .iter()
 9974                .cloned()
 9975                .map(|range| (range, snippet_text.clone()));
 9976            let autoindent_mode = AutoindentMode::Block {
 9977                original_indent_columns: Vec::new(),
 9978            };
 9979            buffer.edit(edits, Some(autoindent_mode), cx);
 9980
 9981            let snapshot = &*buffer.read(cx);
 9982            let snippet = &snippet;
 9983            snippet
 9984                .tabstops
 9985                .iter()
 9986                .map(|tabstop| {
 9987                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9988                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9989                    });
 9990                    let mut tabstop_ranges = tabstop
 9991                        .ranges
 9992                        .iter()
 9993                        .flat_map(|tabstop_range| {
 9994                            let mut delta = 0_isize;
 9995                            insertion_ranges.iter().map(move |insertion_range| {
 9996                                let insertion_start = insertion_range.start + delta;
 9997                                delta += snippet.text.len() as isize
 9998                                    - (insertion_range.end - insertion_range.start) as isize;
 9999
10000                                let start =
10001                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10002                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10003                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10004                            })
10005                        })
10006                        .collect::<Vec<_>>();
10007                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10008
10009                    Tabstop {
10010                        is_end_tabstop,
10011                        ranges: tabstop_ranges,
10012                        choices: tabstop.choices.clone(),
10013                    }
10014                })
10015                .collect::<Vec<_>>()
10016        });
10017        if let Some(tabstop) = tabstops.first() {
10018            self.change_selections(Default::default(), window, cx, |s| {
10019                // Reverse order so that the first range is the newest created selection.
10020                // Completions will use it and autoscroll will prioritize it.
10021                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10022            });
10023
10024            if let Some(choices) = &tabstop.choices
10025                && let Some(selection) = tabstop.ranges.first()
10026            {
10027                self.show_snippet_choices(choices, selection.clone(), cx)
10028            }
10029
10030            // If we're already at the last tabstop and it's at the end of the snippet,
10031            // we're done, we don't need to keep the state around.
10032            if !tabstop.is_end_tabstop {
10033                let choices = tabstops
10034                    .iter()
10035                    .map(|tabstop| tabstop.choices.clone())
10036                    .collect();
10037
10038                let ranges = tabstops
10039                    .into_iter()
10040                    .map(|tabstop| tabstop.ranges)
10041                    .collect::<Vec<_>>();
10042
10043                self.snippet_stack.push(SnippetState {
10044                    active_index: 0,
10045                    ranges,
10046                    choices,
10047                });
10048            }
10049
10050            // Check whether the just-entered snippet ends with an auto-closable bracket.
10051            if self.autoclose_regions.is_empty() {
10052                let snapshot = self.buffer.read(cx).snapshot(cx);
10053                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10054                    let selection_head = selection.head();
10055                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10056                        continue;
10057                    };
10058
10059                    let mut bracket_pair = None;
10060                    let max_lookup_length = scope
10061                        .brackets()
10062                        .map(|(pair, _)| {
10063                            pair.start
10064                                .as_str()
10065                                .chars()
10066                                .count()
10067                                .max(pair.end.as_str().chars().count())
10068                        })
10069                        .max();
10070                    if let Some(max_lookup_length) = max_lookup_length {
10071                        let next_text = snapshot
10072                            .chars_at(selection_head)
10073                            .take(max_lookup_length)
10074                            .collect::<String>();
10075                        let prev_text = snapshot
10076                            .reversed_chars_at(selection_head)
10077                            .take(max_lookup_length)
10078                            .collect::<String>();
10079
10080                        for (pair, enabled) in scope.brackets() {
10081                            if enabled
10082                                && pair.close
10083                                && prev_text.starts_with(pair.start.as_str())
10084                                && next_text.starts_with(pair.end.as_str())
10085                            {
10086                                bracket_pair = Some(pair.clone());
10087                                break;
10088                            }
10089                        }
10090                    }
10091
10092                    if let Some(pair) = bracket_pair {
10093                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10094                        let autoclose_enabled =
10095                            self.use_autoclose && snapshot_settings.use_autoclose;
10096                        if autoclose_enabled {
10097                            let start = snapshot.anchor_after(selection_head);
10098                            let end = snapshot.anchor_after(selection_head);
10099                            self.autoclose_regions.push(AutocloseRegion {
10100                                selection_id: selection.id,
10101                                range: start..end,
10102                                pair,
10103                            });
10104                        }
10105                    }
10106                }
10107            }
10108        }
10109        Ok(())
10110    }
10111
10112    pub fn move_to_next_snippet_tabstop(
10113        &mut self,
10114        window: &mut Window,
10115        cx: &mut Context<Self>,
10116    ) -> bool {
10117        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10118    }
10119
10120    pub fn move_to_prev_snippet_tabstop(
10121        &mut self,
10122        window: &mut Window,
10123        cx: &mut Context<Self>,
10124    ) -> bool {
10125        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10126    }
10127
10128    pub fn move_to_snippet_tabstop(
10129        &mut self,
10130        bias: Bias,
10131        window: &mut Window,
10132        cx: &mut Context<Self>,
10133    ) -> bool {
10134        if let Some(mut snippet) = self.snippet_stack.pop() {
10135            match bias {
10136                Bias::Left => {
10137                    if snippet.active_index > 0 {
10138                        snippet.active_index -= 1;
10139                    } else {
10140                        self.snippet_stack.push(snippet);
10141                        return false;
10142                    }
10143                }
10144                Bias::Right => {
10145                    if snippet.active_index + 1 < snippet.ranges.len() {
10146                        snippet.active_index += 1;
10147                    } else {
10148                        self.snippet_stack.push(snippet);
10149                        return false;
10150                    }
10151                }
10152            }
10153            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10154                self.change_selections(Default::default(), window, cx, |s| {
10155                    // Reverse order so that the first range is the newest created selection.
10156                    // Completions will use it and autoscroll will prioritize it.
10157                    s.select_ranges(current_ranges.iter().rev().cloned())
10158                });
10159
10160                if let Some(choices) = &snippet.choices[snippet.active_index]
10161                    && let Some(selection) = current_ranges.first()
10162                {
10163                    self.show_snippet_choices(choices, selection.clone(), cx);
10164                }
10165
10166                // If snippet state is not at the last tabstop, push it back on the stack
10167                if snippet.active_index + 1 < snippet.ranges.len() {
10168                    self.snippet_stack.push(snippet);
10169                }
10170                return true;
10171            }
10172        }
10173
10174        false
10175    }
10176
10177    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10178        self.transact(window, cx, |this, window, cx| {
10179            this.select_all(&SelectAll, window, cx);
10180            this.insert("", window, cx);
10181        });
10182    }
10183
10184    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10185        if self.read_only(cx) {
10186            return;
10187        }
10188        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10189        self.transact(window, cx, |this, window, cx| {
10190            this.select_autoclose_pair(window, cx);
10191
10192            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10193
10194            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10195            if !this.linked_edit_ranges.is_empty() {
10196                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10197                let snapshot = this.buffer.read(cx).snapshot(cx);
10198
10199                for selection in selections.iter() {
10200                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10201                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10202                    if selection_start.buffer_id != selection_end.buffer_id {
10203                        continue;
10204                    }
10205                    if let Some(ranges) =
10206                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10207                    {
10208                        for (buffer, entries) in ranges {
10209                            linked_ranges.entry(buffer).or_default().extend(entries);
10210                        }
10211                    }
10212                }
10213            }
10214
10215            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10216            for selection in &mut selections {
10217                if selection.is_empty() {
10218                    let old_head = selection.head();
10219                    let mut new_head =
10220                        movement::left(&display_map, old_head.to_display_point(&display_map))
10221                            .to_point(&display_map);
10222                    if let Some((buffer, line_buffer_range)) = display_map
10223                        .buffer_snapshot()
10224                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10225                    {
10226                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10227                        let indent_len = match indent_size.kind {
10228                            IndentKind::Space => {
10229                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10230                            }
10231                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10232                        };
10233                        if old_head.column <= indent_size.len && old_head.column > 0 {
10234                            let indent_len = indent_len.get();
10235                            new_head = cmp::min(
10236                                new_head,
10237                                MultiBufferPoint::new(
10238                                    old_head.row,
10239                                    ((old_head.column - 1) / indent_len) * indent_len,
10240                                ),
10241                            );
10242                        }
10243                    }
10244
10245                    selection.set_head(new_head, SelectionGoal::None);
10246                }
10247            }
10248
10249            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10250            this.insert("", window, cx);
10251            let empty_str: Arc<str> = Arc::from("");
10252            for (buffer, edits) in linked_ranges {
10253                let snapshot = buffer.read(cx).snapshot();
10254                use text::ToPoint as TP;
10255
10256                let edits = edits
10257                    .into_iter()
10258                    .map(|range| {
10259                        let end_point = TP::to_point(&range.end, &snapshot);
10260                        let mut start_point = TP::to_point(&range.start, &snapshot);
10261
10262                        if end_point == start_point {
10263                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10264                                .saturating_sub(1);
10265                            start_point =
10266                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10267                        };
10268
10269                        (start_point..end_point, empty_str.clone())
10270                    })
10271                    .sorted_by_key(|(range, _)| range.start)
10272                    .collect::<Vec<_>>();
10273                buffer.update(cx, |this, cx| {
10274                    this.edit(edits, None, cx);
10275                })
10276            }
10277            this.refresh_edit_prediction(true, false, window, cx);
10278            refresh_linked_ranges(this, window, cx);
10279        });
10280    }
10281
10282    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10283        if self.read_only(cx) {
10284            return;
10285        }
10286        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10287        self.transact(window, cx, |this, window, cx| {
10288            this.change_selections(Default::default(), window, cx, |s| {
10289                s.move_with(|map, selection| {
10290                    if selection.is_empty() {
10291                        let cursor = movement::right(map, selection.head());
10292                        selection.end = cursor;
10293                        selection.reversed = true;
10294                        selection.goal = SelectionGoal::None;
10295                    }
10296                })
10297            });
10298            this.insert("", window, cx);
10299            this.refresh_edit_prediction(true, false, window, cx);
10300        });
10301    }
10302
10303    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10304        if self.mode.is_single_line() {
10305            cx.propagate();
10306            return;
10307        }
10308
10309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10310        if self.move_to_prev_snippet_tabstop(window, cx) {
10311            return;
10312        }
10313        self.outdent(&Outdent, window, cx);
10314    }
10315
10316    pub fn next_snippet_tabstop(
10317        &mut self,
10318        _: &NextSnippetTabstop,
10319        window: &mut Window,
10320        cx: &mut Context<Self>,
10321    ) {
10322        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10323            cx.propagate();
10324            return;
10325        }
10326
10327        if self.move_to_next_snippet_tabstop(window, cx) {
10328            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10329            return;
10330        }
10331        cx.propagate();
10332    }
10333
10334    pub fn previous_snippet_tabstop(
10335        &mut self,
10336        _: &PreviousSnippetTabstop,
10337        window: &mut Window,
10338        cx: &mut Context<Self>,
10339    ) {
10340        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10341            cx.propagate();
10342            return;
10343        }
10344
10345        if self.move_to_prev_snippet_tabstop(window, cx) {
10346            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10347            return;
10348        }
10349        cx.propagate();
10350    }
10351
10352    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10353        if self.mode.is_single_line() {
10354            cx.propagate();
10355            return;
10356        }
10357
10358        if self.move_to_next_snippet_tabstop(window, cx) {
10359            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10360            return;
10361        }
10362        if self.read_only(cx) {
10363            return;
10364        }
10365        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10366        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10367        let buffer = self.buffer.read(cx);
10368        let snapshot = buffer.snapshot(cx);
10369        let rows_iter = selections.iter().map(|s| s.head().row);
10370        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10371
10372        let has_some_cursor_in_whitespace = selections
10373            .iter()
10374            .filter(|selection| selection.is_empty())
10375            .any(|selection| {
10376                let cursor = selection.head();
10377                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10378                cursor.column < current_indent.len
10379            });
10380
10381        let mut edits = Vec::new();
10382        let mut prev_edited_row = 0;
10383        let mut row_delta = 0;
10384        for selection in &mut selections {
10385            if selection.start.row != prev_edited_row {
10386                row_delta = 0;
10387            }
10388            prev_edited_row = selection.end.row;
10389
10390            // If the selection is non-empty, then increase the indentation of the selected lines.
10391            if !selection.is_empty() {
10392                row_delta =
10393                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10394                continue;
10395            }
10396
10397            let cursor = selection.head();
10398            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10399            if let Some(suggested_indent) =
10400                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10401            {
10402                // Don't do anything if already at suggested indent
10403                // and there is any other cursor which is not
10404                if has_some_cursor_in_whitespace
10405                    && cursor.column == current_indent.len
10406                    && current_indent.len == suggested_indent.len
10407                {
10408                    continue;
10409                }
10410
10411                // Adjust line and move cursor to suggested indent
10412                // if cursor is not at suggested indent
10413                if cursor.column < suggested_indent.len
10414                    && cursor.column <= current_indent.len
10415                    && current_indent.len <= suggested_indent.len
10416                {
10417                    selection.start = Point::new(cursor.row, suggested_indent.len);
10418                    selection.end = selection.start;
10419                    if row_delta == 0 {
10420                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10421                            cursor.row,
10422                            current_indent,
10423                            suggested_indent,
10424                        ));
10425                        row_delta = suggested_indent.len - current_indent.len;
10426                    }
10427                    continue;
10428                }
10429
10430                // If current indent is more than suggested indent
10431                // only move cursor to current indent and skip indent
10432                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10433                    selection.start = Point::new(cursor.row, current_indent.len);
10434                    selection.end = selection.start;
10435                    continue;
10436                }
10437            }
10438
10439            // Otherwise, insert a hard or soft tab.
10440            let settings = buffer.language_settings_at(cursor, cx);
10441            let tab_size = if settings.hard_tabs {
10442                IndentSize::tab()
10443            } else {
10444                let tab_size = settings.tab_size.get();
10445                let indent_remainder = snapshot
10446                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10447                    .flat_map(str::chars)
10448                    .fold(row_delta % tab_size, |counter: u32, c| {
10449                        if c == '\t' {
10450                            0
10451                        } else {
10452                            (counter + 1) % tab_size
10453                        }
10454                    });
10455
10456                let chars_to_next_tab_stop = tab_size - indent_remainder;
10457                IndentSize::spaces(chars_to_next_tab_stop)
10458            };
10459            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10460            selection.end = selection.start;
10461            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10462            row_delta += tab_size.len;
10463        }
10464
10465        self.transact(window, cx, |this, window, cx| {
10466            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10467            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10468            this.refresh_edit_prediction(true, false, window, cx);
10469        });
10470    }
10471
10472    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10473        if self.read_only(cx) {
10474            return;
10475        }
10476        if self.mode.is_single_line() {
10477            cx.propagate();
10478            return;
10479        }
10480
10481        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10482        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10483        let mut prev_edited_row = 0;
10484        let mut row_delta = 0;
10485        let mut edits = Vec::new();
10486        let buffer = self.buffer.read(cx);
10487        let snapshot = buffer.snapshot(cx);
10488        for selection in &mut selections {
10489            if selection.start.row != prev_edited_row {
10490                row_delta = 0;
10491            }
10492            prev_edited_row = selection.end.row;
10493
10494            row_delta =
10495                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10496        }
10497
10498        self.transact(window, cx, |this, window, cx| {
10499            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10500            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10501        });
10502    }
10503
10504    fn indent_selection(
10505        buffer: &MultiBuffer,
10506        snapshot: &MultiBufferSnapshot,
10507        selection: &mut Selection<Point>,
10508        edits: &mut Vec<(Range<Point>, String)>,
10509        delta_for_start_row: u32,
10510        cx: &App,
10511    ) -> u32 {
10512        let settings = buffer.language_settings_at(selection.start, cx);
10513        let tab_size = settings.tab_size.get();
10514        let indent_kind = if settings.hard_tabs {
10515            IndentKind::Tab
10516        } else {
10517            IndentKind::Space
10518        };
10519        let mut start_row = selection.start.row;
10520        let mut end_row = selection.end.row + 1;
10521
10522        // If a selection ends at the beginning of a line, don't indent
10523        // that last line.
10524        if selection.end.column == 0 && selection.end.row > selection.start.row {
10525            end_row -= 1;
10526        }
10527
10528        // Avoid re-indenting a row that has already been indented by a
10529        // previous selection, but still update this selection's column
10530        // to reflect that indentation.
10531        if delta_for_start_row > 0 {
10532            start_row += 1;
10533            selection.start.column += delta_for_start_row;
10534            if selection.end.row == selection.start.row {
10535                selection.end.column += delta_for_start_row;
10536            }
10537        }
10538
10539        let mut delta_for_end_row = 0;
10540        let has_multiple_rows = start_row + 1 != end_row;
10541        for row in start_row..end_row {
10542            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10543            let indent_delta = match (current_indent.kind, indent_kind) {
10544                (IndentKind::Space, IndentKind::Space) => {
10545                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10546                    IndentSize::spaces(columns_to_next_tab_stop)
10547                }
10548                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10549                (_, IndentKind::Tab) => IndentSize::tab(),
10550            };
10551
10552            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10553                0
10554            } else {
10555                selection.start.column
10556            };
10557            let row_start = Point::new(row, start);
10558            edits.push((
10559                row_start..row_start,
10560                indent_delta.chars().collect::<String>(),
10561            ));
10562
10563            // Update this selection's endpoints to reflect the indentation.
10564            if row == selection.start.row {
10565                selection.start.column += indent_delta.len;
10566            }
10567            if row == selection.end.row {
10568                selection.end.column += indent_delta.len;
10569                delta_for_end_row = indent_delta.len;
10570            }
10571        }
10572
10573        if selection.start.row == selection.end.row {
10574            delta_for_start_row + delta_for_end_row
10575        } else {
10576            delta_for_end_row
10577        }
10578    }
10579
10580    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10581        if self.read_only(cx) {
10582            return;
10583        }
10584        if self.mode.is_single_line() {
10585            cx.propagate();
10586            return;
10587        }
10588
10589        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10590        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10591        let selections = self.selections.all::<Point>(&display_map);
10592        let mut deletion_ranges = Vec::new();
10593        let mut last_outdent = None;
10594        {
10595            let buffer = self.buffer.read(cx);
10596            let snapshot = buffer.snapshot(cx);
10597            for selection in &selections {
10598                let settings = buffer.language_settings_at(selection.start, cx);
10599                let tab_size = settings.tab_size.get();
10600                let mut rows = selection.spanned_rows(false, &display_map);
10601
10602                // Avoid re-outdenting a row that has already been outdented by a
10603                // previous selection.
10604                if let Some(last_row) = last_outdent
10605                    && last_row == rows.start
10606                {
10607                    rows.start = rows.start.next_row();
10608                }
10609                let has_multiple_rows = rows.len() > 1;
10610                for row in rows.iter_rows() {
10611                    let indent_size = snapshot.indent_size_for_line(row);
10612                    if indent_size.len > 0 {
10613                        let deletion_len = match indent_size.kind {
10614                            IndentKind::Space => {
10615                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10616                                if columns_to_prev_tab_stop == 0 {
10617                                    tab_size
10618                                } else {
10619                                    columns_to_prev_tab_stop
10620                                }
10621                            }
10622                            IndentKind::Tab => 1,
10623                        };
10624                        let start = if has_multiple_rows
10625                            || deletion_len > selection.start.column
10626                            || indent_size.len < selection.start.column
10627                        {
10628                            0
10629                        } else {
10630                            selection.start.column - deletion_len
10631                        };
10632                        deletion_ranges.push(
10633                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10634                        );
10635                        last_outdent = Some(row);
10636                    }
10637                }
10638            }
10639        }
10640
10641        self.transact(window, cx, |this, window, cx| {
10642            this.buffer.update(cx, |buffer, cx| {
10643                let empty_str: Arc<str> = Arc::default();
10644                buffer.edit(
10645                    deletion_ranges
10646                        .into_iter()
10647                        .map(|range| (range, empty_str.clone())),
10648                    None,
10649                    cx,
10650                );
10651            });
10652            let selections = this
10653                .selections
10654                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10655            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10656        });
10657    }
10658
10659    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10660        if self.read_only(cx) {
10661            return;
10662        }
10663        if self.mode.is_single_line() {
10664            cx.propagate();
10665            return;
10666        }
10667
10668        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10669        let selections = self
10670            .selections
10671            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10672            .into_iter()
10673            .map(|s| s.range());
10674
10675        self.transact(window, cx, |this, window, cx| {
10676            this.buffer.update(cx, |buffer, cx| {
10677                buffer.autoindent_ranges(selections, cx);
10678            });
10679            let selections = this
10680                .selections
10681                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10682            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10683        });
10684    }
10685
10686    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10687        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10688        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10689        let selections = self.selections.all::<Point>(&display_map);
10690
10691        let mut new_cursors = Vec::new();
10692        let mut edit_ranges = Vec::new();
10693        let mut selections = selections.iter().peekable();
10694        while let Some(selection) = selections.next() {
10695            let mut rows = selection.spanned_rows(false, &display_map);
10696
10697            // Accumulate contiguous regions of rows that we want to delete.
10698            while let Some(next_selection) = selections.peek() {
10699                let next_rows = next_selection.spanned_rows(false, &display_map);
10700                if next_rows.start <= rows.end {
10701                    rows.end = next_rows.end;
10702                    selections.next().unwrap();
10703                } else {
10704                    break;
10705                }
10706            }
10707
10708            let buffer = display_map.buffer_snapshot();
10709            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10710            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10711                // If there's a line after the range, delete the \n from the end of the row range
10712                (
10713                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10714                    rows.end,
10715                )
10716            } else {
10717                // If there isn't a line after the range, delete the \n from the line before the
10718                // start of the row range
10719                edit_start = edit_start.saturating_sub_usize(1);
10720                (buffer.len(), rows.start.previous_row())
10721            };
10722
10723            let text_layout_details = self.text_layout_details(window);
10724            let x = display_map.x_for_display_point(
10725                selection.head().to_display_point(&display_map),
10726                &text_layout_details,
10727            );
10728            let row = Point::new(target_row.0, 0)
10729                .to_display_point(&display_map)
10730                .row();
10731            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10732
10733            new_cursors.push((
10734                selection.id,
10735                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10736                SelectionGoal::None,
10737            ));
10738            edit_ranges.push(edit_start..edit_end);
10739        }
10740
10741        self.transact(window, cx, |this, window, cx| {
10742            let buffer = this.buffer.update(cx, |buffer, cx| {
10743                let empty_str: Arc<str> = Arc::default();
10744                buffer.edit(
10745                    edit_ranges
10746                        .into_iter()
10747                        .map(|range| (range, empty_str.clone())),
10748                    None,
10749                    cx,
10750                );
10751                buffer.snapshot(cx)
10752            });
10753            let new_selections = new_cursors
10754                .into_iter()
10755                .map(|(id, cursor, goal)| {
10756                    let cursor = cursor.to_point(&buffer);
10757                    Selection {
10758                        id,
10759                        start: cursor,
10760                        end: cursor,
10761                        reversed: false,
10762                        goal,
10763                    }
10764                })
10765                .collect();
10766
10767            this.change_selections(Default::default(), window, cx, |s| {
10768                s.select(new_selections);
10769            });
10770        });
10771    }
10772
10773    pub fn join_lines_impl(
10774        &mut self,
10775        insert_whitespace: bool,
10776        window: &mut Window,
10777        cx: &mut Context<Self>,
10778    ) {
10779        if self.read_only(cx) {
10780            return;
10781        }
10782        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10783        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10784            let start = MultiBufferRow(selection.start.row);
10785            // Treat single line selections as if they include the next line. Otherwise this action
10786            // would do nothing for single line selections individual cursors.
10787            let end = if selection.start.row == selection.end.row {
10788                MultiBufferRow(selection.start.row + 1)
10789            } else {
10790                MultiBufferRow(selection.end.row)
10791            };
10792
10793            if let Some(last_row_range) = row_ranges.last_mut()
10794                && start <= last_row_range.end
10795            {
10796                last_row_range.end = end;
10797                continue;
10798            }
10799            row_ranges.push(start..end);
10800        }
10801
10802        let snapshot = self.buffer.read(cx).snapshot(cx);
10803        let mut cursor_positions = Vec::new();
10804        for row_range in &row_ranges {
10805            let anchor = snapshot.anchor_before(Point::new(
10806                row_range.end.previous_row().0,
10807                snapshot.line_len(row_range.end.previous_row()),
10808            ));
10809            cursor_positions.push(anchor..anchor);
10810        }
10811
10812        self.transact(window, cx, |this, window, cx| {
10813            for row_range in row_ranges.into_iter().rev() {
10814                for row in row_range.iter_rows().rev() {
10815                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10816                    let next_line_row = row.next_row();
10817                    let indent = snapshot.indent_size_for_line(next_line_row);
10818                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10819
10820                    let replace =
10821                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10822                            " "
10823                        } else {
10824                            ""
10825                        };
10826
10827                    this.buffer.update(cx, |buffer, cx| {
10828                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10829                    });
10830                }
10831            }
10832
10833            this.change_selections(Default::default(), window, cx, |s| {
10834                s.select_anchor_ranges(cursor_positions)
10835            });
10836        });
10837    }
10838
10839    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10840        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10841        self.join_lines_impl(true, window, cx);
10842    }
10843
10844    pub fn sort_lines_case_sensitive(
10845        &mut self,
10846        _: &SortLinesCaseSensitive,
10847        window: &mut Window,
10848        cx: &mut Context<Self>,
10849    ) {
10850        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10851    }
10852
10853    pub fn sort_lines_by_length(
10854        &mut self,
10855        _: &SortLinesByLength,
10856        window: &mut Window,
10857        cx: &mut Context<Self>,
10858    ) {
10859        self.manipulate_immutable_lines(window, cx, |lines| {
10860            lines.sort_by_key(|&line| line.chars().count())
10861        })
10862    }
10863
10864    pub fn sort_lines_case_insensitive(
10865        &mut self,
10866        _: &SortLinesCaseInsensitive,
10867        window: &mut Window,
10868        cx: &mut Context<Self>,
10869    ) {
10870        self.manipulate_immutable_lines(window, cx, |lines| {
10871            lines.sort_by_key(|line| line.to_lowercase())
10872        })
10873    }
10874
10875    pub fn unique_lines_case_insensitive(
10876        &mut self,
10877        _: &UniqueLinesCaseInsensitive,
10878        window: &mut Window,
10879        cx: &mut Context<Self>,
10880    ) {
10881        self.manipulate_immutable_lines(window, cx, |lines| {
10882            let mut seen = HashSet::default();
10883            lines.retain(|line| seen.insert(line.to_lowercase()));
10884        })
10885    }
10886
10887    pub fn unique_lines_case_sensitive(
10888        &mut self,
10889        _: &UniqueLinesCaseSensitive,
10890        window: &mut Window,
10891        cx: &mut Context<Self>,
10892    ) {
10893        self.manipulate_immutable_lines(window, cx, |lines| {
10894            let mut seen = HashSet::default();
10895            lines.retain(|line| seen.insert(*line));
10896        })
10897    }
10898
10899    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10900        let snapshot = self.buffer.read(cx).snapshot(cx);
10901        for selection in self.selections.disjoint_anchors_arc().iter() {
10902            if snapshot
10903                .language_at(selection.start)
10904                .and_then(|lang| lang.config().wrap_characters.as_ref())
10905                .is_some()
10906            {
10907                return true;
10908            }
10909        }
10910        false
10911    }
10912
10913    fn wrap_selections_in_tag(
10914        &mut self,
10915        _: &WrapSelectionsInTag,
10916        window: &mut Window,
10917        cx: &mut Context<Self>,
10918    ) {
10919        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10920
10921        let snapshot = self.buffer.read(cx).snapshot(cx);
10922
10923        let mut edits = Vec::new();
10924        let mut boundaries = Vec::new();
10925
10926        for selection in self
10927            .selections
10928            .all_adjusted(&self.display_snapshot(cx))
10929            .iter()
10930        {
10931            let Some(wrap_config) = snapshot
10932                .language_at(selection.start)
10933                .and_then(|lang| lang.config().wrap_characters.clone())
10934            else {
10935                continue;
10936            };
10937
10938            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10939            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10940
10941            let start_before = snapshot.anchor_before(selection.start);
10942            let end_after = snapshot.anchor_after(selection.end);
10943
10944            edits.push((start_before..start_before, open_tag));
10945            edits.push((end_after..end_after, close_tag));
10946
10947            boundaries.push((
10948                start_before,
10949                end_after,
10950                wrap_config.start_prefix.len(),
10951                wrap_config.end_suffix.len(),
10952            ));
10953        }
10954
10955        if edits.is_empty() {
10956            return;
10957        }
10958
10959        self.transact(window, cx, |this, window, cx| {
10960            let buffer = this.buffer.update(cx, |buffer, cx| {
10961                buffer.edit(edits, None, cx);
10962                buffer.snapshot(cx)
10963            });
10964
10965            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10966            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10967                boundaries.into_iter()
10968            {
10969                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10970                let close_offset = end_after
10971                    .to_offset(&buffer)
10972                    .saturating_sub_usize(end_suffix_len);
10973                new_selections.push(open_offset..open_offset);
10974                new_selections.push(close_offset..close_offset);
10975            }
10976
10977            this.change_selections(Default::default(), window, cx, |s| {
10978                s.select_ranges(new_selections);
10979            });
10980
10981            this.request_autoscroll(Autoscroll::fit(), cx);
10982        });
10983    }
10984
10985    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10986        let Some(project) = self.project.clone() else {
10987            return;
10988        };
10989        self.reload(project, window, cx)
10990            .detach_and_notify_err(window, cx);
10991    }
10992
10993    pub fn restore_file(
10994        &mut self,
10995        _: &::git::RestoreFile,
10996        window: &mut Window,
10997        cx: &mut Context<Self>,
10998    ) {
10999        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11000        let mut buffer_ids = HashSet::default();
11001        let snapshot = self.buffer().read(cx).snapshot(cx);
11002        for selection in self
11003            .selections
11004            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11005        {
11006            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11007        }
11008
11009        let buffer = self.buffer().read(cx);
11010        let ranges = buffer_ids
11011            .into_iter()
11012            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11013            .collect::<Vec<_>>();
11014
11015        self.restore_hunks_in_ranges(ranges, window, cx);
11016    }
11017
11018    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11019        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11020        let selections = self
11021            .selections
11022            .all(&self.display_snapshot(cx))
11023            .into_iter()
11024            .map(|s| s.range())
11025            .collect();
11026        self.restore_hunks_in_ranges(selections, window, cx);
11027    }
11028
11029    pub fn restore_hunks_in_ranges(
11030        &mut self,
11031        ranges: Vec<Range<Point>>,
11032        window: &mut Window,
11033        cx: &mut Context<Editor>,
11034    ) {
11035        let mut revert_changes = HashMap::default();
11036        let chunk_by = self
11037            .snapshot(window, cx)
11038            .hunks_for_ranges(ranges)
11039            .into_iter()
11040            .chunk_by(|hunk| hunk.buffer_id);
11041        for (buffer_id, hunks) in &chunk_by {
11042            let hunks = hunks.collect::<Vec<_>>();
11043            for hunk in &hunks {
11044                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11045            }
11046            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11047        }
11048        drop(chunk_by);
11049        if !revert_changes.is_empty() {
11050            self.transact(window, cx, |editor, window, cx| {
11051                editor.restore(revert_changes, window, cx);
11052            });
11053        }
11054    }
11055
11056    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11057        if let Some(status) = self
11058            .addons
11059            .iter()
11060            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11061        {
11062            return Some(status);
11063        }
11064        self.project
11065            .as_ref()?
11066            .read(cx)
11067            .status_for_buffer_id(buffer_id, cx)
11068    }
11069
11070    pub fn open_active_item_in_terminal(
11071        &mut self,
11072        _: &OpenInTerminal,
11073        window: &mut Window,
11074        cx: &mut Context<Self>,
11075    ) {
11076        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11077            let project_path = buffer.read(cx).project_path(cx)?;
11078            let project = self.project()?.read(cx);
11079            let entry = project.entry_for_path(&project_path, cx)?;
11080            let parent = match &entry.canonical_path {
11081                Some(canonical_path) => canonical_path.to_path_buf(),
11082                None => project.absolute_path(&project_path, cx)?,
11083            }
11084            .parent()?
11085            .to_path_buf();
11086            Some(parent)
11087        }) {
11088            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11089        }
11090    }
11091
11092    fn set_breakpoint_context_menu(
11093        &mut self,
11094        display_row: DisplayRow,
11095        position: Option<Anchor>,
11096        clicked_point: gpui::Point<Pixels>,
11097        window: &mut Window,
11098        cx: &mut Context<Self>,
11099    ) {
11100        let source = self
11101            .buffer
11102            .read(cx)
11103            .snapshot(cx)
11104            .anchor_before(Point::new(display_row.0, 0u32));
11105
11106        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11107
11108        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11109            self,
11110            source,
11111            clicked_point,
11112            context_menu,
11113            window,
11114            cx,
11115        );
11116    }
11117
11118    fn add_edit_breakpoint_block(
11119        &mut self,
11120        anchor: Anchor,
11121        breakpoint: &Breakpoint,
11122        edit_action: BreakpointPromptEditAction,
11123        window: &mut Window,
11124        cx: &mut Context<Self>,
11125    ) {
11126        let weak_editor = cx.weak_entity();
11127        let bp_prompt = cx.new(|cx| {
11128            BreakpointPromptEditor::new(
11129                weak_editor,
11130                anchor,
11131                breakpoint.clone(),
11132                edit_action,
11133                window,
11134                cx,
11135            )
11136        });
11137
11138        let height = bp_prompt.update(cx, |this, cx| {
11139            this.prompt
11140                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11141        });
11142        let cloned_prompt = bp_prompt.clone();
11143        let blocks = vec![BlockProperties {
11144            style: BlockStyle::Sticky,
11145            placement: BlockPlacement::Above(anchor),
11146            height: Some(height),
11147            render: Arc::new(move |cx| {
11148                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11149                cloned_prompt.clone().into_any_element()
11150            }),
11151            priority: 0,
11152        }];
11153
11154        let focus_handle = bp_prompt.focus_handle(cx);
11155        window.focus(&focus_handle);
11156
11157        let block_ids = self.insert_blocks(blocks, None, cx);
11158        bp_prompt.update(cx, |prompt, _| {
11159            prompt.add_block_ids(block_ids);
11160        });
11161    }
11162
11163    pub(crate) fn breakpoint_at_row(
11164        &self,
11165        row: u32,
11166        window: &mut Window,
11167        cx: &mut Context<Self>,
11168    ) -> Option<(Anchor, Breakpoint)> {
11169        let snapshot = self.snapshot(window, cx);
11170        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11171
11172        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11173    }
11174
11175    pub(crate) fn breakpoint_at_anchor(
11176        &self,
11177        breakpoint_position: Anchor,
11178        snapshot: &EditorSnapshot,
11179        cx: &mut Context<Self>,
11180    ) -> Option<(Anchor, Breakpoint)> {
11181        let buffer = self
11182            .buffer
11183            .read(cx)
11184            .buffer_for_anchor(breakpoint_position, cx)?;
11185
11186        let enclosing_excerpt = breakpoint_position.excerpt_id;
11187        let buffer_snapshot = buffer.read(cx).snapshot();
11188
11189        let row = buffer_snapshot
11190            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11191            .row;
11192
11193        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11194        let anchor_end = snapshot
11195            .buffer_snapshot()
11196            .anchor_after(Point::new(row, line_len));
11197
11198        self.breakpoint_store
11199            .as_ref()?
11200            .read_with(cx, |breakpoint_store, cx| {
11201                breakpoint_store
11202                    .breakpoints(
11203                        &buffer,
11204                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11205                        &buffer_snapshot,
11206                        cx,
11207                    )
11208                    .next()
11209                    .and_then(|(bp, _)| {
11210                        let breakpoint_row = buffer_snapshot
11211                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11212                            .row;
11213
11214                        if breakpoint_row == row {
11215                            snapshot
11216                                .buffer_snapshot()
11217                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11218                                .map(|position| (position, bp.bp.clone()))
11219                        } else {
11220                            None
11221                        }
11222                    })
11223            })
11224    }
11225
11226    pub fn edit_log_breakpoint(
11227        &mut self,
11228        _: &EditLogBreakpoint,
11229        window: &mut Window,
11230        cx: &mut Context<Self>,
11231    ) {
11232        if self.breakpoint_store.is_none() {
11233            return;
11234        }
11235
11236        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11237            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11238                message: None,
11239                state: BreakpointState::Enabled,
11240                condition: None,
11241                hit_condition: None,
11242            });
11243
11244            self.add_edit_breakpoint_block(
11245                anchor,
11246                &breakpoint,
11247                BreakpointPromptEditAction::Log,
11248                window,
11249                cx,
11250            );
11251        }
11252    }
11253
11254    fn breakpoints_at_cursors(
11255        &self,
11256        window: &mut Window,
11257        cx: &mut Context<Self>,
11258    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11259        let snapshot = self.snapshot(window, cx);
11260        let cursors = self
11261            .selections
11262            .disjoint_anchors_arc()
11263            .iter()
11264            .map(|selection| {
11265                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11266
11267                let breakpoint_position = self
11268                    .breakpoint_at_row(cursor_position.row, window, cx)
11269                    .map(|bp| bp.0)
11270                    .unwrap_or_else(|| {
11271                        snapshot
11272                            .display_snapshot
11273                            .buffer_snapshot()
11274                            .anchor_after(Point::new(cursor_position.row, 0))
11275                    });
11276
11277                let breakpoint = self
11278                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11279                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11280
11281                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11282            })
11283            // 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.
11284            .collect::<HashMap<Anchor, _>>();
11285
11286        cursors.into_iter().collect()
11287    }
11288
11289    pub fn enable_breakpoint(
11290        &mut self,
11291        _: &crate::actions::EnableBreakpoint,
11292        window: &mut Window,
11293        cx: &mut Context<Self>,
11294    ) {
11295        if self.breakpoint_store.is_none() {
11296            return;
11297        }
11298
11299        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11300            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11301                continue;
11302            };
11303            self.edit_breakpoint_at_anchor(
11304                anchor,
11305                breakpoint,
11306                BreakpointEditAction::InvertState,
11307                cx,
11308            );
11309        }
11310    }
11311
11312    pub fn disable_breakpoint(
11313        &mut self,
11314        _: &crate::actions::DisableBreakpoint,
11315        window: &mut Window,
11316        cx: &mut Context<Self>,
11317    ) {
11318        if self.breakpoint_store.is_none() {
11319            return;
11320        }
11321
11322        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11323            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11324                continue;
11325            };
11326            self.edit_breakpoint_at_anchor(
11327                anchor,
11328                breakpoint,
11329                BreakpointEditAction::InvertState,
11330                cx,
11331            );
11332        }
11333    }
11334
11335    pub fn toggle_breakpoint(
11336        &mut self,
11337        _: &crate::actions::ToggleBreakpoint,
11338        window: &mut Window,
11339        cx: &mut Context<Self>,
11340    ) {
11341        if self.breakpoint_store.is_none() {
11342            return;
11343        }
11344
11345        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11346            if let Some(breakpoint) = breakpoint {
11347                self.edit_breakpoint_at_anchor(
11348                    anchor,
11349                    breakpoint,
11350                    BreakpointEditAction::Toggle,
11351                    cx,
11352                );
11353            } else {
11354                self.edit_breakpoint_at_anchor(
11355                    anchor,
11356                    Breakpoint::new_standard(),
11357                    BreakpointEditAction::Toggle,
11358                    cx,
11359                );
11360            }
11361        }
11362    }
11363
11364    pub fn edit_breakpoint_at_anchor(
11365        &mut self,
11366        breakpoint_position: Anchor,
11367        breakpoint: Breakpoint,
11368        edit_action: BreakpointEditAction,
11369        cx: &mut Context<Self>,
11370    ) {
11371        let Some(breakpoint_store) = &self.breakpoint_store else {
11372            return;
11373        };
11374
11375        let Some(buffer) = self
11376            .buffer
11377            .read(cx)
11378            .buffer_for_anchor(breakpoint_position, cx)
11379        else {
11380            return;
11381        };
11382
11383        breakpoint_store.update(cx, |breakpoint_store, cx| {
11384            breakpoint_store.toggle_breakpoint(
11385                buffer,
11386                BreakpointWithPosition {
11387                    position: breakpoint_position.text_anchor,
11388                    bp: breakpoint,
11389                },
11390                edit_action,
11391                cx,
11392            );
11393        });
11394
11395        cx.notify();
11396    }
11397
11398    #[cfg(any(test, feature = "test-support"))]
11399    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11400        self.breakpoint_store.clone()
11401    }
11402
11403    pub fn prepare_restore_change(
11404        &self,
11405        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11406        hunk: &MultiBufferDiffHunk,
11407        cx: &mut App,
11408    ) -> Option<()> {
11409        if hunk.is_created_file() {
11410            return None;
11411        }
11412        let buffer = self.buffer.read(cx);
11413        let diff = buffer.diff_for(hunk.buffer_id)?;
11414        let buffer = buffer.buffer(hunk.buffer_id)?;
11415        let buffer = buffer.read(cx);
11416        let original_text = diff
11417            .read(cx)
11418            .base_text()
11419            .as_rope()
11420            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11421        let buffer_snapshot = buffer.snapshot();
11422        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11423        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11424            probe
11425                .0
11426                .start
11427                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11428                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11429        }) {
11430            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11431            Some(())
11432        } else {
11433            None
11434        }
11435    }
11436
11437    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11438        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11439    }
11440
11441    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11442        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11443    }
11444
11445    fn manipulate_lines<M>(
11446        &mut self,
11447        window: &mut Window,
11448        cx: &mut Context<Self>,
11449        mut manipulate: M,
11450    ) where
11451        M: FnMut(&str) -> LineManipulationResult,
11452    {
11453        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11454
11455        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11456        let buffer = self.buffer.read(cx).snapshot(cx);
11457
11458        let mut edits = Vec::new();
11459
11460        let selections = self.selections.all::<Point>(&display_map);
11461        let mut selections = selections.iter().peekable();
11462        let mut contiguous_row_selections = Vec::new();
11463        let mut new_selections = Vec::new();
11464        let mut added_lines = 0;
11465        let mut removed_lines = 0;
11466
11467        while let Some(selection) = selections.next() {
11468            let (start_row, end_row) = consume_contiguous_rows(
11469                &mut contiguous_row_selections,
11470                selection,
11471                &display_map,
11472                &mut selections,
11473            );
11474
11475            let start_point = Point::new(start_row.0, 0);
11476            let end_point = Point::new(
11477                end_row.previous_row().0,
11478                buffer.line_len(end_row.previous_row()),
11479            );
11480            let text = buffer
11481                .text_for_range(start_point..end_point)
11482                .collect::<String>();
11483
11484            let LineManipulationResult {
11485                new_text,
11486                line_count_before,
11487                line_count_after,
11488            } = manipulate(&text);
11489
11490            edits.push((start_point..end_point, new_text));
11491
11492            // Selections must change based on added and removed line count
11493            let start_row =
11494                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11495            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11496            new_selections.push(Selection {
11497                id: selection.id,
11498                start: start_row,
11499                end: end_row,
11500                goal: SelectionGoal::None,
11501                reversed: selection.reversed,
11502            });
11503
11504            if line_count_after > line_count_before {
11505                added_lines += line_count_after - line_count_before;
11506            } else if line_count_before > line_count_after {
11507                removed_lines += line_count_before - line_count_after;
11508            }
11509        }
11510
11511        self.transact(window, cx, |this, window, cx| {
11512            let buffer = this.buffer.update(cx, |buffer, cx| {
11513                buffer.edit(edits, None, cx);
11514                buffer.snapshot(cx)
11515            });
11516
11517            // Recalculate offsets on newly edited buffer
11518            let new_selections = new_selections
11519                .iter()
11520                .map(|s| {
11521                    let start_point = Point::new(s.start.0, 0);
11522                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11523                    Selection {
11524                        id: s.id,
11525                        start: buffer.point_to_offset(start_point),
11526                        end: buffer.point_to_offset(end_point),
11527                        goal: s.goal,
11528                        reversed: s.reversed,
11529                    }
11530                })
11531                .collect();
11532
11533            this.change_selections(Default::default(), window, cx, |s| {
11534                s.select(new_selections);
11535            });
11536
11537            this.request_autoscroll(Autoscroll::fit(), cx);
11538        });
11539    }
11540
11541    fn manipulate_immutable_lines<Fn>(
11542        &mut self,
11543        window: &mut Window,
11544        cx: &mut Context<Self>,
11545        mut callback: Fn,
11546    ) where
11547        Fn: FnMut(&mut Vec<&str>),
11548    {
11549        self.manipulate_lines(window, cx, |text| {
11550            let mut lines: Vec<&str> = text.split('\n').collect();
11551            let line_count_before = lines.len();
11552
11553            callback(&mut lines);
11554
11555            LineManipulationResult {
11556                new_text: lines.join("\n"),
11557                line_count_before,
11558                line_count_after: lines.len(),
11559            }
11560        });
11561    }
11562
11563    fn manipulate_mutable_lines<Fn>(
11564        &mut self,
11565        window: &mut Window,
11566        cx: &mut Context<Self>,
11567        mut callback: Fn,
11568    ) where
11569        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11570    {
11571        self.manipulate_lines(window, cx, |text| {
11572            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11573            let line_count_before = lines.len();
11574
11575            callback(&mut lines);
11576
11577            LineManipulationResult {
11578                new_text: lines.join("\n"),
11579                line_count_before,
11580                line_count_after: lines.len(),
11581            }
11582        });
11583    }
11584
11585    pub fn convert_indentation_to_spaces(
11586        &mut self,
11587        _: &ConvertIndentationToSpaces,
11588        window: &mut Window,
11589        cx: &mut Context<Self>,
11590    ) {
11591        let settings = self.buffer.read(cx).language_settings(cx);
11592        let tab_size = settings.tab_size.get() as usize;
11593
11594        self.manipulate_mutable_lines(window, cx, |lines| {
11595            // Allocates a reasonably sized scratch buffer once for the whole loop
11596            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11597            // Avoids recomputing spaces that could be inserted many times
11598            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11599                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11600                .collect();
11601
11602            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11603                let mut chars = line.as_ref().chars();
11604                let mut col = 0;
11605                let mut changed = false;
11606
11607                for ch in chars.by_ref() {
11608                    match ch {
11609                        ' ' => {
11610                            reindented_line.push(' ');
11611                            col += 1;
11612                        }
11613                        '\t' => {
11614                            // \t are converted to spaces depending on the current column
11615                            let spaces_len = tab_size - (col % tab_size);
11616                            reindented_line.extend(&space_cache[spaces_len - 1]);
11617                            col += spaces_len;
11618                            changed = true;
11619                        }
11620                        _ => {
11621                            // If we dont append before break, the character is consumed
11622                            reindented_line.push(ch);
11623                            break;
11624                        }
11625                    }
11626                }
11627
11628                if !changed {
11629                    reindented_line.clear();
11630                    continue;
11631                }
11632                // Append the rest of the line and replace old reference with new one
11633                reindented_line.extend(chars);
11634                *line = Cow::Owned(reindented_line.clone());
11635                reindented_line.clear();
11636            }
11637        });
11638    }
11639
11640    pub fn convert_indentation_to_tabs(
11641        &mut self,
11642        _: &ConvertIndentationToTabs,
11643        window: &mut Window,
11644        cx: &mut Context<Self>,
11645    ) {
11646        let settings = self.buffer.read(cx).language_settings(cx);
11647        let tab_size = settings.tab_size.get() as usize;
11648
11649        self.manipulate_mutable_lines(window, cx, |lines| {
11650            // Allocates a reasonably sized buffer once for the whole loop
11651            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11652            // Avoids recomputing spaces that could be inserted many times
11653            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11654                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11655                .collect();
11656
11657            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11658                let mut chars = line.chars();
11659                let mut spaces_count = 0;
11660                let mut first_non_indent_char = None;
11661                let mut changed = false;
11662
11663                for ch in chars.by_ref() {
11664                    match ch {
11665                        ' ' => {
11666                            // Keep track of spaces. Append \t when we reach tab_size
11667                            spaces_count += 1;
11668                            changed = true;
11669                            if spaces_count == tab_size {
11670                                reindented_line.push('\t');
11671                                spaces_count = 0;
11672                            }
11673                        }
11674                        '\t' => {
11675                            reindented_line.push('\t');
11676                            spaces_count = 0;
11677                        }
11678                        _ => {
11679                            // Dont append it yet, we might have remaining spaces
11680                            first_non_indent_char = Some(ch);
11681                            break;
11682                        }
11683                    }
11684                }
11685
11686                if !changed {
11687                    reindented_line.clear();
11688                    continue;
11689                }
11690                // Remaining spaces that didn't make a full tab stop
11691                if spaces_count > 0 {
11692                    reindented_line.extend(&space_cache[spaces_count - 1]);
11693                }
11694                // If we consume an extra character that was not indentation, add it back
11695                if let Some(extra_char) = first_non_indent_char {
11696                    reindented_line.push(extra_char);
11697                }
11698                // Append the rest of the line and replace old reference with new one
11699                reindented_line.extend(chars);
11700                *line = Cow::Owned(reindented_line.clone());
11701                reindented_line.clear();
11702            }
11703        });
11704    }
11705
11706    pub fn convert_to_upper_case(
11707        &mut self,
11708        _: &ConvertToUpperCase,
11709        window: &mut Window,
11710        cx: &mut Context<Self>,
11711    ) {
11712        self.manipulate_text(window, cx, |text| text.to_uppercase())
11713    }
11714
11715    pub fn convert_to_lower_case(
11716        &mut self,
11717        _: &ConvertToLowerCase,
11718        window: &mut Window,
11719        cx: &mut Context<Self>,
11720    ) {
11721        self.manipulate_text(window, cx, |text| text.to_lowercase())
11722    }
11723
11724    pub fn convert_to_title_case(
11725        &mut self,
11726        _: &ConvertToTitleCase,
11727        window: &mut Window,
11728        cx: &mut Context<Self>,
11729    ) {
11730        self.manipulate_text(window, cx, |text| {
11731            text.split('\n')
11732                .map(|line| line.to_case(Case::Title))
11733                .join("\n")
11734        })
11735    }
11736
11737    pub fn convert_to_snake_case(
11738        &mut self,
11739        _: &ConvertToSnakeCase,
11740        window: &mut Window,
11741        cx: &mut Context<Self>,
11742    ) {
11743        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11744    }
11745
11746    pub fn convert_to_kebab_case(
11747        &mut self,
11748        _: &ConvertToKebabCase,
11749        window: &mut Window,
11750        cx: &mut Context<Self>,
11751    ) {
11752        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11753    }
11754
11755    pub fn convert_to_upper_camel_case(
11756        &mut self,
11757        _: &ConvertToUpperCamelCase,
11758        window: &mut Window,
11759        cx: &mut Context<Self>,
11760    ) {
11761        self.manipulate_text(window, cx, |text| {
11762            text.split('\n')
11763                .map(|line| line.to_case(Case::UpperCamel))
11764                .join("\n")
11765        })
11766    }
11767
11768    pub fn convert_to_lower_camel_case(
11769        &mut self,
11770        _: &ConvertToLowerCamelCase,
11771        window: &mut Window,
11772        cx: &mut Context<Self>,
11773    ) {
11774        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11775    }
11776
11777    pub fn convert_to_opposite_case(
11778        &mut self,
11779        _: &ConvertToOppositeCase,
11780        window: &mut Window,
11781        cx: &mut Context<Self>,
11782    ) {
11783        self.manipulate_text(window, cx, |text| {
11784            text.chars()
11785                .fold(String::with_capacity(text.len()), |mut t, c| {
11786                    if c.is_uppercase() {
11787                        t.extend(c.to_lowercase());
11788                    } else {
11789                        t.extend(c.to_uppercase());
11790                    }
11791                    t
11792                })
11793        })
11794    }
11795
11796    pub fn convert_to_sentence_case(
11797        &mut self,
11798        _: &ConvertToSentenceCase,
11799        window: &mut Window,
11800        cx: &mut Context<Self>,
11801    ) {
11802        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11803    }
11804
11805    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11806        self.manipulate_text(window, cx, |text| {
11807            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11808            if has_upper_case_characters {
11809                text.to_lowercase()
11810            } else {
11811                text.to_uppercase()
11812            }
11813        })
11814    }
11815
11816    pub fn convert_to_rot13(
11817        &mut self,
11818        _: &ConvertToRot13,
11819        window: &mut Window,
11820        cx: &mut Context<Self>,
11821    ) {
11822        self.manipulate_text(window, cx, |text| {
11823            text.chars()
11824                .map(|c| match c {
11825                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11826                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11827                    _ => c,
11828                })
11829                .collect()
11830        })
11831    }
11832
11833    pub fn convert_to_rot47(
11834        &mut self,
11835        _: &ConvertToRot47,
11836        window: &mut Window,
11837        cx: &mut Context<Self>,
11838    ) {
11839        self.manipulate_text(window, cx, |text| {
11840            text.chars()
11841                .map(|c| {
11842                    let code_point = c as u32;
11843                    if code_point >= 33 && code_point <= 126 {
11844                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11845                    }
11846                    c
11847                })
11848                .collect()
11849        })
11850    }
11851
11852    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11853    where
11854        Fn: FnMut(&str) -> String,
11855    {
11856        let buffer = self.buffer.read(cx).snapshot(cx);
11857
11858        let mut new_selections = Vec::new();
11859        let mut edits = Vec::new();
11860        let mut selection_adjustment = 0isize;
11861
11862        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11863            let selection_is_empty = selection.is_empty();
11864
11865            let (start, end) = if selection_is_empty {
11866                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11867                (word_range.start, word_range.end)
11868            } else {
11869                (
11870                    buffer.point_to_offset(selection.start),
11871                    buffer.point_to_offset(selection.end),
11872                )
11873            };
11874
11875            let text = buffer.text_for_range(start..end).collect::<String>();
11876            let old_length = text.len() as isize;
11877            let text = callback(&text);
11878
11879            new_selections.push(Selection {
11880                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
11881                end: MultiBufferOffset(
11882                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
11883                ),
11884                goal: SelectionGoal::None,
11885                id: selection.id,
11886                reversed: selection.reversed,
11887            });
11888
11889            selection_adjustment += old_length - text.len() as isize;
11890
11891            edits.push((start..end, text));
11892        }
11893
11894        self.transact(window, cx, |this, window, cx| {
11895            this.buffer.update(cx, |buffer, cx| {
11896                buffer.edit(edits, None, cx);
11897            });
11898
11899            this.change_selections(Default::default(), window, cx, |s| {
11900                s.select(new_selections);
11901            });
11902
11903            this.request_autoscroll(Autoscroll::fit(), cx);
11904        });
11905    }
11906
11907    pub fn move_selection_on_drop(
11908        &mut self,
11909        selection: &Selection<Anchor>,
11910        target: DisplayPoint,
11911        is_cut: bool,
11912        window: &mut Window,
11913        cx: &mut Context<Self>,
11914    ) {
11915        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11916        let buffer = display_map.buffer_snapshot();
11917        let mut edits = Vec::new();
11918        let insert_point = display_map
11919            .clip_point(target, Bias::Left)
11920            .to_point(&display_map);
11921        let text = buffer
11922            .text_for_range(selection.start..selection.end)
11923            .collect::<String>();
11924        if is_cut {
11925            edits.push(((selection.start..selection.end), String::new()));
11926        }
11927        let insert_anchor = buffer.anchor_before(insert_point);
11928        edits.push(((insert_anchor..insert_anchor), text));
11929        let last_edit_start = insert_anchor.bias_left(buffer);
11930        let last_edit_end = insert_anchor.bias_right(buffer);
11931        self.transact(window, cx, |this, window, cx| {
11932            this.buffer.update(cx, |buffer, cx| {
11933                buffer.edit(edits, None, cx);
11934            });
11935            this.change_selections(Default::default(), window, cx, |s| {
11936                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11937            });
11938        });
11939    }
11940
11941    pub fn clear_selection_drag_state(&mut self) {
11942        self.selection_drag_state = SelectionDragState::None;
11943    }
11944
11945    pub fn duplicate(
11946        &mut self,
11947        upwards: bool,
11948        whole_lines: bool,
11949        window: &mut Window,
11950        cx: &mut Context<Self>,
11951    ) {
11952        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11953
11954        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11955        let buffer = display_map.buffer_snapshot();
11956        let selections = self.selections.all::<Point>(&display_map);
11957
11958        let mut edits = Vec::new();
11959        let mut selections_iter = selections.iter().peekable();
11960        while let Some(selection) = selections_iter.next() {
11961            let mut rows = selection.spanned_rows(false, &display_map);
11962            // duplicate line-wise
11963            if whole_lines || selection.start == selection.end {
11964                // Avoid duplicating the same lines twice.
11965                while let Some(next_selection) = selections_iter.peek() {
11966                    let next_rows = next_selection.spanned_rows(false, &display_map);
11967                    if next_rows.start < rows.end {
11968                        rows.end = next_rows.end;
11969                        selections_iter.next().unwrap();
11970                    } else {
11971                        break;
11972                    }
11973                }
11974
11975                // Copy the text from the selected row region and splice it either at the start
11976                // or end of the region.
11977                let start = Point::new(rows.start.0, 0);
11978                let end = Point::new(
11979                    rows.end.previous_row().0,
11980                    buffer.line_len(rows.end.previous_row()),
11981                );
11982
11983                let mut text = buffer.text_for_range(start..end).collect::<String>();
11984
11985                let insert_location = if upwards {
11986                    // When duplicating upward, we need to insert before the current line.
11987                    // If we're on the last line and it doesn't end with a newline,
11988                    // we need to add a newline before the duplicated content.
11989                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11990                        && buffer.max_point().column > 0
11991                        && !text.ends_with('\n');
11992
11993                    if needs_leading_newline {
11994                        text.insert(0, '\n');
11995                        end
11996                    } else {
11997                        text.push('\n');
11998                        Point::new(rows.start.0, 0)
11999                    }
12000                } else {
12001                    text.push('\n');
12002                    start
12003                };
12004                edits.push((insert_location..insert_location, text));
12005            } else {
12006                // duplicate character-wise
12007                let start = selection.start;
12008                let end = selection.end;
12009                let text = buffer.text_for_range(start..end).collect::<String>();
12010                edits.push((selection.end..selection.end, text));
12011            }
12012        }
12013
12014        self.transact(window, cx, |this, window, cx| {
12015            this.buffer.update(cx, |buffer, cx| {
12016                buffer.edit(edits, None, cx);
12017            });
12018
12019            // When duplicating upward with whole lines, move the cursor to the duplicated line
12020            if upwards && whole_lines {
12021                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12022
12023                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12024                    let mut new_ranges = Vec::new();
12025                    let selections = s.all::<Point>(&display_map);
12026                    let mut selections_iter = selections.iter().peekable();
12027
12028                    while let Some(first_selection) = selections_iter.next() {
12029                        // Group contiguous selections together to find the total row span
12030                        let mut group_selections = vec![first_selection];
12031                        let mut rows = first_selection.spanned_rows(false, &display_map);
12032
12033                        while let Some(next_selection) = selections_iter.peek() {
12034                            let next_rows = next_selection.spanned_rows(false, &display_map);
12035                            if next_rows.start < rows.end {
12036                                rows.end = next_rows.end;
12037                                group_selections.push(selections_iter.next().unwrap());
12038                            } else {
12039                                break;
12040                            }
12041                        }
12042
12043                        let row_count = rows.end.0 - rows.start.0;
12044
12045                        // Move all selections in this group up by the total number of duplicated rows
12046                        for selection in group_selections {
12047                            let new_start = Point::new(
12048                                selection.start.row.saturating_sub(row_count),
12049                                selection.start.column,
12050                            );
12051
12052                            let new_end = Point::new(
12053                                selection.end.row.saturating_sub(row_count),
12054                                selection.end.column,
12055                            );
12056
12057                            new_ranges.push(new_start..new_end);
12058                        }
12059                    }
12060
12061                    s.select_ranges(new_ranges);
12062                });
12063            }
12064
12065            this.request_autoscroll(Autoscroll::fit(), cx);
12066        });
12067    }
12068
12069    pub fn duplicate_line_up(
12070        &mut self,
12071        _: &DuplicateLineUp,
12072        window: &mut Window,
12073        cx: &mut Context<Self>,
12074    ) {
12075        self.duplicate(true, true, window, cx);
12076    }
12077
12078    pub fn duplicate_line_down(
12079        &mut self,
12080        _: &DuplicateLineDown,
12081        window: &mut Window,
12082        cx: &mut Context<Self>,
12083    ) {
12084        self.duplicate(false, true, window, cx);
12085    }
12086
12087    pub fn duplicate_selection(
12088        &mut self,
12089        _: &DuplicateSelection,
12090        window: &mut Window,
12091        cx: &mut Context<Self>,
12092    ) {
12093        self.duplicate(false, false, window, cx);
12094    }
12095
12096    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12097        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12098        if self.mode.is_single_line() {
12099            cx.propagate();
12100            return;
12101        }
12102
12103        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12104        let buffer = self.buffer.read(cx).snapshot(cx);
12105
12106        let mut edits = Vec::new();
12107        let mut unfold_ranges = Vec::new();
12108        let mut refold_creases = Vec::new();
12109
12110        let selections = self.selections.all::<Point>(&display_map);
12111        let mut selections = selections.iter().peekable();
12112        let mut contiguous_row_selections = Vec::new();
12113        let mut new_selections = Vec::new();
12114
12115        while let Some(selection) = selections.next() {
12116            // Find all the selections that span a contiguous row range
12117            let (start_row, end_row) = consume_contiguous_rows(
12118                &mut contiguous_row_selections,
12119                selection,
12120                &display_map,
12121                &mut selections,
12122            );
12123
12124            // Move the text spanned by the row range to be before the line preceding the row range
12125            if start_row.0 > 0 {
12126                let range_to_move = Point::new(
12127                    start_row.previous_row().0,
12128                    buffer.line_len(start_row.previous_row()),
12129                )
12130                    ..Point::new(
12131                        end_row.previous_row().0,
12132                        buffer.line_len(end_row.previous_row()),
12133                    );
12134                let insertion_point = display_map
12135                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12136                    .0;
12137
12138                // Don't move lines across excerpts
12139                if buffer
12140                    .excerpt_containing(insertion_point..range_to_move.end)
12141                    .is_some()
12142                {
12143                    let text = buffer
12144                        .text_for_range(range_to_move.clone())
12145                        .flat_map(|s| s.chars())
12146                        .skip(1)
12147                        .chain(['\n'])
12148                        .collect::<String>();
12149
12150                    edits.push((
12151                        buffer.anchor_after(range_to_move.start)
12152                            ..buffer.anchor_before(range_to_move.end),
12153                        String::new(),
12154                    ));
12155                    let insertion_anchor = buffer.anchor_after(insertion_point);
12156                    edits.push((insertion_anchor..insertion_anchor, text));
12157
12158                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12159
12160                    // Move selections up
12161                    new_selections.extend(contiguous_row_selections.drain(..).map(
12162                        |mut selection| {
12163                            selection.start.row -= row_delta;
12164                            selection.end.row -= row_delta;
12165                            selection
12166                        },
12167                    ));
12168
12169                    // Move folds up
12170                    unfold_ranges.push(range_to_move.clone());
12171                    for fold in display_map.folds_in_range(
12172                        buffer.anchor_before(range_to_move.start)
12173                            ..buffer.anchor_after(range_to_move.end),
12174                    ) {
12175                        let mut start = fold.range.start.to_point(&buffer);
12176                        let mut end = fold.range.end.to_point(&buffer);
12177                        start.row -= row_delta;
12178                        end.row -= row_delta;
12179                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12180                    }
12181                }
12182            }
12183
12184            // If we didn't move line(s), preserve the existing selections
12185            new_selections.append(&mut contiguous_row_selections);
12186        }
12187
12188        self.transact(window, cx, |this, window, cx| {
12189            this.unfold_ranges(&unfold_ranges, true, true, cx);
12190            this.buffer.update(cx, |buffer, cx| {
12191                for (range, text) in edits {
12192                    buffer.edit([(range, text)], None, cx);
12193                }
12194            });
12195            this.fold_creases(refold_creases, true, window, cx);
12196            this.change_selections(Default::default(), window, cx, |s| {
12197                s.select(new_selections);
12198            })
12199        });
12200    }
12201
12202    pub fn move_line_down(
12203        &mut self,
12204        _: &MoveLineDown,
12205        window: &mut Window,
12206        cx: &mut Context<Self>,
12207    ) {
12208        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12209        if self.mode.is_single_line() {
12210            cx.propagate();
12211            return;
12212        }
12213
12214        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12215        let buffer = self.buffer.read(cx).snapshot(cx);
12216
12217        let mut edits = Vec::new();
12218        let mut unfold_ranges = Vec::new();
12219        let mut refold_creases = Vec::new();
12220
12221        let selections = self.selections.all::<Point>(&display_map);
12222        let mut selections = selections.iter().peekable();
12223        let mut contiguous_row_selections = Vec::new();
12224        let mut new_selections = Vec::new();
12225
12226        while let Some(selection) = selections.next() {
12227            // Find all the selections that span a contiguous row range
12228            let (start_row, end_row) = consume_contiguous_rows(
12229                &mut contiguous_row_selections,
12230                selection,
12231                &display_map,
12232                &mut selections,
12233            );
12234
12235            // Move the text spanned by the row range to be after the last line of the row range
12236            if end_row.0 <= buffer.max_point().row {
12237                let range_to_move =
12238                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12239                let insertion_point = display_map
12240                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12241                    .0;
12242
12243                // Don't move lines across excerpt boundaries
12244                if buffer
12245                    .excerpt_containing(range_to_move.start..insertion_point)
12246                    .is_some()
12247                {
12248                    let mut text = String::from("\n");
12249                    text.extend(buffer.text_for_range(range_to_move.clone()));
12250                    text.pop(); // Drop trailing newline
12251                    edits.push((
12252                        buffer.anchor_after(range_to_move.start)
12253                            ..buffer.anchor_before(range_to_move.end),
12254                        String::new(),
12255                    ));
12256                    let insertion_anchor = buffer.anchor_after(insertion_point);
12257                    edits.push((insertion_anchor..insertion_anchor, text));
12258
12259                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12260
12261                    // Move selections down
12262                    new_selections.extend(contiguous_row_selections.drain(..).map(
12263                        |mut selection| {
12264                            selection.start.row += row_delta;
12265                            selection.end.row += row_delta;
12266                            selection
12267                        },
12268                    ));
12269
12270                    // Move folds down
12271                    unfold_ranges.push(range_to_move.clone());
12272                    for fold in display_map.folds_in_range(
12273                        buffer.anchor_before(range_to_move.start)
12274                            ..buffer.anchor_after(range_to_move.end),
12275                    ) {
12276                        let mut start = fold.range.start.to_point(&buffer);
12277                        let mut end = fold.range.end.to_point(&buffer);
12278                        start.row += row_delta;
12279                        end.row += row_delta;
12280                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12281                    }
12282                }
12283            }
12284
12285            // If we didn't move line(s), preserve the existing selections
12286            new_selections.append(&mut contiguous_row_selections);
12287        }
12288
12289        self.transact(window, cx, |this, window, cx| {
12290            this.unfold_ranges(&unfold_ranges, true, true, cx);
12291            this.buffer.update(cx, |buffer, cx| {
12292                for (range, text) in edits {
12293                    buffer.edit([(range, text)], None, cx);
12294                }
12295            });
12296            this.fold_creases(refold_creases, true, window, cx);
12297            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12298        });
12299    }
12300
12301    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12302        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12303        let text_layout_details = &self.text_layout_details(window);
12304        self.transact(window, cx, |this, window, cx| {
12305            let edits = this.change_selections(Default::default(), window, cx, |s| {
12306                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12307                s.move_with(|display_map, selection| {
12308                    if !selection.is_empty() {
12309                        return;
12310                    }
12311
12312                    let mut head = selection.head();
12313                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12314                    if head.column() == display_map.line_len(head.row()) {
12315                        transpose_offset = display_map
12316                            .buffer_snapshot()
12317                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12318                    }
12319
12320                    if transpose_offset == MultiBufferOffset(0) {
12321                        return;
12322                    }
12323
12324                    *head.column_mut() += 1;
12325                    head = display_map.clip_point(head, Bias::Right);
12326                    let goal = SelectionGoal::HorizontalPosition(
12327                        display_map
12328                            .x_for_display_point(head, text_layout_details)
12329                            .into(),
12330                    );
12331                    selection.collapse_to(head, goal);
12332
12333                    let transpose_start = display_map
12334                        .buffer_snapshot()
12335                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12336                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12337                        let transpose_end = display_map
12338                            .buffer_snapshot()
12339                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12340                        if let Some(ch) = display_map
12341                            .buffer_snapshot()
12342                            .chars_at(transpose_start)
12343                            .next()
12344                        {
12345                            edits.push((transpose_start..transpose_offset, String::new()));
12346                            edits.push((transpose_end..transpose_end, ch.to_string()));
12347                        }
12348                    }
12349                });
12350                edits
12351            });
12352            this.buffer
12353                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12354            let selections = this
12355                .selections
12356                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12357            this.change_selections(Default::default(), window, cx, |s| {
12358                s.select(selections);
12359            });
12360        });
12361    }
12362
12363    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12364        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12365        if self.mode.is_single_line() {
12366            cx.propagate();
12367            return;
12368        }
12369
12370        self.rewrap_impl(RewrapOptions::default(), cx)
12371    }
12372
12373    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12374        let buffer = self.buffer.read(cx).snapshot(cx);
12375        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12376
12377        #[derive(Clone, Debug, PartialEq)]
12378        enum CommentFormat {
12379            /// single line comment, with prefix for line
12380            Line(String),
12381            /// single line within a block comment, with prefix for line
12382            BlockLine(String),
12383            /// a single line of a block comment that includes the initial delimiter
12384            BlockCommentWithStart(BlockCommentConfig),
12385            /// a single line of a block comment that includes the ending delimiter
12386            BlockCommentWithEnd(BlockCommentConfig),
12387        }
12388
12389        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12390        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12391            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12392                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12393                .peekable();
12394
12395            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12396                row
12397            } else {
12398                return Vec::new();
12399            };
12400
12401            let language_settings = buffer.language_settings_at(selection.head(), cx);
12402            let language_scope = buffer.language_scope_at(selection.head());
12403
12404            let indent_and_prefix_for_row =
12405                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12406                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12407                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12408                        &language_scope
12409                    {
12410                        let indent_end = Point::new(row, indent.len);
12411                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12412                        let line_text_after_indent = buffer
12413                            .text_for_range(indent_end..line_end)
12414                            .collect::<String>();
12415
12416                        let is_within_comment_override = buffer
12417                            .language_scope_at(indent_end)
12418                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12419                        let comment_delimiters = if is_within_comment_override {
12420                            // we are within a comment syntax node, but we don't
12421                            // yet know what kind of comment: block, doc or line
12422                            match (
12423                                language_scope.documentation_comment(),
12424                                language_scope.block_comment(),
12425                            ) {
12426                                (Some(config), _) | (_, Some(config))
12427                                    if buffer.contains_str_at(indent_end, &config.start) =>
12428                                {
12429                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12430                                }
12431                                (Some(config), _) | (_, Some(config))
12432                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12433                                {
12434                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12435                                }
12436                                (Some(config), _) | (_, Some(config))
12437                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12438                                {
12439                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12440                                }
12441                                (_, _) => language_scope
12442                                    .line_comment_prefixes()
12443                                    .iter()
12444                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12445                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12446                            }
12447                        } else {
12448                            // we not in an overridden comment node, but we may
12449                            // be within a non-overridden line comment node
12450                            language_scope
12451                                .line_comment_prefixes()
12452                                .iter()
12453                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12454                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12455                        };
12456
12457                        let rewrap_prefix = language_scope
12458                            .rewrap_prefixes()
12459                            .iter()
12460                            .find_map(|prefix_regex| {
12461                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12462                                    if mat.start() == 0 {
12463                                        Some(mat.as_str().to_string())
12464                                    } else {
12465                                        None
12466                                    }
12467                                })
12468                            })
12469                            .flatten();
12470                        (comment_delimiters, rewrap_prefix)
12471                    } else {
12472                        (None, None)
12473                    };
12474                    (indent, comment_prefix, rewrap_prefix)
12475                };
12476
12477            let mut ranges = Vec::new();
12478            let from_empty_selection = selection.is_empty();
12479
12480            let mut current_range_start = first_row;
12481            let mut prev_row = first_row;
12482            let (
12483                mut current_range_indent,
12484                mut current_range_comment_delimiters,
12485                mut current_range_rewrap_prefix,
12486            ) = indent_and_prefix_for_row(first_row);
12487
12488            for row in non_blank_rows_iter.skip(1) {
12489                let has_paragraph_break = row > prev_row + 1;
12490
12491                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12492                    indent_and_prefix_for_row(row);
12493
12494                let has_indent_change = row_indent != current_range_indent;
12495                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12496
12497                let has_boundary_change = has_comment_change
12498                    || row_rewrap_prefix.is_some()
12499                    || (has_indent_change && current_range_comment_delimiters.is_some());
12500
12501                if has_paragraph_break || has_boundary_change {
12502                    ranges.push((
12503                        language_settings.clone(),
12504                        Point::new(current_range_start, 0)
12505                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12506                        current_range_indent,
12507                        current_range_comment_delimiters.clone(),
12508                        current_range_rewrap_prefix.clone(),
12509                        from_empty_selection,
12510                    ));
12511                    current_range_start = row;
12512                    current_range_indent = row_indent;
12513                    current_range_comment_delimiters = row_comment_delimiters;
12514                    current_range_rewrap_prefix = row_rewrap_prefix;
12515                }
12516                prev_row = row;
12517            }
12518
12519            ranges.push((
12520                language_settings.clone(),
12521                Point::new(current_range_start, 0)
12522                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12523                current_range_indent,
12524                current_range_comment_delimiters,
12525                current_range_rewrap_prefix,
12526                from_empty_selection,
12527            ));
12528
12529            ranges
12530        });
12531
12532        let mut edits = Vec::new();
12533        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12534
12535        for (
12536            language_settings,
12537            wrap_range,
12538            mut indent_size,
12539            comment_prefix,
12540            rewrap_prefix,
12541            from_empty_selection,
12542        ) in wrap_ranges
12543        {
12544            let mut start_row = wrap_range.start.row;
12545            let mut end_row = wrap_range.end.row;
12546
12547            // Skip selections that overlap with a range that has already been rewrapped.
12548            let selection_range = start_row..end_row;
12549            if rewrapped_row_ranges
12550                .iter()
12551                .any(|range| range.overlaps(&selection_range))
12552            {
12553                continue;
12554            }
12555
12556            let tab_size = language_settings.tab_size;
12557
12558            let (line_prefix, inside_comment) = match &comment_prefix {
12559                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12560                    (Some(prefix.as_str()), true)
12561                }
12562                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12563                    (Some(prefix.as_ref()), true)
12564                }
12565                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12566                    start: _,
12567                    end: _,
12568                    prefix,
12569                    tab_size,
12570                })) => {
12571                    indent_size.len += tab_size;
12572                    (Some(prefix.as_ref()), true)
12573                }
12574                None => (None, false),
12575            };
12576            let indent_prefix = indent_size.chars().collect::<String>();
12577            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12578
12579            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12580                RewrapBehavior::InComments => inside_comment,
12581                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12582                RewrapBehavior::Anywhere => true,
12583            };
12584
12585            let should_rewrap = options.override_language_settings
12586                || allow_rewrap_based_on_language
12587                || self.hard_wrap.is_some();
12588            if !should_rewrap {
12589                continue;
12590            }
12591
12592            if from_empty_selection {
12593                'expand_upwards: while start_row > 0 {
12594                    let prev_row = start_row - 1;
12595                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12596                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12597                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12598                    {
12599                        start_row = prev_row;
12600                    } else {
12601                        break 'expand_upwards;
12602                    }
12603                }
12604
12605                'expand_downwards: while end_row < buffer.max_point().row {
12606                    let next_row = end_row + 1;
12607                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12608                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12609                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12610                    {
12611                        end_row = next_row;
12612                    } else {
12613                        break 'expand_downwards;
12614                    }
12615                }
12616            }
12617
12618            let start = Point::new(start_row, 0);
12619            let start_offset = ToOffset::to_offset(&start, &buffer);
12620            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12621            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12622            let mut first_line_delimiter = None;
12623            let mut last_line_delimiter = None;
12624            let Some(lines_without_prefixes) = selection_text
12625                .lines()
12626                .enumerate()
12627                .map(|(ix, line)| {
12628                    let line_trimmed = line.trim_start();
12629                    if rewrap_prefix.is_some() && ix > 0 {
12630                        Ok(line_trimmed)
12631                    } else if let Some(
12632                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12633                            start,
12634                            prefix,
12635                            end,
12636                            tab_size,
12637                        })
12638                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12639                            start,
12640                            prefix,
12641                            end,
12642                            tab_size,
12643                        }),
12644                    ) = &comment_prefix
12645                    {
12646                        let line_trimmed = line_trimmed
12647                            .strip_prefix(start.as_ref())
12648                            .map(|s| {
12649                                let mut indent_size = indent_size;
12650                                indent_size.len -= tab_size;
12651                                let indent_prefix: String = indent_size.chars().collect();
12652                                first_line_delimiter = Some((indent_prefix, start));
12653                                s.trim_start()
12654                            })
12655                            .unwrap_or(line_trimmed);
12656                        let line_trimmed = line_trimmed
12657                            .strip_suffix(end.as_ref())
12658                            .map(|s| {
12659                                last_line_delimiter = Some(end);
12660                                s.trim_end()
12661                            })
12662                            .unwrap_or(line_trimmed);
12663                        let line_trimmed = line_trimmed
12664                            .strip_prefix(prefix.as_ref())
12665                            .unwrap_or(line_trimmed);
12666                        Ok(line_trimmed)
12667                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12668                        line_trimmed.strip_prefix(prefix).with_context(|| {
12669                            format!("line did not start with prefix {prefix:?}: {line:?}")
12670                        })
12671                    } else {
12672                        line_trimmed
12673                            .strip_prefix(&line_prefix.trim_start())
12674                            .with_context(|| {
12675                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12676                            })
12677                    }
12678                })
12679                .collect::<Result<Vec<_>, _>>()
12680                .log_err()
12681            else {
12682                continue;
12683            };
12684
12685            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12686                buffer
12687                    .language_settings_at(Point::new(start_row, 0), cx)
12688                    .preferred_line_length as usize
12689            });
12690
12691            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12692                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12693            } else {
12694                line_prefix.clone()
12695            };
12696
12697            let wrapped_text = {
12698                let mut wrapped_text = wrap_with_prefix(
12699                    line_prefix,
12700                    subsequent_lines_prefix,
12701                    lines_without_prefixes.join("\n"),
12702                    wrap_column,
12703                    tab_size,
12704                    options.preserve_existing_whitespace,
12705                );
12706
12707                if let Some((indent, delimiter)) = first_line_delimiter {
12708                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12709                }
12710                if let Some(last_line) = last_line_delimiter {
12711                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12712                }
12713
12714                wrapped_text
12715            };
12716
12717            // TODO: should always use char-based diff while still supporting cursor behavior that
12718            // matches vim.
12719            let mut diff_options = DiffOptions::default();
12720            if options.override_language_settings {
12721                diff_options.max_word_diff_len = 0;
12722                diff_options.max_word_diff_line_count = 0;
12723            } else {
12724                diff_options.max_word_diff_len = usize::MAX;
12725                diff_options.max_word_diff_line_count = usize::MAX;
12726            }
12727
12728            for (old_range, new_text) in
12729                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12730            {
12731                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12732                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12733                edits.push((edit_start..edit_end, new_text));
12734            }
12735
12736            rewrapped_row_ranges.push(start_row..=end_row);
12737        }
12738
12739        self.buffer
12740            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12741    }
12742
12743    pub fn cut_common(
12744        &mut self,
12745        cut_no_selection_line: bool,
12746        window: &mut Window,
12747        cx: &mut Context<Self>,
12748    ) -> ClipboardItem {
12749        let mut text = String::new();
12750        let buffer = self.buffer.read(cx).snapshot(cx);
12751        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12752        let mut clipboard_selections = Vec::with_capacity(selections.len());
12753        {
12754            let max_point = buffer.max_point();
12755            let mut is_first = true;
12756            let mut prev_selection_was_entire_line = false;
12757            for selection in &mut selections {
12758                let is_entire_line =
12759                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12760                if is_entire_line {
12761                    selection.start = Point::new(selection.start.row, 0);
12762                    if !selection.is_empty() && selection.end.column == 0 {
12763                        selection.end = cmp::min(max_point, selection.end);
12764                    } else {
12765                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12766                    }
12767                    selection.goal = SelectionGoal::None;
12768                }
12769                if is_first {
12770                    is_first = false;
12771                } else if !prev_selection_was_entire_line {
12772                    text += "\n";
12773                }
12774                prev_selection_was_entire_line = is_entire_line;
12775                let mut len = 0;
12776                for chunk in buffer.text_for_range(selection.start..selection.end) {
12777                    text.push_str(chunk);
12778                    len += chunk.len();
12779                }
12780                clipboard_selections.push(ClipboardSelection {
12781                    len,
12782                    is_entire_line,
12783                    first_line_indent: buffer
12784                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12785                        .len,
12786                });
12787            }
12788        }
12789
12790        self.transact(window, cx, |this, window, cx| {
12791            this.change_selections(Default::default(), window, cx, |s| {
12792                s.select(selections);
12793            });
12794            this.insert("", window, cx);
12795        });
12796        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12797    }
12798
12799    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12800        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12801        let item = self.cut_common(true, window, cx);
12802        cx.write_to_clipboard(item);
12803    }
12804
12805    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12806        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12807        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12808            s.move_with(|snapshot, sel| {
12809                if sel.is_empty() {
12810                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12811                }
12812                if sel.is_empty() {
12813                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12814                }
12815            });
12816        });
12817        let item = self.cut_common(false, window, cx);
12818        cx.set_global(KillRing(item))
12819    }
12820
12821    pub fn kill_ring_yank(
12822        &mut self,
12823        _: &KillRingYank,
12824        window: &mut Window,
12825        cx: &mut Context<Self>,
12826    ) {
12827        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12828        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12829            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12830                (kill_ring.text().to_string(), kill_ring.metadata_json())
12831            } else {
12832                return;
12833            }
12834        } else {
12835            return;
12836        };
12837        self.do_paste(&text, metadata, false, window, cx);
12838    }
12839
12840    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12841        self.do_copy(true, cx);
12842    }
12843
12844    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12845        self.do_copy(false, cx);
12846    }
12847
12848    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12849        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12850        let buffer = self.buffer.read(cx).read(cx);
12851        let mut text = String::new();
12852
12853        let mut clipboard_selections = Vec::with_capacity(selections.len());
12854        {
12855            let max_point = buffer.max_point();
12856            let mut is_first = true;
12857            let mut prev_selection_was_entire_line = false;
12858            for selection in &selections {
12859                let mut start = selection.start;
12860                let mut end = selection.end;
12861                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12862                let mut add_trailing_newline = false;
12863                if is_entire_line {
12864                    start = Point::new(start.row, 0);
12865                    let next_line_start = Point::new(end.row + 1, 0);
12866                    if next_line_start <= max_point {
12867                        end = next_line_start;
12868                    } else {
12869                        // We're on the last line without a trailing newline.
12870                        // Copy to the end of the line and add a newline afterwards.
12871                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12872                        add_trailing_newline = true;
12873                    }
12874                }
12875
12876                let mut trimmed_selections = Vec::new();
12877                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12878                    let row = MultiBufferRow(start.row);
12879                    let first_indent = buffer.indent_size_for_line(row);
12880                    if first_indent.len == 0 || start.column > first_indent.len {
12881                        trimmed_selections.push(start..end);
12882                    } else {
12883                        trimmed_selections.push(
12884                            Point::new(row.0, first_indent.len)
12885                                ..Point::new(row.0, buffer.line_len(row)),
12886                        );
12887                        for row in start.row + 1..=end.row {
12888                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12889                            if row == end.row {
12890                                line_len = end.column;
12891                            }
12892                            if line_len == 0 {
12893                                trimmed_selections
12894                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12895                                continue;
12896                            }
12897                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12898                            if row_indent_size.len >= first_indent.len {
12899                                trimmed_selections.push(
12900                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12901                                );
12902                            } else {
12903                                trimmed_selections.clear();
12904                                trimmed_selections.push(start..end);
12905                                break;
12906                            }
12907                        }
12908                    }
12909                } else {
12910                    trimmed_selections.push(start..end);
12911                }
12912
12913                for trimmed_range in trimmed_selections {
12914                    if is_first {
12915                        is_first = false;
12916                    } else if !prev_selection_was_entire_line {
12917                        text += "\n";
12918                    }
12919                    prev_selection_was_entire_line = is_entire_line;
12920                    let mut len = 0;
12921                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12922                        text.push_str(chunk);
12923                        len += chunk.len();
12924                    }
12925                    if add_trailing_newline {
12926                        text.push('\n');
12927                        len += 1;
12928                    }
12929                    clipboard_selections.push(ClipboardSelection {
12930                        len,
12931                        is_entire_line,
12932                        first_line_indent: buffer
12933                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12934                            .len,
12935                    });
12936                }
12937            }
12938        }
12939
12940        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12941            text,
12942            clipboard_selections,
12943        ));
12944    }
12945
12946    pub fn do_paste(
12947        &mut self,
12948        text: &String,
12949        clipboard_selections: Option<Vec<ClipboardSelection>>,
12950        handle_entire_lines: bool,
12951        window: &mut Window,
12952        cx: &mut Context<Self>,
12953    ) {
12954        if self.read_only(cx) {
12955            return;
12956        }
12957
12958        let clipboard_text = Cow::Borrowed(text.as_str());
12959
12960        self.transact(window, cx, |this, window, cx| {
12961            let had_active_edit_prediction = this.has_active_edit_prediction();
12962            let display_map = this.display_snapshot(cx);
12963            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
12964            let cursor_offset = this
12965                .selections
12966                .last::<MultiBufferOffset>(&display_map)
12967                .head();
12968
12969            if let Some(mut clipboard_selections) = clipboard_selections {
12970                let all_selections_were_entire_line =
12971                    clipboard_selections.iter().all(|s| s.is_entire_line);
12972                let first_selection_indent_column =
12973                    clipboard_selections.first().map(|s| s.first_line_indent);
12974                if clipboard_selections.len() != old_selections.len() {
12975                    clipboard_selections.drain(..);
12976                }
12977                let mut auto_indent_on_paste = true;
12978
12979                this.buffer.update(cx, |buffer, cx| {
12980                    let snapshot = buffer.read(cx);
12981                    auto_indent_on_paste = snapshot
12982                        .language_settings_at(cursor_offset, cx)
12983                        .auto_indent_on_paste;
12984
12985                    let mut start_offset = 0;
12986                    let mut edits = Vec::new();
12987                    let mut original_indent_columns = Vec::new();
12988                    for (ix, selection) in old_selections.iter().enumerate() {
12989                        let to_insert;
12990                        let entire_line;
12991                        let original_indent_column;
12992                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12993                            let end_offset = start_offset + clipboard_selection.len;
12994                            to_insert = &clipboard_text[start_offset..end_offset];
12995                            entire_line = clipboard_selection.is_entire_line;
12996                            start_offset = if entire_line {
12997                                end_offset
12998                            } else {
12999                                end_offset + 1
13000                            };
13001                            original_indent_column = Some(clipboard_selection.first_line_indent);
13002                        } else {
13003                            to_insert = &*clipboard_text;
13004                            entire_line = all_selections_were_entire_line;
13005                            original_indent_column = first_selection_indent_column
13006                        }
13007
13008                        let (range, to_insert) =
13009                            if selection.is_empty() && handle_entire_lines && entire_line {
13010                                // If the corresponding selection was empty when this slice of the
13011                                // clipboard text was written, then the entire line containing the
13012                                // selection was copied. If this selection is also currently empty,
13013                                // then paste the line before the current line of the buffer.
13014                                let column = selection.start.to_point(&snapshot).column as usize;
13015                                let line_start = selection.start - column;
13016                                (line_start..line_start, Cow::Borrowed(to_insert))
13017                            } else {
13018                                let language = snapshot.language_at(selection.head());
13019                                let range = selection.range();
13020                                if let Some(language) = language
13021                                    && language.name() == "Markdown".into()
13022                                {
13023                                    edit_for_markdown_paste(
13024                                        &snapshot,
13025                                        range,
13026                                        to_insert,
13027                                        url::Url::parse(to_insert).ok(),
13028                                    )
13029                                } else {
13030                                    (range, Cow::Borrowed(to_insert))
13031                                }
13032                            };
13033
13034                        edits.push((range, to_insert));
13035                        original_indent_columns.push(original_indent_column);
13036                    }
13037                    drop(snapshot);
13038
13039                    buffer.edit(
13040                        edits,
13041                        if auto_indent_on_paste {
13042                            Some(AutoindentMode::Block {
13043                                original_indent_columns,
13044                            })
13045                        } else {
13046                            None
13047                        },
13048                        cx,
13049                    );
13050                });
13051
13052                let selections = this
13053                    .selections
13054                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13055                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13056            } else {
13057                let url = url::Url::parse(&clipboard_text).ok();
13058
13059                let auto_indent_mode = if !clipboard_text.is_empty() {
13060                    Some(AutoindentMode::Block {
13061                        original_indent_columns: Vec::new(),
13062                    })
13063                } else {
13064                    None
13065                };
13066
13067                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13068                    let snapshot = buffer.snapshot(cx);
13069
13070                    let anchors = old_selections
13071                        .iter()
13072                        .map(|s| {
13073                            let anchor = snapshot.anchor_after(s.head());
13074                            s.map(|_| anchor)
13075                        })
13076                        .collect::<Vec<_>>();
13077
13078                    let mut edits = Vec::new();
13079
13080                    for selection in old_selections.iter() {
13081                        let language = snapshot.language_at(selection.head());
13082                        let range = selection.range();
13083
13084                        let (edit_range, edit_text) = if let Some(language) = language
13085                            && language.name() == "Markdown".into()
13086                        {
13087                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13088                        } else {
13089                            (range, clipboard_text.clone())
13090                        };
13091
13092                        edits.push((edit_range, edit_text));
13093                    }
13094
13095                    drop(snapshot);
13096                    buffer.edit(edits, auto_indent_mode, cx);
13097
13098                    anchors
13099                });
13100
13101                this.change_selections(Default::default(), window, cx, |s| {
13102                    s.select_anchors(selection_anchors);
13103                });
13104            }
13105
13106            //   🤔                 |    ..     | show_in_menu |
13107            // | ..                  |   true        true
13108            // | had_edit_prediction |   false       true
13109
13110            let trigger_in_words =
13111                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13112
13113            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13114        });
13115    }
13116
13117    pub fn diff_clipboard_with_selection(
13118        &mut self,
13119        _: &DiffClipboardWithSelection,
13120        window: &mut Window,
13121        cx: &mut Context<Self>,
13122    ) {
13123        let selections = self
13124            .selections
13125            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13126
13127        if selections.is_empty() {
13128            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13129            return;
13130        };
13131
13132        let clipboard_text = match cx.read_from_clipboard() {
13133            Some(item) => match item.entries().first() {
13134                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13135                _ => None,
13136            },
13137            None => None,
13138        };
13139
13140        let Some(clipboard_text) = clipboard_text else {
13141            log::warn!("Clipboard doesn't contain text.");
13142            return;
13143        };
13144
13145        window.dispatch_action(
13146            Box::new(DiffClipboardWithSelectionData {
13147                clipboard_text,
13148                editor: cx.entity(),
13149            }),
13150            cx,
13151        );
13152    }
13153
13154    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13155        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13156        if let Some(item) = cx.read_from_clipboard() {
13157            let entries = item.entries();
13158
13159            match entries.first() {
13160                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13161                // of all the pasted entries.
13162                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13163                    .do_paste(
13164                        clipboard_string.text(),
13165                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13166                        true,
13167                        window,
13168                        cx,
13169                    ),
13170                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13171            }
13172        }
13173    }
13174
13175    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13176        if self.read_only(cx) {
13177            return;
13178        }
13179
13180        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13181
13182        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13183            if let Some((selections, _)) =
13184                self.selection_history.transaction(transaction_id).cloned()
13185            {
13186                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13187                    s.select_anchors(selections.to_vec());
13188                });
13189            } else {
13190                log::error!(
13191                    "No entry in selection_history found for undo. \
13192                     This may correspond to a bug where undo does not update the selection. \
13193                     If this is occurring, please add details to \
13194                     https://github.com/zed-industries/zed/issues/22692"
13195                );
13196            }
13197            self.request_autoscroll(Autoscroll::fit(), cx);
13198            self.unmark_text(window, cx);
13199            self.refresh_edit_prediction(true, false, window, cx);
13200            cx.emit(EditorEvent::Edited { transaction_id });
13201            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13202        }
13203    }
13204
13205    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13206        if self.read_only(cx) {
13207            return;
13208        }
13209
13210        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13211
13212        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13213            if let Some((_, Some(selections))) =
13214                self.selection_history.transaction(transaction_id).cloned()
13215            {
13216                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13217                    s.select_anchors(selections.to_vec());
13218                });
13219            } else {
13220                log::error!(
13221                    "No entry in selection_history found for redo. \
13222                     This may correspond to a bug where undo does not update the selection. \
13223                     If this is occurring, please add details to \
13224                     https://github.com/zed-industries/zed/issues/22692"
13225                );
13226            }
13227            self.request_autoscroll(Autoscroll::fit(), cx);
13228            self.unmark_text(window, cx);
13229            self.refresh_edit_prediction(true, false, window, cx);
13230            cx.emit(EditorEvent::Edited { transaction_id });
13231        }
13232    }
13233
13234    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13235        self.buffer
13236            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13237    }
13238
13239    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13240        self.buffer
13241            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13242    }
13243
13244    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13245        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13246        self.change_selections(Default::default(), window, cx, |s| {
13247            s.move_with(|map, selection| {
13248                let cursor = if selection.is_empty() {
13249                    movement::left(map, selection.start)
13250                } else {
13251                    selection.start
13252                };
13253                selection.collapse_to(cursor, SelectionGoal::None);
13254            });
13255        })
13256    }
13257
13258    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13259        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13260        self.change_selections(Default::default(), window, cx, |s| {
13261            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13262        })
13263    }
13264
13265    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13266        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13267        self.change_selections(Default::default(), window, cx, |s| {
13268            s.move_with(|map, selection| {
13269                let cursor = if selection.is_empty() {
13270                    movement::right(map, selection.end)
13271                } else {
13272                    selection.end
13273                };
13274                selection.collapse_to(cursor, SelectionGoal::None)
13275            });
13276        })
13277    }
13278
13279    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13280        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13281        self.change_selections(Default::default(), window, cx, |s| {
13282            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13283        });
13284    }
13285
13286    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13287        if self.take_rename(true, window, cx).is_some() {
13288            return;
13289        }
13290
13291        if self.mode.is_single_line() {
13292            cx.propagate();
13293            return;
13294        }
13295
13296        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13297
13298        let text_layout_details = &self.text_layout_details(window);
13299        let selection_count = self.selections.count();
13300        let first_selection = self.selections.first_anchor();
13301
13302        self.change_selections(Default::default(), window, cx, |s| {
13303            s.move_with(|map, selection| {
13304                if !selection.is_empty() {
13305                    selection.goal = SelectionGoal::None;
13306                }
13307                let (cursor, goal) = movement::up(
13308                    map,
13309                    selection.start,
13310                    selection.goal,
13311                    false,
13312                    text_layout_details,
13313                );
13314                selection.collapse_to(cursor, goal);
13315            });
13316        });
13317
13318        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13319        {
13320            cx.propagate();
13321        }
13322    }
13323
13324    pub fn move_up_by_lines(
13325        &mut self,
13326        action: &MoveUpByLines,
13327        window: &mut Window,
13328        cx: &mut Context<Self>,
13329    ) {
13330        if self.take_rename(true, window, cx).is_some() {
13331            return;
13332        }
13333
13334        if self.mode.is_single_line() {
13335            cx.propagate();
13336            return;
13337        }
13338
13339        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13340
13341        let text_layout_details = &self.text_layout_details(window);
13342
13343        self.change_selections(Default::default(), window, cx, |s| {
13344            s.move_with(|map, selection| {
13345                if !selection.is_empty() {
13346                    selection.goal = SelectionGoal::None;
13347                }
13348                let (cursor, goal) = movement::up_by_rows(
13349                    map,
13350                    selection.start,
13351                    action.lines,
13352                    selection.goal,
13353                    false,
13354                    text_layout_details,
13355                );
13356                selection.collapse_to(cursor, goal);
13357            });
13358        })
13359    }
13360
13361    pub fn move_down_by_lines(
13362        &mut self,
13363        action: &MoveDownByLines,
13364        window: &mut Window,
13365        cx: &mut Context<Self>,
13366    ) {
13367        if self.take_rename(true, window, cx).is_some() {
13368            return;
13369        }
13370
13371        if self.mode.is_single_line() {
13372            cx.propagate();
13373            return;
13374        }
13375
13376        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13377
13378        let text_layout_details = &self.text_layout_details(window);
13379
13380        self.change_selections(Default::default(), window, cx, |s| {
13381            s.move_with(|map, selection| {
13382                if !selection.is_empty() {
13383                    selection.goal = SelectionGoal::None;
13384                }
13385                let (cursor, goal) = movement::down_by_rows(
13386                    map,
13387                    selection.start,
13388                    action.lines,
13389                    selection.goal,
13390                    false,
13391                    text_layout_details,
13392                );
13393                selection.collapse_to(cursor, goal);
13394            });
13395        })
13396    }
13397
13398    pub fn select_down_by_lines(
13399        &mut self,
13400        action: &SelectDownByLines,
13401        window: &mut Window,
13402        cx: &mut Context<Self>,
13403    ) {
13404        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13405        let text_layout_details = &self.text_layout_details(window);
13406        self.change_selections(Default::default(), window, cx, |s| {
13407            s.move_heads_with(|map, head, goal| {
13408                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13409            })
13410        })
13411    }
13412
13413    pub fn select_up_by_lines(
13414        &mut self,
13415        action: &SelectUpByLines,
13416        window: &mut Window,
13417        cx: &mut Context<Self>,
13418    ) {
13419        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13420        let text_layout_details = &self.text_layout_details(window);
13421        self.change_selections(Default::default(), window, cx, |s| {
13422            s.move_heads_with(|map, head, goal| {
13423                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13424            })
13425        })
13426    }
13427
13428    pub fn select_page_up(
13429        &mut self,
13430        _: &SelectPageUp,
13431        window: &mut Window,
13432        cx: &mut Context<Self>,
13433    ) {
13434        let Some(row_count) = self.visible_row_count() else {
13435            return;
13436        };
13437
13438        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13439
13440        let text_layout_details = &self.text_layout_details(window);
13441
13442        self.change_selections(Default::default(), window, cx, |s| {
13443            s.move_heads_with(|map, head, goal| {
13444                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13445            })
13446        })
13447    }
13448
13449    pub fn move_page_up(
13450        &mut self,
13451        action: &MovePageUp,
13452        window: &mut Window,
13453        cx: &mut Context<Self>,
13454    ) {
13455        if self.take_rename(true, window, cx).is_some() {
13456            return;
13457        }
13458
13459        if self
13460            .context_menu
13461            .borrow_mut()
13462            .as_mut()
13463            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13464            .unwrap_or(false)
13465        {
13466            return;
13467        }
13468
13469        if matches!(self.mode, EditorMode::SingleLine) {
13470            cx.propagate();
13471            return;
13472        }
13473
13474        let Some(row_count) = self.visible_row_count() else {
13475            return;
13476        };
13477
13478        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13479
13480        let effects = if action.center_cursor {
13481            SelectionEffects::scroll(Autoscroll::center())
13482        } else {
13483            SelectionEffects::default()
13484        };
13485
13486        let text_layout_details = &self.text_layout_details(window);
13487
13488        self.change_selections(effects, window, cx, |s| {
13489            s.move_with(|map, selection| {
13490                if !selection.is_empty() {
13491                    selection.goal = SelectionGoal::None;
13492                }
13493                let (cursor, goal) = movement::up_by_rows(
13494                    map,
13495                    selection.end,
13496                    row_count,
13497                    selection.goal,
13498                    false,
13499                    text_layout_details,
13500                );
13501                selection.collapse_to(cursor, goal);
13502            });
13503        });
13504    }
13505
13506    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13507        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13508        let text_layout_details = &self.text_layout_details(window);
13509        self.change_selections(Default::default(), window, cx, |s| {
13510            s.move_heads_with(|map, head, goal| {
13511                movement::up(map, head, goal, false, text_layout_details)
13512            })
13513        })
13514    }
13515
13516    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13517        self.take_rename(true, window, cx);
13518
13519        if self.mode.is_single_line() {
13520            cx.propagate();
13521            return;
13522        }
13523
13524        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13525
13526        let text_layout_details = &self.text_layout_details(window);
13527        let selection_count = self.selections.count();
13528        let first_selection = self.selections.first_anchor();
13529
13530        self.change_selections(Default::default(), window, cx, |s| {
13531            s.move_with(|map, selection| {
13532                if !selection.is_empty() {
13533                    selection.goal = SelectionGoal::None;
13534                }
13535                let (cursor, goal) = movement::down(
13536                    map,
13537                    selection.end,
13538                    selection.goal,
13539                    false,
13540                    text_layout_details,
13541                );
13542                selection.collapse_to(cursor, goal);
13543            });
13544        });
13545
13546        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13547        {
13548            cx.propagate();
13549        }
13550    }
13551
13552    pub fn select_page_down(
13553        &mut self,
13554        _: &SelectPageDown,
13555        window: &mut Window,
13556        cx: &mut Context<Self>,
13557    ) {
13558        let Some(row_count) = self.visible_row_count() else {
13559            return;
13560        };
13561
13562        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13563
13564        let text_layout_details = &self.text_layout_details(window);
13565
13566        self.change_selections(Default::default(), window, cx, |s| {
13567            s.move_heads_with(|map, head, goal| {
13568                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13569            })
13570        })
13571    }
13572
13573    pub fn move_page_down(
13574        &mut self,
13575        action: &MovePageDown,
13576        window: &mut Window,
13577        cx: &mut Context<Self>,
13578    ) {
13579        if self.take_rename(true, window, cx).is_some() {
13580            return;
13581        }
13582
13583        if self
13584            .context_menu
13585            .borrow_mut()
13586            .as_mut()
13587            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13588            .unwrap_or(false)
13589        {
13590            return;
13591        }
13592
13593        if matches!(self.mode, EditorMode::SingleLine) {
13594            cx.propagate();
13595            return;
13596        }
13597
13598        let Some(row_count) = self.visible_row_count() else {
13599            return;
13600        };
13601
13602        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13603
13604        let effects = if action.center_cursor {
13605            SelectionEffects::scroll(Autoscroll::center())
13606        } else {
13607            SelectionEffects::default()
13608        };
13609
13610        let text_layout_details = &self.text_layout_details(window);
13611        self.change_selections(effects, window, cx, |s| {
13612            s.move_with(|map, selection| {
13613                if !selection.is_empty() {
13614                    selection.goal = SelectionGoal::None;
13615                }
13616                let (cursor, goal) = movement::down_by_rows(
13617                    map,
13618                    selection.end,
13619                    row_count,
13620                    selection.goal,
13621                    false,
13622                    text_layout_details,
13623                );
13624                selection.collapse_to(cursor, goal);
13625            });
13626        });
13627    }
13628
13629    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13630        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13631        let text_layout_details = &self.text_layout_details(window);
13632        self.change_selections(Default::default(), window, cx, |s| {
13633            s.move_heads_with(|map, head, goal| {
13634                movement::down(map, head, goal, false, text_layout_details)
13635            })
13636        });
13637    }
13638
13639    pub fn context_menu_first(
13640        &mut self,
13641        _: &ContextMenuFirst,
13642        window: &mut Window,
13643        cx: &mut Context<Self>,
13644    ) {
13645        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13646            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13647        }
13648    }
13649
13650    pub fn context_menu_prev(
13651        &mut self,
13652        _: &ContextMenuPrevious,
13653        window: &mut Window,
13654        cx: &mut Context<Self>,
13655    ) {
13656        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13657            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13658        }
13659    }
13660
13661    pub fn context_menu_next(
13662        &mut self,
13663        _: &ContextMenuNext,
13664        window: &mut Window,
13665        cx: &mut Context<Self>,
13666    ) {
13667        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13668            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13669        }
13670    }
13671
13672    pub fn context_menu_last(
13673        &mut self,
13674        _: &ContextMenuLast,
13675        window: &mut Window,
13676        cx: &mut Context<Self>,
13677    ) {
13678        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13679            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13680        }
13681    }
13682
13683    pub fn signature_help_prev(
13684        &mut self,
13685        _: &SignatureHelpPrevious,
13686        _: &mut Window,
13687        cx: &mut Context<Self>,
13688    ) {
13689        if let Some(popover) = self.signature_help_state.popover_mut() {
13690            if popover.current_signature == 0 {
13691                popover.current_signature = popover.signatures.len() - 1;
13692            } else {
13693                popover.current_signature -= 1;
13694            }
13695            cx.notify();
13696        }
13697    }
13698
13699    pub fn signature_help_next(
13700        &mut self,
13701        _: &SignatureHelpNext,
13702        _: &mut Window,
13703        cx: &mut Context<Self>,
13704    ) {
13705        if let Some(popover) = self.signature_help_state.popover_mut() {
13706            if popover.current_signature + 1 == popover.signatures.len() {
13707                popover.current_signature = 0;
13708            } else {
13709                popover.current_signature += 1;
13710            }
13711            cx.notify();
13712        }
13713    }
13714
13715    pub fn move_to_previous_word_start(
13716        &mut self,
13717        _: &MoveToPreviousWordStart,
13718        window: &mut Window,
13719        cx: &mut Context<Self>,
13720    ) {
13721        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13722        self.change_selections(Default::default(), window, cx, |s| {
13723            s.move_cursors_with(|map, head, _| {
13724                (
13725                    movement::previous_word_start(map, head),
13726                    SelectionGoal::None,
13727                )
13728            });
13729        })
13730    }
13731
13732    pub fn move_to_previous_subword_start(
13733        &mut self,
13734        _: &MoveToPreviousSubwordStart,
13735        window: &mut Window,
13736        cx: &mut Context<Self>,
13737    ) {
13738        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13739        self.change_selections(Default::default(), window, cx, |s| {
13740            s.move_cursors_with(|map, head, _| {
13741                (
13742                    movement::previous_subword_start(map, head),
13743                    SelectionGoal::None,
13744                )
13745            });
13746        })
13747    }
13748
13749    pub fn select_to_previous_word_start(
13750        &mut self,
13751        _: &SelectToPreviousWordStart,
13752        window: &mut Window,
13753        cx: &mut Context<Self>,
13754    ) {
13755        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13756        self.change_selections(Default::default(), window, cx, |s| {
13757            s.move_heads_with(|map, head, _| {
13758                (
13759                    movement::previous_word_start(map, head),
13760                    SelectionGoal::None,
13761                )
13762            });
13763        })
13764    }
13765
13766    pub fn select_to_previous_subword_start(
13767        &mut self,
13768        _: &SelectToPreviousSubwordStart,
13769        window: &mut Window,
13770        cx: &mut Context<Self>,
13771    ) {
13772        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13773        self.change_selections(Default::default(), window, cx, |s| {
13774            s.move_heads_with(|map, head, _| {
13775                (
13776                    movement::previous_subword_start(map, head),
13777                    SelectionGoal::None,
13778                )
13779            });
13780        })
13781    }
13782
13783    pub fn delete_to_previous_word_start(
13784        &mut self,
13785        action: &DeleteToPreviousWordStart,
13786        window: &mut Window,
13787        cx: &mut Context<Self>,
13788    ) {
13789        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13790        self.transact(window, cx, |this, window, cx| {
13791            this.select_autoclose_pair(window, cx);
13792            this.change_selections(Default::default(), window, cx, |s| {
13793                s.move_with(|map, selection| {
13794                    if selection.is_empty() {
13795                        let mut cursor = if action.ignore_newlines {
13796                            movement::previous_word_start(map, selection.head())
13797                        } else {
13798                            movement::previous_word_start_or_newline(map, selection.head())
13799                        };
13800                        cursor = movement::adjust_greedy_deletion(
13801                            map,
13802                            selection.head(),
13803                            cursor,
13804                            action.ignore_brackets,
13805                        );
13806                        selection.set_head(cursor, SelectionGoal::None);
13807                    }
13808                });
13809            });
13810            this.insert("", window, cx);
13811        });
13812    }
13813
13814    pub fn delete_to_previous_subword_start(
13815        &mut self,
13816        _: &DeleteToPreviousSubwordStart,
13817        window: &mut Window,
13818        cx: &mut Context<Self>,
13819    ) {
13820        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13821        self.transact(window, cx, |this, window, cx| {
13822            this.select_autoclose_pair(window, cx);
13823            this.change_selections(Default::default(), window, cx, |s| {
13824                s.move_with(|map, selection| {
13825                    if selection.is_empty() {
13826                        let mut cursor = movement::previous_subword_start(map, selection.head());
13827                        cursor =
13828                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13829                        selection.set_head(cursor, SelectionGoal::None);
13830                    }
13831                });
13832            });
13833            this.insert("", window, cx);
13834        });
13835    }
13836
13837    pub fn move_to_next_word_end(
13838        &mut self,
13839        _: &MoveToNextWordEnd,
13840        window: &mut Window,
13841        cx: &mut Context<Self>,
13842    ) {
13843        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13844        self.change_selections(Default::default(), window, cx, |s| {
13845            s.move_cursors_with(|map, head, _| {
13846                (movement::next_word_end(map, head), SelectionGoal::None)
13847            });
13848        })
13849    }
13850
13851    pub fn move_to_next_subword_end(
13852        &mut self,
13853        _: &MoveToNextSubwordEnd,
13854        window: &mut Window,
13855        cx: &mut Context<Self>,
13856    ) {
13857        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13858        self.change_selections(Default::default(), window, cx, |s| {
13859            s.move_cursors_with(|map, head, _| {
13860                (movement::next_subword_end(map, head), SelectionGoal::None)
13861            });
13862        })
13863    }
13864
13865    pub fn select_to_next_word_end(
13866        &mut self,
13867        _: &SelectToNextWordEnd,
13868        window: &mut Window,
13869        cx: &mut Context<Self>,
13870    ) {
13871        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13872        self.change_selections(Default::default(), window, cx, |s| {
13873            s.move_heads_with(|map, head, _| {
13874                (movement::next_word_end(map, head), SelectionGoal::None)
13875            });
13876        })
13877    }
13878
13879    pub fn select_to_next_subword_end(
13880        &mut self,
13881        _: &SelectToNextSubwordEnd,
13882        window: &mut Window,
13883        cx: &mut Context<Self>,
13884    ) {
13885        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13886        self.change_selections(Default::default(), window, cx, |s| {
13887            s.move_heads_with(|map, head, _| {
13888                (movement::next_subword_end(map, head), SelectionGoal::None)
13889            });
13890        })
13891    }
13892
13893    pub fn delete_to_next_word_end(
13894        &mut self,
13895        action: &DeleteToNextWordEnd,
13896        window: &mut Window,
13897        cx: &mut Context<Self>,
13898    ) {
13899        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13900        self.transact(window, cx, |this, window, cx| {
13901            this.change_selections(Default::default(), window, cx, |s| {
13902                s.move_with(|map, selection| {
13903                    if selection.is_empty() {
13904                        let mut cursor = if action.ignore_newlines {
13905                            movement::next_word_end(map, selection.head())
13906                        } else {
13907                            movement::next_word_end_or_newline(map, selection.head())
13908                        };
13909                        cursor = movement::adjust_greedy_deletion(
13910                            map,
13911                            selection.head(),
13912                            cursor,
13913                            action.ignore_brackets,
13914                        );
13915                        selection.set_head(cursor, SelectionGoal::None);
13916                    }
13917                });
13918            });
13919            this.insert("", window, cx);
13920        });
13921    }
13922
13923    pub fn delete_to_next_subword_end(
13924        &mut self,
13925        _: &DeleteToNextSubwordEnd,
13926        window: &mut Window,
13927        cx: &mut Context<Self>,
13928    ) {
13929        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13930        self.transact(window, cx, |this, window, cx| {
13931            this.change_selections(Default::default(), window, cx, |s| {
13932                s.move_with(|map, selection| {
13933                    if selection.is_empty() {
13934                        let mut cursor = movement::next_subword_end(map, selection.head());
13935                        cursor =
13936                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13937                        selection.set_head(cursor, SelectionGoal::None);
13938                    }
13939                });
13940            });
13941            this.insert("", window, cx);
13942        });
13943    }
13944
13945    pub fn move_to_beginning_of_line(
13946        &mut self,
13947        action: &MoveToBeginningOfLine,
13948        window: &mut Window,
13949        cx: &mut Context<Self>,
13950    ) {
13951        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13952        self.change_selections(Default::default(), window, cx, |s| {
13953            s.move_cursors_with(|map, head, _| {
13954                (
13955                    movement::indented_line_beginning(
13956                        map,
13957                        head,
13958                        action.stop_at_soft_wraps,
13959                        action.stop_at_indent,
13960                    ),
13961                    SelectionGoal::None,
13962                )
13963            });
13964        })
13965    }
13966
13967    pub fn select_to_beginning_of_line(
13968        &mut self,
13969        action: &SelectToBeginningOfLine,
13970        window: &mut Window,
13971        cx: &mut Context<Self>,
13972    ) {
13973        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13974        self.change_selections(Default::default(), window, cx, |s| {
13975            s.move_heads_with(|map, head, _| {
13976                (
13977                    movement::indented_line_beginning(
13978                        map,
13979                        head,
13980                        action.stop_at_soft_wraps,
13981                        action.stop_at_indent,
13982                    ),
13983                    SelectionGoal::None,
13984                )
13985            });
13986        });
13987    }
13988
13989    pub fn delete_to_beginning_of_line(
13990        &mut self,
13991        action: &DeleteToBeginningOfLine,
13992        window: &mut Window,
13993        cx: &mut Context<Self>,
13994    ) {
13995        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13996        self.transact(window, cx, |this, window, cx| {
13997            this.change_selections(Default::default(), window, cx, |s| {
13998                s.move_with(|_, selection| {
13999                    selection.reversed = true;
14000                });
14001            });
14002
14003            this.select_to_beginning_of_line(
14004                &SelectToBeginningOfLine {
14005                    stop_at_soft_wraps: false,
14006                    stop_at_indent: action.stop_at_indent,
14007                },
14008                window,
14009                cx,
14010            );
14011            this.backspace(&Backspace, window, cx);
14012        });
14013    }
14014
14015    pub fn move_to_end_of_line(
14016        &mut self,
14017        action: &MoveToEndOfLine,
14018        window: &mut Window,
14019        cx: &mut Context<Self>,
14020    ) {
14021        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14022        self.change_selections(Default::default(), window, cx, |s| {
14023            s.move_cursors_with(|map, head, _| {
14024                (
14025                    movement::line_end(map, head, action.stop_at_soft_wraps),
14026                    SelectionGoal::None,
14027                )
14028            });
14029        })
14030    }
14031
14032    pub fn select_to_end_of_line(
14033        &mut self,
14034        action: &SelectToEndOfLine,
14035        window: &mut Window,
14036        cx: &mut Context<Self>,
14037    ) {
14038        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14039        self.change_selections(Default::default(), window, cx, |s| {
14040            s.move_heads_with(|map, head, _| {
14041                (
14042                    movement::line_end(map, head, action.stop_at_soft_wraps),
14043                    SelectionGoal::None,
14044                )
14045            });
14046        })
14047    }
14048
14049    pub fn delete_to_end_of_line(
14050        &mut self,
14051        _: &DeleteToEndOfLine,
14052        window: &mut Window,
14053        cx: &mut Context<Self>,
14054    ) {
14055        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14056        self.transact(window, cx, |this, window, cx| {
14057            this.select_to_end_of_line(
14058                &SelectToEndOfLine {
14059                    stop_at_soft_wraps: false,
14060                },
14061                window,
14062                cx,
14063            );
14064            this.delete(&Delete, window, cx);
14065        });
14066    }
14067
14068    pub fn cut_to_end_of_line(
14069        &mut self,
14070        action: &CutToEndOfLine,
14071        window: &mut Window,
14072        cx: &mut Context<Self>,
14073    ) {
14074        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14075        self.transact(window, cx, |this, window, cx| {
14076            this.select_to_end_of_line(
14077                &SelectToEndOfLine {
14078                    stop_at_soft_wraps: false,
14079                },
14080                window,
14081                cx,
14082            );
14083            if !action.stop_at_newlines {
14084                this.change_selections(Default::default(), window, cx, |s| {
14085                    s.move_with(|_, sel| {
14086                        if sel.is_empty() {
14087                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14088                        }
14089                    });
14090                });
14091            }
14092            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14093            let item = this.cut_common(false, window, cx);
14094            cx.write_to_clipboard(item);
14095        });
14096    }
14097
14098    pub fn move_to_start_of_paragraph(
14099        &mut self,
14100        _: &MoveToStartOfParagraph,
14101        window: &mut Window,
14102        cx: &mut Context<Self>,
14103    ) {
14104        if matches!(self.mode, EditorMode::SingleLine) {
14105            cx.propagate();
14106            return;
14107        }
14108        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14109        self.change_selections(Default::default(), window, cx, |s| {
14110            s.move_with(|map, selection| {
14111                selection.collapse_to(
14112                    movement::start_of_paragraph(map, selection.head(), 1),
14113                    SelectionGoal::None,
14114                )
14115            });
14116        })
14117    }
14118
14119    pub fn move_to_end_of_paragraph(
14120        &mut self,
14121        _: &MoveToEndOfParagraph,
14122        window: &mut Window,
14123        cx: &mut Context<Self>,
14124    ) {
14125        if matches!(self.mode, EditorMode::SingleLine) {
14126            cx.propagate();
14127            return;
14128        }
14129        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14130        self.change_selections(Default::default(), window, cx, |s| {
14131            s.move_with(|map, selection| {
14132                selection.collapse_to(
14133                    movement::end_of_paragraph(map, selection.head(), 1),
14134                    SelectionGoal::None,
14135                )
14136            });
14137        })
14138    }
14139
14140    pub fn select_to_start_of_paragraph(
14141        &mut self,
14142        _: &SelectToStartOfParagraph,
14143        window: &mut Window,
14144        cx: &mut Context<Self>,
14145    ) {
14146        if matches!(self.mode, EditorMode::SingleLine) {
14147            cx.propagate();
14148            return;
14149        }
14150        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14151        self.change_selections(Default::default(), window, cx, |s| {
14152            s.move_heads_with(|map, head, _| {
14153                (
14154                    movement::start_of_paragraph(map, head, 1),
14155                    SelectionGoal::None,
14156                )
14157            });
14158        })
14159    }
14160
14161    pub fn select_to_end_of_paragraph(
14162        &mut self,
14163        _: &SelectToEndOfParagraph,
14164        window: &mut Window,
14165        cx: &mut Context<Self>,
14166    ) {
14167        if matches!(self.mode, EditorMode::SingleLine) {
14168            cx.propagate();
14169            return;
14170        }
14171        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14172        self.change_selections(Default::default(), window, cx, |s| {
14173            s.move_heads_with(|map, head, _| {
14174                (
14175                    movement::end_of_paragraph(map, head, 1),
14176                    SelectionGoal::None,
14177                )
14178            });
14179        })
14180    }
14181
14182    pub fn move_to_start_of_excerpt(
14183        &mut self,
14184        _: &MoveToStartOfExcerpt,
14185        window: &mut Window,
14186        cx: &mut Context<Self>,
14187    ) {
14188        if matches!(self.mode, EditorMode::SingleLine) {
14189            cx.propagate();
14190            return;
14191        }
14192        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14193        self.change_selections(Default::default(), window, cx, |s| {
14194            s.move_with(|map, selection| {
14195                selection.collapse_to(
14196                    movement::start_of_excerpt(
14197                        map,
14198                        selection.head(),
14199                        workspace::searchable::Direction::Prev,
14200                    ),
14201                    SelectionGoal::None,
14202                )
14203            });
14204        })
14205    }
14206
14207    pub fn move_to_start_of_next_excerpt(
14208        &mut self,
14209        _: &MoveToStartOfNextExcerpt,
14210        window: &mut Window,
14211        cx: &mut Context<Self>,
14212    ) {
14213        if matches!(self.mode, EditorMode::SingleLine) {
14214            cx.propagate();
14215            return;
14216        }
14217
14218        self.change_selections(Default::default(), window, cx, |s| {
14219            s.move_with(|map, selection| {
14220                selection.collapse_to(
14221                    movement::start_of_excerpt(
14222                        map,
14223                        selection.head(),
14224                        workspace::searchable::Direction::Next,
14225                    ),
14226                    SelectionGoal::None,
14227                )
14228            });
14229        })
14230    }
14231
14232    pub fn move_to_end_of_excerpt(
14233        &mut self,
14234        _: &MoveToEndOfExcerpt,
14235        window: &mut Window,
14236        cx: &mut Context<Self>,
14237    ) {
14238        if matches!(self.mode, EditorMode::SingleLine) {
14239            cx.propagate();
14240            return;
14241        }
14242        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14243        self.change_selections(Default::default(), window, cx, |s| {
14244            s.move_with(|map, selection| {
14245                selection.collapse_to(
14246                    movement::end_of_excerpt(
14247                        map,
14248                        selection.head(),
14249                        workspace::searchable::Direction::Next,
14250                    ),
14251                    SelectionGoal::None,
14252                )
14253            });
14254        })
14255    }
14256
14257    pub fn move_to_end_of_previous_excerpt(
14258        &mut self,
14259        _: &MoveToEndOfPreviousExcerpt,
14260        window: &mut Window,
14261        cx: &mut Context<Self>,
14262    ) {
14263        if matches!(self.mode, EditorMode::SingleLine) {
14264            cx.propagate();
14265            return;
14266        }
14267        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14268        self.change_selections(Default::default(), window, cx, |s| {
14269            s.move_with(|map, selection| {
14270                selection.collapse_to(
14271                    movement::end_of_excerpt(
14272                        map,
14273                        selection.head(),
14274                        workspace::searchable::Direction::Prev,
14275                    ),
14276                    SelectionGoal::None,
14277                )
14278            });
14279        })
14280    }
14281
14282    pub fn select_to_start_of_excerpt(
14283        &mut self,
14284        _: &SelectToStartOfExcerpt,
14285        window: &mut Window,
14286        cx: &mut Context<Self>,
14287    ) {
14288        if matches!(self.mode, EditorMode::SingleLine) {
14289            cx.propagate();
14290            return;
14291        }
14292        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14293        self.change_selections(Default::default(), window, cx, |s| {
14294            s.move_heads_with(|map, head, _| {
14295                (
14296                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14297                    SelectionGoal::None,
14298                )
14299            });
14300        })
14301    }
14302
14303    pub fn select_to_start_of_next_excerpt(
14304        &mut self,
14305        _: &SelectToStartOfNextExcerpt,
14306        window: &mut Window,
14307        cx: &mut Context<Self>,
14308    ) {
14309        if matches!(self.mode, EditorMode::SingleLine) {
14310            cx.propagate();
14311            return;
14312        }
14313        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14314        self.change_selections(Default::default(), window, cx, |s| {
14315            s.move_heads_with(|map, head, _| {
14316                (
14317                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14318                    SelectionGoal::None,
14319                )
14320            });
14321        })
14322    }
14323
14324    pub fn select_to_end_of_excerpt(
14325        &mut self,
14326        _: &SelectToEndOfExcerpt,
14327        window: &mut Window,
14328        cx: &mut Context<Self>,
14329    ) {
14330        if matches!(self.mode, EditorMode::SingleLine) {
14331            cx.propagate();
14332            return;
14333        }
14334        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14335        self.change_selections(Default::default(), window, cx, |s| {
14336            s.move_heads_with(|map, head, _| {
14337                (
14338                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14339                    SelectionGoal::None,
14340                )
14341            });
14342        })
14343    }
14344
14345    pub fn select_to_end_of_previous_excerpt(
14346        &mut self,
14347        _: &SelectToEndOfPreviousExcerpt,
14348        window: &mut Window,
14349        cx: &mut Context<Self>,
14350    ) {
14351        if matches!(self.mode, EditorMode::SingleLine) {
14352            cx.propagate();
14353            return;
14354        }
14355        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14356        self.change_selections(Default::default(), window, cx, |s| {
14357            s.move_heads_with(|map, head, _| {
14358                (
14359                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14360                    SelectionGoal::None,
14361                )
14362            });
14363        })
14364    }
14365
14366    pub fn move_to_beginning(
14367        &mut self,
14368        _: &MoveToBeginning,
14369        window: &mut Window,
14370        cx: &mut Context<Self>,
14371    ) {
14372        if matches!(self.mode, EditorMode::SingleLine) {
14373            cx.propagate();
14374            return;
14375        }
14376        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14377        self.change_selections(Default::default(), window, cx, |s| {
14378            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14379        });
14380    }
14381
14382    pub fn select_to_beginning(
14383        &mut self,
14384        _: &SelectToBeginning,
14385        window: &mut Window,
14386        cx: &mut Context<Self>,
14387    ) {
14388        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14389        selection.set_head(Point::zero(), SelectionGoal::None);
14390        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14391        self.change_selections(Default::default(), window, cx, |s| {
14392            s.select(vec![selection]);
14393        });
14394    }
14395
14396    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14397        if matches!(self.mode, EditorMode::SingleLine) {
14398            cx.propagate();
14399            return;
14400        }
14401        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14402        let cursor = self.buffer.read(cx).read(cx).len();
14403        self.change_selections(Default::default(), window, cx, |s| {
14404            s.select_ranges(vec![cursor..cursor])
14405        });
14406    }
14407
14408    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14409        self.nav_history = nav_history;
14410    }
14411
14412    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14413        self.nav_history.as_ref()
14414    }
14415
14416    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14417        self.push_to_nav_history(
14418            self.selections.newest_anchor().head(),
14419            None,
14420            false,
14421            true,
14422            cx,
14423        );
14424    }
14425
14426    fn push_to_nav_history(
14427        &mut self,
14428        cursor_anchor: Anchor,
14429        new_position: Option<Point>,
14430        is_deactivate: bool,
14431        always: bool,
14432        cx: &mut Context<Self>,
14433    ) {
14434        if let Some(nav_history) = self.nav_history.as_mut() {
14435            let buffer = self.buffer.read(cx).read(cx);
14436            let cursor_position = cursor_anchor.to_point(&buffer);
14437            let scroll_state = self.scroll_manager.anchor();
14438            let scroll_top_row = scroll_state.top_row(&buffer);
14439            drop(buffer);
14440
14441            if let Some(new_position) = new_position {
14442                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14443                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14444                    return;
14445                }
14446            }
14447
14448            nav_history.push(
14449                Some(NavigationData {
14450                    cursor_anchor,
14451                    cursor_position,
14452                    scroll_anchor: scroll_state,
14453                    scroll_top_row,
14454                }),
14455                cx,
14456            );
14457            cx.emit(EditorEvent::PushedToNavHistory {
14458                anchor: cursor_anchor,
14459                is_deactivate,
14460            })
14461        }
14462    }
14463
14464    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14465        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14466        let buffer = self.buffer.read(cx).snapshot(cx);
14467        let mut selection = self
14468            .selections
14469            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14470        selection.set_head(buffer.len(), SelectionGoal::None);
14471        self.change_selections(Default::default(), window, cx, |s| {
14472            s.select(vec![selection]);
14473        });
14474    }
14475
14476    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14477        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14478        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14479            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14480        });
14481    }
14482
14483    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14484        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14485        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14486        let mut selections = self.selections.all::<Point>(&display_map);
14487        let max_point = display_map.buffer_snapshot().max_point();
14488        for selection in &mut selections {
14489            let rows = selection.spanned_rows(true, &display_map);
14490            selection.start = Point::new(rows.start.0, 0);
14491            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14492            selection.reversed = false;
14493        }
14494        self.change_selections(Default::default(), window, cx, |s| {
14495            s.select(selections);
14496        });
14497    }
14498
14499    pub fn split_selection_into_lines(
14500        &mut self,
14501        action: &SplitSelectionIntoLines,
14502        window: &mut Window,
14503        cx: &mut Context<Self>,
14504    ) {
14505        let selections = self
14506            .selections
14507            .all::<Point>(&self.display_snapshot(cx))
14508            .into_iter()
14509            .map(|selection| selection.start..selection.end)
14510            .collect::<Vec<_>>();
14511        self.unfold_ranges(&selections, true, true, cx);
14512
14513        let mut new_selection_ranges = Vec::new();
14514        {
14515            let buffer = self.buffer.read(cx).read(cx);
14516            for selection in selections {
14517                for row in selection.start.row..selection.end.row {
14518                    let line_start = Point::new(row, 0);
14519                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14520
14521                    if action.keep_selections {
14522                        // Keep the selection range for each line
14523                        let selection_start = if row == selection.start.row {
14524                            selection.start
14525                        } else {
14526                            line_start
14527                        };
14528                        new_selection_ranges.push(selection_start..line_end);
14529                    } else {
14530                        // Collapse to cursor at end of line
14531                        new_selection_ranges.push(line_end..line_end);
14532                    }
14533                }
14534
14535                let is_multiline_selection = selection.start.row != selection.end.row;
14536                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14537                // so this action feels more ergonomic when paired with other selection operations
14538                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14539                if !should_skip_last {
14540                    if action.keep_selections {
14541                        if is_multiline_selection {
14542                            let line_start = Point::new(selection.end.row, 0);
14543                            new_selection_ranges.push(line_start..selection.end);
14544                        } else {
14545                            new_selection_ranges.push(selection.start..selection.end);
14546                        }
14547                    } else {
14548                        new_selection_ranges.push(selection.end..selection.end);
14549                    }
14550                }
14551            }
14552        }
14553        self.change_selections(Default::default(), window, cx, |s| {
14554            s.select_ranges(new_selection_ranges);
14555        });
14556    }
14557
14558    pub fn add_selection_above(
14559        &mut self,
14560        action: &AddSelectionAbove,
14561        window: &mut Window,
14562        cx: &mut Context<Self>,
14563    ) {
14564        self.add_selection(true, action.skip_soft_wrap, window, cx);
14565    }
14566
14567    pub fn add_selection_below(
14568        &mut self,
14569        action: &AddSelectionBelow,
14570        window: &mut Window,
14571        cx: &mut Context<Self>,
14572    ) {
14573        self.add_selection(false, action.skip_soft_wrap, window, cx);
14574    }
14575
14576    fn add_selection(
14577        &mut self,
14578        above: bool,
14579        skip_soft_wrap: bool,
14580        window: &mut Window,
14581        cx: &mut Context<Self>,
14582    ) {
14583        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14584
14585        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14586        let all_selections = self.selections.all::<Point>(&display_map);
14587        let text_layout_details = self.text_layout_details(window);
14588
14589        let (mut columnar_selections, new_selections_to_columnarize) = {
14590            if let Some(state) = self.add_selections_state.as_ref() {
14591                let columnar_selection_ids: HashSet<_> = state
14592                    .groups
14593                    .iter()
14594                    .flat_map(|group| group.stack.iter())
14595                    .copied()
14596                    .collect();
14597
14598                all_selections
14599                    .into_iter()
14600                    .partition(|s| columnar_selection_ids.contains(&s.id))
14601            } else {
14602                (Vec::new(), all_selections)
14603            }
14604        };
14605
14606        let mut state = self
14607            .add_selections_state
14608            .take()
14609            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14610
14611        for selection in new_selections_to_columnarize {
14612            let range = selection.display_range(&display_map).sorted();
14613            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14614            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14615            let positions = start_x.min(end_x)..start_x.max(end_x);
14616            let mut stack = Vec::new();
14617            for row in range.start.row().0..=range.end.row().0 {
14618                if let Some(selection) = self.selections.build_columnar_selection(
14619                    &display_map,
14620                    DisplayRow(row),
14621                    &positions,
14622                    selection.reversed,
14623                    &text_layout_details,
14624                ) {
14625                    stack.push(selection.id);
14626                    columnar_selections.push(selection);
14627                }
14628            }
14629            if !stack.is_empty() {
14630                if above {
14631                    stack.reverse();
14632                }
14633                state.groups.push(AddSelectionsGroup { above, stack });
14634            }
14635        }
14636
14637        let mut final_selections = Vec::new();
14638        let end_row = if above {
14639            DisplayRow(0)
14640        } else {
14641            display_map.max_point().row()
14642        };
14643
14644        let mut last_added_item_per_group = HashMap::default();
14645        for group in state.groups.iter_mut() {
14646            if let Some(last_id) = group.stack.last() {
14647                last_added_item_per_group.insert(*last_id, group);
14648            }
14649        }
14650
14651        for selection in columnar_selections {
14652            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14653                if above == group.above {
14654                    let range = selection.display_range(&display_map).sorted();
14655                    debug_assert_eq!(range.start.row(), range.end.row());
14656                    let mut row = range.start.row();
14657                    let positions =
14658                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14659                            Pixels::from(start)..Pixels::from(end)
14660                        } else {
14661                            let start_x =
14662                                display_map.x_for_display_point(range.start, &text_layout_details);
14663                            let end_x =
14664                                display_map.x_for_display_point(range.end, &text_layout_details);
14665                            start_x.min(end_x)..start_x.max(end_x)
14666                        };
14667
14668                    let mut maybe_new_selection = None;
14669                    let direction = if above { -1 } else { 1 };
14670
14671                    while row != end_row {
14672                        if skip_soft_wrap {
14673                            row = display_map
14674                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14675                                .row();
14676                        } else if above {
14677                            row.0 -= 1;
14678                        } else {
14679                            row.0 += 1;
14680                        }
14681
14682                        if let Some(new_selection) = self.selections.build_columnar_selection(
14683                            &display_map,
14684                            row,
14685                            &positions,
14686                            selection.reversed,
14687                            &text_layout_details,
14688                        ) {
14689                            maybe_new_selection = Some(new_selection);
14690                            break;
14691                        }
14692                    }
14693
14694                    if let Some(new_selection) = maybe_new_selection {
14695                        group.stack.push(new_selection.id);
14696                        if above {
14697                            final_selections.push(new_selection);
14698                            final_selections.push(selection);
14699                        } else {
14700                            final_selections.push(selection);
14701                            final_selections.push(new_selection);
14702                        }
14703                    } else {
14704                        final_selections.push(selection);
14705                    }
14706                } else {
14707                    group.stack.pop();
14708                }
14709            } else {
14710                final_selections.push(selection);
14711            }
14712        }
14713
14714        self.change_selections(Default::default(), window, cx, |s| {
14715            s.select(final_selections);
14716        });
14717
14718        let final_selection_ids: HashSet<_> = self
14719            .selections
14720            .all::<Point>(&display_map)
14721            .iter()
14722            .map(|s| s.id)
14723            .collect();
14724        state.groups.retain_mut(|group| {
14725            // selections might get merged above so we remove invalid items from stacks
14726            group.stack.retain(|id| final_selection_ids.contains(id));
14727
14728            // single selection in stack can be treated as initial state
14729            group.stack.len() > 1
14730        });
14731
14732        if !state.groups.is_empty() {
14733            self.add_selections_state = Some(state);
14734        }
14735    }
14736
14737    fn select_match_ranges(
14738        &mut self,
14739        range: Range<MultiBufferOffset>,
14740        reversed: bool,
14741        replace_newest: bool,
14742        auto_scroll: Option<Autoscroll>,
14743        window: &mut Window,
14744        cx: &mut Context<Editor>,
14745    ) {
14746        self.unfold_ranges(
14747            std::slice::from_ref(&range),
14748            false,
14749            auto_scroll.is_some(),
14750            cx,
14751        );
14752        let effects = if let Some(scroll) = auto_scroll {
14753            SelectionEffects::scroll(scroll)
14754        } else {
14755            SelectionEffects::no_scroll()
14756        };
14757        self.change_selections(effects, window, cx, |s| {
14758            if replace_newest {
14759                s.delete(s.newest_anchor().id);
14760            }
14761            if reversed {
14762                s.insert_range(range.end..range.start);
14763            } else {
14764                s.insert_range(range);
14765            }
14766        });
14767    }
14768
14769    pub fn select_next_match_internal(
14770        &mut self,
14771        display_map: &DisplaySnapshot,
14772        replace_newest: bool,
14773        autoscroll: Option<Autoscroll>,
14774        window: &mut Window,
14775        cx: &mut Context<Self>,
14776    ) -> Result<()> {
14777        let buffer = display_map.buffer_snapshot();
14778        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14779        if let Some(mut select_next_state) = self.select_next_state.take() {
14780            let query = &select_next_state.query;
14781            if !select_next_state.done {
14782                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14783                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14784                let mut next_selected_range = None;
14785
14786                let bytes_after_last_selection =
14787                    buffer.bytes_in_range(last_selection.end..buffer.len());
14788                let bytes_before_first_selection =
14789                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
14790                let query_matches = query
14791                    .stream_find_iter(bytes_after_last_selection)
14792                    .map(|result| (last_selection.end, result))
14793                    .chain(
14794                        query
14795                            .stream_find_iter(bytes_before_first_selection)
14796                            .map(|result| (MultiBufferOffset(0), result)),
14797                    );
14798
14799                for (start_offset, query_match) in query_matches {
14800                    let query_match = query_match.unwrap(); // can only fail due to I/O
14801                    let offset_range =
14802                        start_offset + query_match.start()..start_offset + query_match.end();
14803
14804                    if !select_next_state.wordwise
14805                        || (!buffer.is_inside_word(offset_range.start, None)
14806                            && !buffer.is_inside_word(offset_range.end, None))
14807                    {
14808                        let idx = selections
14809                            .partition_point(|selection| selection.end <= offset_range.start);
14810                        let overlaps = selections
14811                            .get(idx)
14812                            .map_or(false, |selection| selection.start < offset_range.end);
14813
14814                        if !overlaps {
14815                            next_selected_range = Some(offset_range);
14816                            break;
14817                        }
14818                    }
14819                }
14820
14821                if let Some(next_selected_range) = next_selected_range {
14822                    self.select_match_ranges(
14823                        next_selected_range,
14824                        last_selection.reversed,
14825                        replace_newest,
14826                        autoscroll,
14827                        window,
14828                        cx,
14829                    );
14830                } else {
14831                    select_next_state.done = true;
14832                }
14833            }
14834
14835            self.select_next_state = Some(select_next_state);
14836        } else {
14837            let mut only_carets = true;
14838            let mut same_text_selected = true;
14839            let mut selected_text = None;
14840
14841            let mut selections_iter = selections.iter().peekable();
14842            while let Some(selection) = selections_iter.next() {
14843                if selection.start != selection.end {
14844                    only_carets = false;
14845                }
14846
14847                if same_text_selected {
14848                    if selected_text.is_none() {
14849                        selected_text =
14850                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14851                    }
14852
14853                    if let Some(next_selection) = selections_iter.peek() {
14854                        if next_selection.len() == selection.len() {
14855                            let next_selected_text = buffer
14856                                .text_for_range(next_selection.range())
14857                                .collect::<String>();
14858                            if Some(next_selected_text) != selected_text {
14859                                same_text_selected = false;
14860                                selected_text = None;
14861                            }
14862                        } else {
14863                            same_text_selected = false;
14864                            selected_text = None;
14865                        }
14866                    }
14867                }
14868            }
14869
14870            if only_carets {
14871                for selection in &mut selections {
14872                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14873                    selection.start = word_range.start;
14874                    selection.end = word_range.end;
14875                    selection.goal = SelectionGoal::None;
14876                    selection.reversed = false;
14877                    self.select_match_ranges(
14878                        selection.start..selection.end,
14879                        selection.reversed,
14880                        replace_newest,
14881                        autoscroll,
14882                        window,
14883                        cx,
14884                    );
14885                }
14886
14887                if selections.len() == 1 {
14888                    let selection = selections
14889                        .last()
14890                        .expect("ensured that there's only one selection");
14891                    let query = buffer
14892                        .text_for_range(selection.start..selection.end)
14893                        .collect::<String>();
14894                    let is_empty = query.is_empty();
14895                    let select_state = SelectNextState {
14896                        query: self.build_query(&[query], cx)?,
14897                        wordwise: true,
14898                        done: is_empty,
14899                    };
14900                    self.select_next_state = Some(select_state);
14901                } else {
14902                    self.select_next_state = None;
14903                }
14904            } else if let Some(selected_text) = selected_text {
14905                self.select_next_state = Some(SelectNextState {
14906                    query: self.build_query(&[selected_text], cx)?,
14907                    wordwise: false,
14908                    done: false,
14909                });
14910                self.select_next_match_internal(
14911                    display_map,
14912                    replace_newest,
14913                    autoscroll,
14914                    window,
14915                    cx,
14916                )?;
14917            }
14918        }
14919        Ok(())
14920    }
14921
14922    pub fn select_all_matches(
14923        &mut self,
14924        _action: &SelectAllMatches,
14925        window: &mut Window,
14926        cx: &mut Context<Self>,
14927    ) -> Result<()> {
14928        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14929
14930        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14931
14932        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14933        let Some(select_next_state) = self.select_next_state.as_mut() else {
14934            return Ok(());
14935        };
14936        if select_next_state.done {
14937            return Ok(());
14938        }
14939
14940        let mut new_selections = Vec::new();
14941
14942        let reversed = self
14943            .selections
14944            .oldest::<MultiBufferOffset>(&display_map)
14945            .reversed;
14946        let buffer = display_map.buffer_snapshot();
14947        let query_matches = select_next_state
14948            .query
14949            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
14950
14951        for query_match in query_matches.into_iter() {
14952            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14953            let offset_range = if reversed {
14954                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
14955            } else {
14956                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
14957            };
14958
14959            if !select_next_state.wordwise
14960                || (!buffer.is_inside_word(offset_range.start, None)
14961                    && !buffer.is_inside_word(offset_range.end, None))
14962            {
14963                new_selections.push(offset_range.start..offset_range.end);
14964            }
14965        }
14966
14967        select_next_state.done = true;
14968
14969        if new_selections.is_empty() {
14970            log::error!("bug: new_selections is empty in select_all_matches");
14971            return Ok(());
14972        }
14973
14974        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14975        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14976            selections.select_ranges(new_selections)
14977        });
14978
14979        Ok(())
14980    }
14981
14982    pub fn select_next(
14983        &mut self,
14984        action: &SelectNext,
14985        window: &mut Window,
14986        cx: &mut Context<Self>,
14987    ) -> Result<()> {
14988        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14989        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14990        self.select_next_match_internal(
14991            &display_map,
14992            action.replace_newest,
14993            Some(Autoscroll::newest()),
14994            window,
14995            cx,
14996        )?;
14997        Ok(())
14998    }
14999
15000    pub fn select_previous(
15001        &mut self,
15002        action: &SelectPrevious,
15003        window: &mut Window,
15004        cx: &mut Context<Self>,
15005    ) -> Result<()> {
15006        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15007        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15008        let buffer = display_map.buffer_snapshot();
15009        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15010        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15011            let query = &select_prev_state.query;
15012            if !select_prev_state.done {
15013                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15014                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15015                let mut next_selected_range = None;
15016                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15017                let bytes_before_last_selection =
15018                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15019                let bytes_after_first_selection =
15020                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15021                let query_matches = query
15022                    .stream_find_iter(bytes_before_last_selection)
15023                    .map(|result| (last_selection.start, result))
15024                    .chain(
15025                        query
15026                            .stream_find_iter(bytes_after_first_selection)
15027                            .map(|result| (buffer.len(), result)),
15028                    );
15029                for (end_offset, query_match) in query_matches {
15030                    let query_match = query_match.unwrap(); // can only fail due to I/O
15031                    let offset_range =
15032                        end_offset - query_match.end()..end_offset - query_match.start();
15033
15034                    if !select_prev_state.wordwise
15035                        || (!buffer.is_inside_word(offset_range.start, None)
15036                            && !buffer.is_inside_word(offset_range.end, None))
15037                    {
15038                        next_selected_range = Some(offset_range);
15039                        break;
15040                    }
15041                }
15042
15043                if let Some(next_selected_range) = next_selected_range {
15044                    self.select_match_ranges(
15045                        next_selected_range,
15046                        last_selection.reversed,
15047                        action.replace_newest,
15048                        Some(Autoscroll::newest()),
15049                        window,
15050                        cx,
15051                    );
15052                } else {
15053                    select_prev_state.done = true;
15054                }
15055            }
15056
15057            self.select_prev_state = Some(select_prev_state);
15058        } else {
15059            let mut only_carets = true;
15060            let mut same_text_selected = true;
15061            let mut selected_text = None;
15062
15063            let mut selections_iter = selections.iter().peekable();
15064            while let Some(selection) = selections_iter.next() {
15065                if selection.start != selection.end {
15066                    only_carets = false;
15067                }
15068
15069                if same_text_selected {
15070                    if selected_text.is_none() {
15071                        selected_text =
15072                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15073                    }
15074
15075                    if let Some(next_selection) = selections_iter.peek() {
15076                        if next_selection.len() == selection.len() {
15077                            let next_selected_text = buffer
15078                                .text_for_range(next_selection.range())
15079                                .collect::<String>();
15080                            if Some(next_selected_text) != selected_text {
15081                                same_text_selected = false;
15082                                selected_text = None;
15083                            }
15084                        } else {
15085                            same_text_selected = false;
15086                            selected_text = None;
15087                        }
15088                    }
15089                }
15090            }
15091
15092            if only_carets {
15093                for selection in &mut selections {
15094                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15095                    selection.start = word_range.start;
15096                    selection.end = word_range.end;
15097                    selection.goal = SelectionGoal::None;
15098                    selection.reversed = false;
15099                    self.select_match_ranges(
15100                        selection.start..selection.end,
15101                        selection.reversed,
15102                        action.replace_newest,
15103                        Some(Autoscroll::newest()),
15104                        window,
15105                        cx,
15106                    );
15107                }
15108                if selections.len() == 1 {
15109                    let selection = selections
15110                        .last()
15111                        .expect("ensured that there's only one selection");
15112                    let query = buffer
15113                        .text_for_range(selection.start..selection.end)
15114                        .collect::<String>();
15115                    let is_empty = query.is_empty();
15116                    let select_state = SelectNextState {
15117                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15118                        wordwise: true,
15119                        done: is_empty,
15120                    };
15121                    self.select_prev_state = Some(select_state);
15122                } else {
15123                    self.select_prev_state = None;
15124                }
15125            } else if let Some(selected_text) = selected_text {
15126                self.select_prev_state = Some(SelectNextState {
15127                    query: self
15128                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15129                    wordwise: false,
15130                    done: false,
15131                });
15132                self.select_previous(action, window, cx)?;
15133            }
15134        }
15135        Ok(())
15136    }
15137
15138    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15139    /// setting the case sensitivity based on the global
15140    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15141    /// editor's settings.
15142    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15143    where
15144        I: IntoIterator<Item = P>,
15145        P: AsRef<[u8]>,
15146    {
15147        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
15148            || EditorSettings::get_global(cx).search.case_sensitive,
15149            |value| value,
15150        );
15151
15152        let mut builder = AhoCorasickBuilder::new();
15153        builder.ascii_case_insensitive(!case_sensitive);
15154        builder.build(patterns)
15155    }
15156
15157    pub fn find_next_match(
15158        &mut self,
15159        _: &FindNextMatch,
15160        window: &mut Window,
15161        cx: &mut Context<Self>,
15162    ) -> Result<()> {
15163        let selections = self.selections.disjoint_anchors_arc();
15164        match selections.first() {
15165            Some(first) if selections.len() >= 2 => {
15166                self.change_selections(Default::default(), window, cx, |s| {
15167                    s.select_ranges([first.range()]);
15168                });
15169            }
15170            _ => self.select_next(
15171                &SelectNext {
15172                    replace_newest: true,
15173                },
15174                window,
15175                cx,
15176            )?,
15177        }
15178        Ok(())
15179    }
15180
15181    pub fn find_previous_match(
15182        &mut self,
15183        _: &FindPreviousMatch,
15184        window: &mut Window,
15185        cx: &mut Context<Self>,
15186    ) -> Result<()> {
15187        let selections = self.selections.disjoint_anchors_arc();
15188        match selections.last() {
15189            Some(last) if selections.len() >= 2 => {
15190                self.change_selections(Default::default(), window, cx, |s| {
15191                    s.select_ranges([last.range()]);
15192                });
15193            }
15194            _ => self.select_previous(
15195                &SelectPrevious {
15196                    replace_newest: true,
15197                },
15198                window,
15199                cx,
15200            )?,
15201        }
15202        Ok(())
15203    }
15204
15205    pub fn toggle_comments(
15206        &mut self,
15207        action: &ToggleComments,
15208        window: &mut Window,
15209        cx: &mut Context<Self>,
15210    ) {
15211        if self.read_only(cx) {
15212            return;
15213        }
15214        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15215        let text_layout_details = &self.text_layout_details(window);
15216        self.transact(window, cx, |this, window, cx| {
15217            let mut selections = this
15218                .selections
15219                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15220            let mut edits = Vec::new();
15221            let mut selection_edit_ranges = Vec::new();
15222            let mut last_toggled_row = None;
15223            let snapshot = this.buffer.read(cx).read(cx);
15224            let empty_str: Arc<str> = Arc::default();
15225            let mut suffixes_inserted = Vec::new();
15226            let ignore_indent = action.ignore_indent;
15227
15228            fn comment_prefix_range(
15229                snapshot: &MultiBufferSnapshot,
15230                row: MultiBufferRow,
15231                comment_prefix: &str,
15232                comment_prefix_whitespace: &str,
15233                ignore_indent: bool,
15234            ) -> Range<Point> {
15235                let indent_size = if ignore_indent {
15236                    0
15237                } else {
15238                    snapshot.indent_size_for_line(row).len
15239                };
15240
15241                let start = Point::new(row.0, indent_size);
15242
15243                let mut line_bytes = snapshot
15244                    .bytes_in_range(start..snapshot.max_point())
15245                    .flatten()
15246                    .copied();
15247
15248                // If this line currently begins with the line comment prefix, then record
15249                // the range containing the prefix.
15250                if line_bytes
15251                    .by_ref()
15252                    .take(comment_prefix.len())
15253                    .eq(comment_prefix.bytes())
15254                {
15255                    // Include any whitespace that matches the comment prefix.
15256                    let matching_whitespace_len = line_bytes
15257                        .zip(comment_prefix_whitespace.bytes())
15258                        .take_while(|(a, b)| a == b)
15259                        .count() as u32;
15260                    let end = Point::new(
15261                        start.row,
15262                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15263                    );
15264                    start..end
15265                } else {
15266                    start..start
15267                }
15268            }
15269
15270            fn comment_suffix_range(
15271                snapshot: &MultiBufferSnapshot,
15272                row: MultiBufferRow,
15273                comment_suffix: &str,
15274                comment_suffix_has_leading_space: bool,
15275            ) -> Range<Point> {
15276                let end = Point::new(row.0, snapshot.line_len(row));
15277                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15278
15279                let mut line_end_bytes = snapshot
15280                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15281                    .flatten()
15282                    .copied();
15283
15284                let leading_space_len = if suffix_start_column > 0
15285                    && line_end_bytes.next() == Some(b' ')
15286                    && comment_suffix_has_leading_space
15287                {
15288                    1
15289                } else {
15290                    0
15291                };
15292
15293                // If this line currently begins with the line comment prefix, then record
15294                // the range containing the prefix.
15295                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15296                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15297                    start..end
15298                } else {
15299                    end..end
15300                }
15301            }
15302
15303            // TODO: Handle selections that cross excerpts
15304            for selection in &mut selections {
15305                let start_column = snapshot
15306                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15307                    .len;
15308                let language = if let Some(language) =
15309                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15310                {
15311                    language
15312                } else {
15313                    continue;
15314                };
15315
15316                selection_edit_ranges.clear();
15317
15318                // If multiple selections contain a given row, avoid processing that
15319                // row more than once.
15320                let mut start_row = MultiBufferRow(selection.start.row);
15321                if last_toggled_row == Some(start_row) {
15322                    start_row = start_row.next_row();
15323                }
15324                let end_row =
15325                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15326                        MultiBufferRow(selection.end.row - 1)
15327                    } else {
15328                        MultiBufferRow(selection.end.row)
15329                    };
15330                last_toggled_row = Some(end_row);
15331
15332                if start_row > end_row {
15333                    continue;
15334                }
15335
15336                // If the language has line comments, toggle those.
15337                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15338
15339                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15340                if ignore_indent {
15341                    full_comment_prefixes = full_comment_prefixes
15342                        .into_iter()
15343                        .map(|s| Arc::from(s.trim_end()))
15344                        .collect();
15345                }
15346
15347                if !full_comment_prefixes.is_empty() {
15348                    let first_prefix = full_comment_prefixes
15349                        .first()
15350                        .expect("prefixes is non-empty");
15351                    let prefix_trimmed_lengths = full_comment_prefixes
15352                        .iter()
15353                        .map(|p| p.trim_end_matches(' ').len())
15354                        .collect::<SmallVec<[usize; 4]>>();
15355
15356                    let mut all_selection_lines_are_comments = true;
15357
15358                    for row in start_row.0..=end_row.0 {
15359                        let row = MultiBufferRow(row);
15360                        if start_row < end_row && snapshot.is_line_blank(row) {
15361                            continue;
15362                        }
15363
15364                        let prefix_range = full_comment_prefixes
15365                            .iter()
15366                            .zip(prefix_trimmed_lengths.iter().copied())
15367                            .map(|(prefix, trimmed_prefix_len)| {
15368                                comment_prefix_range(
15369                                    snapshot.deref(),
15370                                    row,
15371                                    &prefix[..trimmed_prefix_len],
15372                                    &prefix[trimmed_prefix_len..],
15373                                    ignore_indent,
15374                                )
15375                            })
15376                            .max_by_key(|range| range.end.column - range.start.column)
15377                            .expect("prefixes is non-empty");
15378
15379                        if prefix_range.is_empty() {
15380                            all_selection_lines_are_comments = false;
15381                        }
15382
15383                        selection_edit_ranges.push(prefix_range);
15384                    }
15385
15386                    if all_selection_lines_are_comments {
15387                        edits.extend(
15388                            selection_edit_ranges
15389                                .iter()
15390                                .cloned()
15391                                .map(|range| (range, empty_str.clone())),
15392                        );
15393                    } else {
15394                        let min_column = selection_edit_ranges
15395                            .iter()
15396                            .map(|range| range.start.column)
15397                            .min()
15398                            .unwrap_or(0);
15399                        edits.extend(selection_edit_ranges.iter().map(|range| {
15400                            let position = Point::new(range.start.row, min_column);
15401                            (position..position, first_prefix.clone())
15402                        }));
15403                    }
15404                } else if let Some(BlockCommentConfig {
15405                    start: full_comment_prefix,
15406                    end: comment_suffix,
15407                    ..
15408                }) = language.block_comment()
15409                {
15410                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15411                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15412                    let prefix_range = comment_prefix_range(
15413                        snapshot.deref(),
15414                        start_row,
15415                        comment_prefix,
15416                        comment_prefix_whitespace,
15417                        ignore_indent,
15418                    );
15419                    let suffix_range = comment_suffix_range(
15420                        snapshot.deref(),
15421                        end_row,
15422                        comment_suffix.trim_start_matches(' '),
15423                        comment_suffix.starts_with(' '),
15424                    );
15425
15426                    if prefix_range.is_empty() || suffix_range.is_empty() {
15427                        edits.push((
15428                            prefix_range.start..prefix_range.start,
15429                            full_comment_prefix.clone(),
15430                        ));
15431                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15432                        suffixes_inserted.push((end_row, comment_suffix.len()));
15433                    } else {
15434                        edits.push((prefix_range, empty_str.clone()));
15435                        edits.push((suffix_range, empty_str.clone()));
15436                    }
15437                } else {
15438                    continue;
15439                }
15440            }
15441
15442            drop(snapshot);
15443            this.buffer.update(cx, |buffer, cx| {
15444                buffer.edit(edits, None, cx);
15445            });
15446
15447            // Adjust selections so that they end before any comment suffixes that
15448            // were inserted.
15449            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15450            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15451            let snapshot = this.buffer.read(cx).read(cx);
15452            for selection in &mut selections {
15453                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15454                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15455                        Ordering::Less => {
15456                            suffixes_inserted.next();
15457                            continue;
15458                        }
15459                        Ordering::Greater => break,
15460                        Ordering::Equal => {
15461                            if selection.end.column == snapshot.line_len(row) {
15462                                if selection.is_empty() {
15463                                    selection.start.column -= suffix_len as u32;
15464                                }
15465                                selection.end.column -= suffix_len as u32;
15466                            }
15467                            break;
15468                        }
15469                    }
15470                }
15471            }
15472
15473            drop(snapshot);
15474            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15475
15476            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15477            let selections_on_single_row = selections.windows(2).all(|selections| {
15478                selections[0].start.row == selections[1].start.row
15479                    && selections[0].end.row == selections[1].end.row
15480                    && selections[0].start.row == selections[0].end.row
15481            });
15482            let selections_selecting = selections
15483                .iter()
15484                .any(|selection| selection.start != selection.end);
15485            let advance_downwards = action.advance_downwards
15486                && selections_on_single_row
15487                && !selections_selecting
15488                && !matches!(this.mode, EditorMode::SingleLine);
15489
15490            if advance_downwards {
15491                let snapshot = this.buffer.read(cx).snapshot(cx);
15492
15493                this.change_selections(Default::default(), window, cx, |s| {
15494                    s.move_cursors_with(|display_snapshot, display_point, _| {
15495                        let mut point = display_point.to_point(display_snapshot);
15496                        point.row += 1;
15497                        point = snapshot.clip_point(point, Bias::Left);
15498                        let display_point = point.to_display_point(display_snapshot);
15499                        let goal = SelectionGoal::HorizontalPosition(
15500                            display_snapshot
15501                                .x_for_display_point(display_point, text_layout_details)
15502                                .into(),
15503                        );
15504                        (display_point, goal)
15505                    })
15506                });
15507            }
15508        });
15509    }
15510
15511    pub fn select_enclosing_symbol(
15512        &mut self,
15513        _: &SelectEnclosingSymbol,
15514        window: &mut Window,
15515        cx: &mut Context<Self>,
15516    ) {
15517        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15518
15519        let buffer = self.buffer.read(cx).snapshot(cx);
15520        let old_selections = self
15521            .selections
15522            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15523            .into_boxed_slice();
15524
15525        fn update_selection(
15526            selection: &Selection<MultiBufferOffset>,
15527            buffer_snap: &MultiBufferSnapshot,
15528        ) -> Option<Selection<MultiBufferOffset>> {
15529            let cursor = selection.head();
15530            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15531            for symbol in symbols.iter().rev() {
15532                let start = symbol.range.start.to_offset(buffer_snap);
15533                let end = symbol.range.end.to_offset(buffer_snap);
15534                let new_range = start..end;
15535                if start < selection.start || end > selection.end {
15536                    return Some(Selection {
15537                        id: selection.id,
15538                        start: new_range.start,
15539                        end: new_range.end,
15540                        goal: SelectionGoal::None,
15541                        reversed: selection.reversed,
15542                    });
15543                }
15544            }
15545            None
15546        }
15547
15548        let mut selected_larger_symbol = false;
15549        let new_selections = old_selections
15550            .iter()
15551            .map(|selection| match update_selection(selection, &buffer) {
15552                Some(new_selection) => {
15553                    if new_selection.range() != selection.range() {
15554                        selected_larger_symbol = true;
15555                    }
15556                    new_selection
15557                }
15558                None => selection.clone(),
15559            })
15560            .collect::<Vec<_>>();
15561
15562        if selected_larger_symbol {
15563            self.change_selections(Default::default(), window, cx, |s| {
15564                s.select(new_selections);
15565            });
15566        }
15567    }
15568
15569    pub fn select_larger_syntax_node(
15570        &mut self,
15571        _: &SelectLargerSyntaxNode,
15572        window: &mut Window,
15573        cx: &mut Context<Self>,
15574    ) {
15575        let Some(visible_row_count) = self.visible_row_count() else {
15576            return;
15577        };
15578        let old_selections: Box<[_]> = self
15579            .selections
15580            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15581            .into();
15582        if old_selections.is_empty() {
15583            return;
15584        }
15585
15586        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15587
15588        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15589        let buffer = self.buffer.read(cx).snapshot(cx);
15590
15591        let mut selected_larger_node = false;
15592        let mut new_selections = old_selections
15593            .iter()
15594            .map(|selection| {
15595                let old_range = selection.start..selection.end;
15596
15597                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15598                    // manually select word at selection
15599                    if ["string_content", "inline"].contains(&node.kind()) {
15600                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15601                        // ignore if word is already selected
15602                        if !word_range.is_empty() && old_range != word_range {
15603                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15604                            // only select word if start and end point belongs to same word
15605                            if word_range == last_word_range {
15606                                selected_larger_node = true;
15607                                return Selection {
15608                                    id: selection.id,
15609                                    start: word_range.start,
15610                                    end: word_range.end,
15611                                    goal: SelectionGoal::None,
15612                                    reversed: selection.reversed,
15613                                };
15614                            }
15615                        }
15616                    }
15617                }
15618
15619                let mut new_range = old_range.clone();
15620                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15621                    new_range = range;
15622                    if !node.is_named() {
15623                        continue;
15624                    }
15625                    if !display_map.intersects_fold(new_range.start)
15626                        && !display_map.intersects_fold(new_range.end)
15627                    {
15628                        break;
15629                    }
15630                }
15631
15632                selected_larger_node |= new_range != old_range;
15633                Selection {
15634                    id: selection.id,
15635                    start: new_range.start,
15636                    end: new_range.end,
15637                    goal: SelectionGoal::None,
15638                    reversed: selection.reversed,
15639                }
15640            })
15641            .collect::<Vec<_>>();
15642
15643        if !selected_larger_node {
15644            return; // don't put this call in the history
15645        }
15646
15647        // scroll based on transformation done to the last selection created by the user
15648        let (last_old, last_new) = old_selections
15649            .last()
15650            .zip(new_selections.last().cloned())
15651            .expect("old_selections isn't empty");
15652
15653        // revert selection
15654        let is_selection_reversed = {
15655            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15656            new_selections.last_mut().expect("checked above").reversed =
15657                should_newest_selection_be_reversed;
15658            should_newest_selection_be_reversed
15659        };
15660
15661        if selected_larger_node {
15662            self.select_syntax_node_history.disable_clearing = true;
15663            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15664                s.select(new_selections.clone());
15665            });
15666            self.select_syntax_node_history.disable_clearing = false;
15667        }
15668
15669        let start_row = last_new.start.to_display_point(&display_map).row().0;
15670        let end_row = last_new.end.to_display_point(&display_map).row().0;
15671        let selection_height = end_row - start_row + 1;
15672        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15673
15674        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15675        let scroll_behavior = if fits_on_the_screen {
15676            self.request_autoscroll(Autoscroll::fit(), cx);
15677            SelectSyntaxNodeScrollBehavior::FitSelection
15678        } else if is_selection_reversed {
15679            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15680            SelectSyntaxNodeScrollBehavior::CursorTop
15681        } else {
15682            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15683            SelectSyntaxNodeScrollBehavior::CursorBottom
15684        };
15685
15686        self.select_syntax_node_history.push((
15687            old_selections,
15688            scroll_behavior,
15689            is_selection_reversed,
15690        ));
15691    }
15692
15693    pub fn select_smaller_syntax_node(
15694        &mut self,
15695        _: &SelectSmallerSyntaxNode,
15696        window: &mut Window,
15697        cx: &mut Context<Self>,
15698    ) {
15699        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15700
15701        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15702            self.select_syntax_node_history.pop()
15703        {
15704            if let Some(selection) = selections.last_mut() {
15705                selection.reversed = is_selection_reversed;
15706            }
15707
15708            self.select_syntax_node_history.disable_clearing = true;
15709            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15710                s.select(selections.to_vec());
15711            });
15712            self.select_syntax_node_history.disable_clearing = false;
15713
15714            match scroll_behavior {
15715                SelectSyntaxNodeScrollBehavior::CursorTop => {
15716                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15717                }
15718                SelectSyntaxNodeScrollBehavior::FitSelection => {
15719                    self.request_autoscroll(Autoscroll::fit(), cx);
15720                }
15721                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15722                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15723                }
15724            }
15725        }
15726    }
15727
15728    pub fn unwrap_syntax_node(
15729        &mut self,
15730        _: &UnwrapSyntaxNode,
15731        window: &mut Window,
15732        cx: &mut Context<Self>,
15733    ) {
15734        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15735
15736        let buffer = self.buffer.read(cx).snapshot(cx);
15737        let selections = self
15738            .selections
15739            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15740            .into_iter()
15741            // subtracting the offset requires sorting
15742            .sorted_by_key(|i| i.start);
15743
15744        let full_edits = selections
15745            .into_iter()
15746            .filter_map(|selection| {
15747                let child = if selection.is_empty()
15748                    && let Some((_, ancestor_range)) =
15749                        buffer.syntax_ancestor(selection.start..selection.end)
15750                {
15751                    ancestor_range
15752                } else {
15753                    selection.range()
15754                };
15755
15756                let mut parent = child.clone();
15757                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15758                    parent = ancestor_range;
15759                    if parent.start < child.start || parent.end > child.end {
15760                        break;
15761                    }
15762                }
15763
15764                if parent == child {
15765                    return None;
15766                }
15767                let text = buffer.text_for_range(child).collect::<String>();
15768                Some((selection.id, parent, text))
15769            })
15770            .collect::<Vec<_>>();
15771        if full_edits.is_empty() {
15772            return;
15773        }
15774
15775        self.transact(window, cx, |this, window, cx| {
15776            this.buffer.update(cx, |buffer, cx| {
15777                buffer.edit(
15778                    full_edits
15779                        .iter()
15780                        .map(|(_, p, t)| (p.clone(), t.clone()))
15781                        .collect::<Vec<_>>(),
15782                    None,
15783                    cx,
15784                );
15785            });
15786            this.change_selections(Default::default(), window, cx, |s| {
15787                let mut offset = 0;
15788                let mut selections = vec![];
15789                for (id, parent, text) in full_edits {
15790                    let start = parent.start - offset;
15791                    offset += (parent.end - parent.start) - text.len();
15792                    selections.push(Selection {
15793                        id,
15794                        start,
15795                        end: start + text.len(),
15796                        reversed: false,
15797                        goal: Default::default(),
15798                    });
15799                }
15800                s.select(selections);
15801            });
15802        });
15803    }
15804
15805    pub fn select_next_syntax_node(
15806        &mut self,
15807        _: &SelectNextSyntaxNode,
15808        window: &mut Window,
15809        cx: &mut Context<Self>,
15810    ) {
15811        let old_selections: Box<[_]> = self
15812            .selections
15813            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15814            .into();
15815        if old_selections.is_empty() {
15816            return;
15817        }
15818
15819        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15820
15821        let buffer = self.buffer.read(cx).snapshot(cx);
15822        let mut selected_sibling = false;
15823
15824        let new_selections = old_selections
15825            .iter()
15826            .map(|selection| {
15827                let old_range = selection.start..selection.end;
15828
15829                let old_range =
15830                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15831                let excerpt = buffer.excerpt_containing(old_range.clone());
15832
15833                if let Some(mut excerpt) = excerpt
15834                    && let Some(node) = excerpt
15835                        .buffer()
15836                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
15837                {
15838                    let new_range = excerpt.map_range_from_buffer(
15839                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15840                    );
15841                    selected_sibling = true;
15842                    Selection {
15843                        id: selection.id,
15844                        start: new_range.start,
15845                        end: new_range.end,
15846                        goal: SelectionGoal::None,
15847                        reversed: selection.reversed,
15848                    }
15849                } else {
15850                    selection.clone()
15851                }
15852            })
15853            .collect::<Vec<_>>();
15854
15855        if selected_sibling {
15856            self.change_selections(
15857                SelectionEffects::scroll(Autoscroll::fit()),
15858                window,
15859                cx,
15860                |s| {
15861                    s.select(new_selections);
15862                },
15863            );
15864        }
15865    }
15866
15867    pub fn select_prev_syntax_node(
15868        &mut self,
15869        _: &SelectPreviousSyntaxNode,
15870        window: &mut Window,
15871        cx: &mut Context<Self>,
15872    ) {
15873        let old_selections: Box<[_]> = self
15874            .selections
15875            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15876            .into();
15877        if old_selections.is_empty() {
15878            return;
15879        }
15880
15881        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15882
15883        let buffer = self.buffer.read(cx).snapshot(cx);
15884        let mut selected_sibling = false;
15885
15886        let new_selections = old_selections
15887            .iter()
15888            .map(|selection| {
15889                let old_range = selection.start..selection.end;
15890                let old_range =
15891                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15892                let excerpt = buffer.excerpt_containing(old_range.clone());
15893
15894                if let Some(mut excerpt) = excerpt
15895                    && let Some(node) = excerpt
15896                        .buffer()
15897                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
15898                {
15899                    let new_range = excerpt.map_range_from_buffer(
15900                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15901                    );
15902                    selected_sibling = true;
15903                    Selection {
15904                        id: selection.id,
15905                        start: new_range.start,
15906                        end: new_range.end,
15907                        goal: SelectionGoal::None,
15908                        reversed: selection.reversed,
15909                    }
15910                } else {
15911                    selection.clone()
15912                }
15913            })
15914            .collect::<Vec<_>>();
15915
15916        if selected_sibling {
15917            self.change_selections(
15918                SelectionEffects::scroll(Autoscroll::fit()),
15919                window,
15920                cx,
15921                |s| {
15922                    s.select(new_selections);
15923                },
15924            );
15925        }
15926    }
15927
15928    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15929        if !EditorSettings::get_global(cx).gutter.runnables {
15930            self.clear_tasks();
15931            return Task::ready(());
15932        }
15933        let project = self.project().map(Entity::downgrade);
15934        let task_sources = self.lsp_task_sources(cx);
15935        let multi_buffer = self.buffer.downgrade();
15936        cx.spawn_in(window, async move |editor, cx| {
15937            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15938            let Some(project) = project.and_then(|p| p.upgrade()) else {
15939                return;
15940            };
15941            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15942                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15943            }) else {
15944                return;
15945            };
15946
15947            let hide_runnables = project
15948                .update(cx, |project, _| project.is_via_collab())
15949                .unwrap_or(true);
15950            if hide_runnables {
15951                return;
15952            }
15953            let new_rows =
15954                cx.background_spawn({
15955                    let snapshot = display_snapshot.clone();
15956                    async move {
15957                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15958                    }
15959                })
15960                    .await;
15961            let Ok(lsp_tasks) =
15962                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15963            else {
15964                return;
15965            };
15966            let lsp_tasks = lsp_tasks.await;
15967
15968            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15969                lsp_tasks
15970                    .into_iter()
15971                    .flat_map(|(kind, tasks)| {
15972                        tasks.into_iter().filter_map(move |(location, task)| {
15973                            Some((kind.clone(), location?, task))
15974                        })
15975                    })
15976                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15977                        let buffer = location.target.buffer;
15978                        let buffer_snapshot = buffer.read(cx).snapshot();
15979                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15980                            |(excerpt_id, snapshot, _)| {
15981                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15982                                    display_snapshot
15983                                        .buffer_snapshot()
15984                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15985                                } else {
15986                                    None
15987                                }
15988                            },
15989                        );
15990                        if let Some(offset) = offset {
15991                            let task_buffer_range =
15992                                location.target.range.to_point(&buffer_snapshot);
15993                            let context_buffer_range =
15994                                task_buffer_range.to_offset(&buffer_snapshot);
15995                            let context_range = BufferOffset(context_buffer_range.start)
15996                                ..BufferOffset(context_buffer_range.end);
15997
15998                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15999                                .or_insert_with(|| RunnableTasks {
16000                                    templates: Vec::new(),
16001                                    offset,
16002                                    column: task_buffer_range.start.column,
16003                                    extra_variables: HashMap::default(),
16004                                    context_range,
16005                                })
16006                                .templates
16007                                .push((kind, task.original_task().clone()));
16008                        }
16009
16010                        acc
16011                    })
16012            }) else {
16013                return;
16014            };
16015
16016            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16017                buffer.language_settings(cx).tasks.prefer_lsp
16018            }) else {
16019                return;
16020            };
16021
16022            let rows = Self::runnable_rows(
16023                project,
16024                display_snapshot,
16025                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16026                new_rows,
16027                cx.clone(),
16028            )
16029            .await;
16030            editor
16031                .update(cx, |editor, _| {
16032                    editor.clear_tasks();
16033                    for (key, mut value) in rows {
16034                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16035                            value.templates.extend(lsp_tasks.templates);
16036                        }
16037
16038                        editor.insert_tasks(key, value);
16039                    }
16040                    for (key, value) in lsp_tasks_by_rows {
16041                        editor.insert_tasks(key, value);
16042                    }
16043                })
16044                .ok();
16045        })
16046    }
16047    fn fetch_runnable_ranges(
16048        snapshot: &DisplaySnapshot,
16049        range: Range<Anchor>,
16050    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16051        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16052    }
16053
16054    fn runnable_rows(
16055        project: Entity<Project>,
16056        snapshot: DisplaySnapshot,
16057        prefer_lsp: bool,
16058        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16059        cx: AsyncWindowContext,
16060    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16061        cx.spawn(async move |cx| {
16062            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16063            for (run_range, mut runnable) in runnable_ranges {
16064                let Some(tasks) = cx
16065                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16066                    .ok()
16067                else {
16068                    continue;
16069                };
16070                let mut tasks = tasks.await;
16071
16072                if prefer_lsp {
16073                    tasks.retain(|(task_kind, _)| {
16074                        !matches!(task_kind, TaskSourceKind::Language { .. })
16075                    });
16076                }
16077                if tasks.is_empty() {
16078                    continue;
16079                }
16080
16081                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16082                let Some(row) = snapshot
16083                    .buffer_snapshot()
16084                    .buffer_line_for_row(MultiBufferRow(point.row))
16085                    .map(|(_, range)| range.start.row)
16086                else {
16087                    continue;
16088                };
16089
16090                let context_range =
16091                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16092                runnable_rows.push((
16093                    (runnable.buffer_id, row),
16094                    RunnableTasks {
16095                        templates: tasks,
16096                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16097                        context_range,
16098                        column: point.column,
16099                        extra_variables: runnable.extra_captures,
16100                    },
16101                ));
16102            }
16103            runnable_rows
16104        })
16105    }
16106
16107    fn templates_with_tags(
16108        project: &Entity<Project>,
16109        runnable: &mut Runnable,
16110        cx: &mut App,
16111    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16112        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16113            let (worktree_id, file) = project
16114                .buffer_for_id(runnable.buffer, cx)
16115                .and_then(|buffer| buffer.read(cx).file())
16116                .map(|file| (file.worktree_id(cx), file.clone()))
16117                .unzip();
16118
16119            (
16120                project.task_store().read(cx).task_inventory().cloned(),
16121                worktree_id,
16122                file,
16123            )
16124        });
16125
16126        let tags = mem::take(&mut runnable.tags);
16127        let language = runnable.language.clone();
16128        cx.spawn(async move |cx| {
16129            let mut templates_with_tags = Vec::new();
16130            if let Some(inventory) = inventory {
16131                for RunnableTag(tag) in tags {
16132                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16133                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16134                    }) else {
16135                        return templates_with_tags;
16136                    };
16137                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16138                        move |(_, template)| {
16139                            template.tags.iter().any(|source_tag| source_tag == &tag)
16140                        },
16141                    ));
16142                }
16143            }
16144            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16145
16146            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16147                // Strongest source wins; if we have worktree tag binding, prefer that to
16148                // global and language bindings;
16149                // if we have a global binding, prefer that to language binding.
16150                let first_mismatch = templates_with_tags
16151                    .iter()
16152                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16153                if let Some(index) = first_mismatch {
16154                    templates_with_tags.truncate(index);
16155                }
16156            }
16157
16158            templates_with_tags
16159        })
16160    }
16161
16162    pub fn move_to_enclosing_bracket(
16163        &mut self,
16164        _: &MoveToEnclosingBracket,
16165        window: &mut Window,
16166        cx: &mut Context<Self>,
16167    ) {
16168        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16169        self.change_selections(Default::default(), window, cx, |s| {
16170            s.move_offsets_with(|snapshot, selection| {
16171                let Some(enclosing_bracket_ranges) =
16172                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16173                else {
16174                    return;
16175                };
16176
16177                let mut best_length = usize::MAX;
16178                let mut best_inside = false;
16179                let mut best_in_bracket_range = false;
16180                let mut best_destination = None;
16181                for (open, close) in enclosing_bracket_ranges {
16182                    let close = close.to_inclusive();
16183                    let length = *close.end() - open.start;
16184                    let inside = selection.start >= open.end && selection.end <= *close.start();
16185                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16186                        || close.contains(&selection.head());
16187
16188                    // If best is next to a bracket and current isn't, skip
16189                    if !in_bracket_range && best_in_bracket_range {
16190                        continue;
16191                    }
16192
16193                    // Prefer smaller lengths unless best is inside and current isn't
16194                    if length > best_length && (best_inside || !inside) {
16195                        continue;
16196                    }
16197
16198                    best_length = length;
16199                    best_inside = inside;
16200                    best_in_bracket_range = in_bracket_range;
16201                    best_destination = Some(
16202                        if close.contains(&selection.start) && close.contains(&selection.end) {
16203                            if inside { open.end } else { open.start }
16204                        } else if inside {
16205                            *close.start()
16206                        } else {
16207                            *close.end()
16208                        },
16209                    );
16210                }
16211
16212                if let Some(destination) = best_destination {
16213                    selection.collapse_to(destination, SelectionGoal::None);
16214                }
16215            })
16216        });
16217    }
16218
16219    pub fn undo_selection(
16220        &mut self,
16221        _: &UndoSelection,
16222        window: &mut Window,
16223        cx: &mut Context<Self>,
16224    ) {
16225        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16226        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16227            self.selection_history.mode = SelectionHistoryMode::Undoing;
16228            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16229                this.end_selection(window, cx);
16230                this.change_selections(
16231                    SelectionEffects::scroll(Autoscroll::newest()),
16232                    window,
16233                    cx,
16234                    |s| s.select_anchors(entry.selections.to_vec()),
16235                );
16236            });
16237            self.selection_history.mode = SelectionHistoryMode::Normal;
16238
16239            self.select_next_state = entry.select_next_state;
16240            self.select_prev_state = entry.select_prev_state;
16241            self.add_selections_state = entry.add_selections_state;
16242        }
16243    }
16244
16245    pub fn redo_selection(
16246        &mut self,
16247        _: &RedoSelection,
16248        window: &mut Window,
16249        cx: &mut Context<Self>,
16250    ) {
16251        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16252        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16253            self.selection_history.mode = SelectionHistoryMode::Redoing;
16254            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16255                this.end_selection(window, cx);
16256                this.change_selections(
16257                    SelectionEffects::scroll(Autoscroll::newest()),
16258                    window,
16259                    cx,
16260                    |s| s.select_anchors(entry.selections.to_vec()),
16261                );
16262            });
16263            self.selection_history.mode = SelectionHistoryMode::Normal;
16264
16265            self.select_next_state = entry.select_next_state;
16266            self.select_prev_state = entry.select_prev_state;
16267            self.add_selections_state = entry.add_selections_state;
16268        }
16269    }
16270
16271    pub fn expand_excerpts(
16272        &mut self,
16273        action: &ExpandExcerpts,
16274        _: &mut Window,
16275        cx: &mut Context<Self>,
16276    ) {
16277        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16278    }
16279
16280    pub fn expand_excerpts_down(
16281        &mut self,
16282        action: &ExpandExcerptsDown,
16283        _: &mut Window,
16284        cx: &mut Context<Self>,
16285    ) {
16286        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16287    }
16288
16289    pub fn expand_excerpts_up(
16290        &mut self,
16291        action: &ExpandExcerptsUp,
16292        _: &mut Window,
16293        cx: &mut Context<Self>,
16294    ) {
16295        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16296    }
16297
16298    pub fn expand_excerpts_for_direction(
16299        &mut self,
16300        lines: u32,
16301        direction: ExpandExcerptDirection,
16302
16303        cx: &mut Context<Self>,
16304    ) {
16305        let selections = self.selections.disjoint_anchors_arc();
16306
16307        let lines = if lines == 0 {
16308            EditorSettings::get_global(cx).expand_excerpt_lines
16309        } else {
16310            lines
16311        };
16312
16313        self.buffer.update(cx, |buffer, cx| {
16314            let snapshot = buffer.snapshot(cx);
16315            let mut excerpt_ids = selections
16316                .iter()
16317                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16318                .collect::<Vec<_>>();
16319            excerpt_ids.sort();
16320            excerpt_ids.dedup();
16321            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16322        })
16323    }
16324
16325    pub fn expand_excerpt(
16326        &mut self,
16327        excerpt: ExcerptId,
16328        direction: ExpandExcerptDirection,
16329        window: &mut Window,
16330        cx: &mut Context<Self>,
16331    ) {
16332        let current_scroll_position = self.scroll_position(cx);
16333        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16334        let mut scroll = None;
16335
16336        if direction == ExpandExcerptDirection::Down {
16337            let multi_buffer = self.buffer.read(cx);
16338            let snapshot = multi_buffer.snapshot(cx);
16339            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16340                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16341                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16342            {
16343                let buffer_snapshot = buffer.read(cx).snapshot();
16344                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16345                let last_row = buffer_snapshot.max_point().row;
16346                let lines_below = last_row.saturating_sub(excerpt_end_row);
16347                if lines_below >= lines_to_expand {
16348                    scroll = Some(
16349                        current_scroll_position
16350                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16351                    );
16352                }
16353            }
16354        }
16355        if direction == ExpandExcerptDirection::Up
16356            && self
16357                .buffer
16358                .read(cx)
16359                .snapshot(cx)
16360                .excerpt_before(excerpt)
16361                .is_none()
16362        {
16363            scroll = Some(current_scroll_position);
16364        }
16365
16366        self.buffer.update(cx, |buffer, cx| {
16367            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16368        });
16369
16370        if let Some(new_scroll_position) = scroll {
16371            self.set_scroll_position(new_scroll_position, window, cx);
16372        }
16373    }
16374
16375    pub fn go_to_singleton_buffer_point(
16376        &mut self,
16377        point: Point,
16378        window: &mut Window,
16379        cx: &mut Context<Self>,
16380    ) {
16381        self.go_to_singleton_buffer_range(point..point, window, cx);
16382    }
16383
16384    pub fn go_to_singleton_buffer_range(
16385        &mut self,
16386        range: Range<Point>,
16387        window: &mut Window,
16388        cx: &mut Context<Self>,
16389    ) {
16390        let multibuffer = self.buffer().read(cx);
16391        let Some(buffer) = multibuffer.as_singleton() else {
16392            return;
16393        };
16394        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16395            return;
16396        };
16397        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16398            return;
16399        };
16400        self.change_selections(
16401            SelectionEffects::default().nav_history(true),
16402            window,
16403            cx,
16404            |s| s.select_anchor_ranges([start..end]),
16405        );
16406    }
16407
16408    pub fn go_to_diagnostic(
16409        &mut self,
16410        action: &GoToDiagnostic,
16411        window: &mut Window,
16412        cx: &mut Context<Self>,
16413    ) {
16414        if !self.diagnostics_enabled() {
16415            return;
16416        }
16417        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16418        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16419    }
16420
16421    pub fn go_to_prev_diagnostic(
16422        &mut self,
16423        action: &GoToPreviousDiagnostic,
16424        window: &mut Window,
16425        cx: &mut Context<Self>,
16426    ) {
16427        if !self.diagnostics_enabled() {
16428            return;
16429        }
16430        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16431        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16432    }
16433
16434    pub fn go_to_diagnostic_impl(
16435        &mut self,
16436        direction: Direction,
16437        severity: GoToDiagnosticSeverityFilter,
16438        window: &mut Window,
16439        cx: &mut Context<Self>,
16440    ) {
16441        let buffer = self.buffer.read(cx).snapshot(cx);
16442        let selection = self
16443            .selections
16444            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16445
16446        let mut active_group_id = None;
16447        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16448            && active_group.active_range.start.to_offset(&buffer) == selection.start
16449        {
16450            active_group_id = Some(active_group.group_id);
16451        }
16452
16453        fn filtered<'a>(
16454            severity: GoToDiagnosticSeverityFilter,
16455            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16456        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16457            diagnostics
16458                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16459                .filter(|entry| entry.range.start != entry.range.end)
16460                .filter(|entry| !entry.diagnostic.is_unnecessary)
16461        }
16462
16463        let before = filtered(
16464            severity,
16465            buffer
16466                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16467                .filter(|entry| entry.range.start <= selection.start),
16468        );
16469        let after = filtered(
16470            severity,
16471            buffer
16472                .diagnostics_in_range(selection.start..buffer.len())
16473                .filter(|entry| entry.range.start >= selection.start),
16474        );
16475
16476        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16477        if direction == Direction::Prev {
16478            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16479            {
16480                for diagnostic in prev_diagnostics.into_iter().rev() {
16481                    if diagnostic.range.start != selection.start
16482                        || active_group_id
16483                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16484                    {
16485                        found = Some(diagnostic);
16486                        break 'outer;
16487                    }
16488                }
16489            }
16490        } else {
16491            for diagnostic in after.chain(before) {
16492                if diagnostic.range.start != selection.start
16493                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16494                {
16495                    found = Some(diagnostic);
16496                    break;
16497                }
16498            }
16499        }
16500        let Some(next_diagnostic) = found else {
16501            return;
16502        };
16503
16504        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16505        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16506            return;
16507        };
16508        let snapshot = self.snapshot(window, cx);
16509        if snapshot.intersects_fold(next_diagnostic.range.start) {
16510            self.unfold_ranges(
16511                std::slice::from_ref(&next_diagnostic.range),
16512                true,
16513                false,
16514                cx,
16515            );
16516        }
16517        self.change_selections(Default::default(), window, cx, |s| {
16518            s.select_ranges(vec![
16519                next_diagnostic.range.start..next_diagnostic.range.start,
16520            ])
16521        });
16522        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16523        self.refresh_edit_prediction(false, true, window, cx);
16524    }
16525
16526    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16527        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16528        let snapshot = self.snapshot(window, cx);
16529        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16530        self.go_to_hunk_before_or_after_position(
16531            &snapshot,
16532            selection.head(),
16533            Direction::Next,
16534            window,
16535            cx,
16536        );
16537    }
16538
16539    pub fn go_to_hunk_before_or_after_position(
16540        &mut self,
16541        snapshot: &EditorSnapshot,
16542        position: Point,
16543        direction: Direction,
16544        window: &mut Window,
16545        cx: &mut Context<Editor>,
16546    ) {
16547        let row = if direction == Direction::Next {
16548            self.hunk_after_position(snapshot, position)
16549                .map(|hunk| hunk.row_range.start)
16550        } else {
16551            self.hunk_before_position(snapshot, position)
16552        };
16553
16554        if let Some(row) = row {
16555            let destination = Point::new(row.0, 0);
16556            let autoscroll = Autoscroll::center();
16557
16558            self.unfold_ranges(&[destination..destination], false, false, cx);
16559            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16560                s.select_ranges([destination..destination]);
16561            });
16562        }
16563    }
16564
16565    fn hunk_after_position(
16566        &mut self,
16567        snapshot: &EditorSnapshot,
16568        position: Point,
16569    ) -> Option<MultiBufferDiffHunk> {
16570        snapshot
16571            .buffer_snapshot()
16572            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16573            .find(|hunk| hunk.row_range.start.0 > position.row)
16574            .or_else(|| {
16575                snapshot
16576                    .buffer_snapshot()
16577                    .diff_hunks_in_range(Point::zero()..position)
16578                    .find(|hunk| hunk.row_range.end.0 < position.row)
16579            })
16580    }
16581
16582    fn go_to_prev_hunk(
16583        &mut self,
16584        _: &GoToPreviousHunk,
16585        window: &mut Window,
16586        cx: &mut Context<Self>,
16587    ) {
16588        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16589        let snapshot = self.snapshot(window, cx);
16590        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16591        self.go_to_hunk_before_or_after_position(
16592            &snapshot,
16593            selection.head(),
16594            Direction::Prev,
16595            window,
16596            cx,
16597        );
16598    }
16599
16600    fn hunk_before_position(
16601        &mut self,
16602        snapshot: &EditorSnapshot,
16603        position: Point,
16604    ) -> Option<MultiBufferRow> {
16605        snapshot
16606            .buffer_snapshot()
16607            .diff_hunk_before(position)
16608            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16609    }
16610
16611    fn go_to_next_change(
16612        &mut self,
16613        _: &GoToNextChange,
16614        window: &mut Window,
16615        cx: &mut Context<Self>,
16616    ) {
16617        if let Some(selections) = self
16618            .change_list
16619            .next_change(1, Direction::Next)
16620            .map(|s| s.to_vec())
16621        {
16622            self.change_selections(Default::default(), window, cx, |s| {
16623                let map = s.display_snapshot();
16624                s.select_display_ranges(selections.iter().map(|a| {
16625                    let point = a.to_display_point(&map);
16626                    point..point
16627                }))
16628            })
16629        }
16630    }
16631
16632    fn go_to_previous_change(
16633        &mut self,
16634        _: &GoToPreviousChange,
16635        window: &mut Window,
16636        cx: &mut Context<Self>,
16637    ) {
16638        if let Some(selections) = self
16639            .change_list
16640            .next_change(1, Direction::Prev)
16641            .map(|s| s.to_vec())
16642        {
16643            self.change_selections(Default::default(), window, cx, |s| {
16644                let map = s.display_snapshot();
16645                s.select_display_ranges(selections.iter().map(|a| {
16646                    let point = a.to_display_point(&map);
16647                    point..point
16648                }))
16649            })
16650        }
16651    }
16652
16653    pub fn go_to_next_document_highlight(
16654        &mut self,
16655        _: &GoToNextDocumentHighlight,
16656        window: &mut Window,
16657        cx: &mut Context<Self>,
16658    ) {
16659        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16660    }
16661
16662    pub fn go_to_prev_document_highlight(
16663        &mut self,
16664        _: &GoToPreviousDocumentHighlight,
16665        window: &mut Window,
16666        cx: &mut Context<Self>,
16667    ) {
16668        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16669    }
16670
16671    pub fn go_to_document_highlight_before_or_after_position(
16672        &mut self,
16673        direction: Direction,
16674        window: &mut Window,
16675        cx: &mut Context<Editor>,
16676    ) {
16677        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16678        let snapshot = self.snapshot(window, cx);
16679        let buffer = &snapshot.buffer_snapshot();
16680        let position = self
16681            .selections
16682            .newest::<Point>(&snapshot.display_snapshot)
16683            .head();
16684        let anchor_position = buffer.anchor_after(position);
16685
16686        // Get all document highlights (both read and write)
16687        let mut all_highlights = Vec::new();
16688
16689        if let Some((_, read_highlights)) = self
16690            .background_highlights
16691            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16692        {
16693            all_highlights.extend(read_highlights.iter());
16694        }
16695
16696        if let Some((_, write_highlights)) = self
16697            .background_highlights
16698            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16699        {
16700            all_highlights.extend(write_highlights.iter());
16701        }
16702
16703        if all_highlights.is_empty() {
16704            return;
16705        }
16706
16707        // Sort highlights by position
16708        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16709
16710        let target_highlight = match direction {
16711            Direction::Next => {
16712                // Find the first highlight after the current position
16713                all_highlights
16714                    .iter()
16715                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16716            }
16717            Direction::Prev => {
16718                // Find the last highlight before the current position
16719                all_highlights
16720                    .iter()
16721                    .rev()
16722                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16723            }
16724        };
16725
16726        if let Some(highlight) = target_highlight {
16727            let destination = highlight.start.to_point(buffer);
16728            let autoscroll = Autoscroll::center();
16729
16730            self.unfold_ranges(&[destination..destination], false, false, cx);
16731            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16732                s.select_ranges([destination..destination]);
16733            });
16734        }
16735    }
16736
16737    fn go_to_line<T: 'static>(
16738        &mut self,
16739        position: Anchor,
16740        highlight_color: Option<Hsla>,
16741        window: &mut Window,
16742        cx: &mut Context<Self>,
16743    ) {
16744        let snapshot = self.snapshot(window, cx).display_snapshot;
16745        let position = position.to_point(&snapshot.buffer_snapshot());
16746        let start = snapshot
16747            .buffer_snapshot()
16748            .clip_point(Point::new(position.row, 0), Bias::Left);
16749        let end = start + Point::new(1, 0);
16750        let start = snapshot.buffer_snapshot().anchor_before(start);
16751        let end = snapshot.buffer_snapshot().anchor_before(end);
16752
16753        self.highlight_rows::<T>(
16754            start..end,
16755            highlight_color
16756                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16757            Default::default(),
16758            cx,
16759        );
16760
16761        if self.buffer.read(cx).is_singleton() {
16762            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16763        }
16764    }
16765
16766    pub fn go_to_definition(
16767        &mut self,
16768        _: &GoToDefinition,
16769        window: &mut Window,
16770        cx: &mut Context<Self>,
16771    ) -> Task<Result<Navigated>> {
16772        let definition =
16773            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16774        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16775        cx.spawn_in(window, async move |editor, cx| {
16776            if definition.await? == Navigated::Yes {
16777                return Ok(Navigated::Yes);
16778            }
16779            match fallback_strategy {
16780                GoToDefinitionFallback::None => Ok(Navigated::No),
16781                GoToDefinitionFallback::FindAllReferences => {
16782                    match editor.update_in(cx, |editor, window, cx| {
16783                        editor.find_all_references(&FindAllReferences, window, cx)
16784                    })? {
16785                        Some(references) => references.await,
16786                        None => Ok(Navigated::No),
16787                    }
16788                }
16789            }
16790        })
16791    }
16792
16793    pub fn go_to_declaration(
16794        &mut self,
16795        _: &GoToDeclaration,
16796        window: &mut Window,
16797        cx: &mut Context<Self>,
16798    ) -> Task<Result<Navigated>> {
16799        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16800    }
16801
16802    pub fn go_to_declaration_split(
16803        &mut self,
16804        _: &GoToDeclaration,
16805        window: &mut Window,
16806        cx: &mut Context<Self>,
16807    ) -> Task<Result<Navigated>> {
16808        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16809    }
16810
16811    pub fn go_to_implementation(
16812        &mut self,
16813        _: &GoToImplementation,
16814        window: &mut Window,
16815        cx: &mut Context<Self>,
16816    ) -> Task<Result<Navigated>> {
16817        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16818    }
16819
16820    pub fn go_to_implementation_split(
16821        &mut self,
16822        _: &GoToImplementationSplit,
16823        window: &mut Window,
16824        cx: &mut Context<Self>,
16825    ) -> Task<Result<Navigated>> {
16826        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16827    }
16828
16829    pub fn go_to_type_definition(
16830        &mut self,
16831        _: &GoToTypeDefinition,
16832        window: &mut Window,
16833        cx: &mut Context<Self>,
16834    ) -> Task<Result<Navigated>> {
16835        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16836    }
16837
16838    pub fn go_to_definition_split(
16839        &mut self,
16840        _: &GoToDefinitionSplit,
16841        window: &mut Window,
16842        cx: &mut Context<Self>,
16843    ) -> Task<Result<Navigated>> {
16844        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16845    }
16846
16847    pub fn go_to_type_definition_split(
16848        &mut self,
16849        _: &GoToTypeDefinitionSplit,
16850        window: &mut Window,
16851        cx: &mut Context<Self>,
16852    ) -> Task<Result<Navigated>> {
16853        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16854    }
16855
16856    fn go_to_definition_of_kind(
16857        &mut self,
16858        kind: GotoDefinitionKind,
16859        split: bool,
16860        window: &mut Window,
16861        cx: &mut Context<Self>,
16862    ) -> Task<Result<Navigated>> {
16863        let Some(provider) = self.semantics_provider.clone() else {
16864            return Task::ready(Ok(Navigated::No));
16865        };
16866        let head = self
16867            .selections
16868            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
16869            .head();
16870        let buffer = self.buffer.read(cx);
16871        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16872            return Task::ready(Ok(Navigated::No));
16873        };
16874        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16875            return Task::ready(Ok(Navigated::No));
16876        };
16877
16878        cx.spawn_in(window, async move |editor, cx| {
16879            let Some(definitions) = definitions.await? else {
16880                return Ok(Navigated::No);
16881            };
16882            let navigated = editor
16883                .update_in(cx, |editor, window, cx| {
16884                    editor.navigate_to_hover_links(
16885                        Some(kind),
16886                        definitions
16887                            .into_iter()
16888                            .filter(|location| {
16889                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16890                            })
16891                            .map(HoverLink::Text)
16892                            .collect::<Vec<_>>(),
16893                        split,
16894                        window,
16895                        cx,
16896                    )
16897                })?
16898                .await?;
16899            anyhow::Ok(navigated)
16900        })
16901    }
16902
16903    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16904        let selection = self.selections.newest_anchor();
16905        let head = selection.head();
16906        let tail = selection.tail();
16907
16908        let Some((buffer, start_position)) =
16909            self.buffer.read(cx).text_anchor_for_position(head, cx)
16910        else {
16911            return;
16912        };
16913
16914        let end_position = if head != tail {
16915            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16916                return;
16917            };
16918            Some(pos)
16919        } else {
16920            None
16921        };
16922
16923        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16924            let url = if let Some(end_pos) = end_position {
16925                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16926            } else {
16927                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16928            };
16929
16930            if let Some(url) = url {
16931                cx.update(|window, cx| {
16932                    if parse_zed_link(&url, cx).is_some() {
16933                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16934                    } else {
16935                        cx.open_url(&url);
16936                    }
16937                })?;
16938            }
16939
16940            anyhow::Ok(())
16941        });
16942
16943        url_finder.detach();
16944    }
16945
16946    pub fn open_selected_filename(
16947        &mut self,
16948        _: &OpenSelectedFilename,
16949        window: &mut Window,
16950        cx: &mut Context<Self>,
16951    ) {
16952        let Some(workspace) = self.workspace() else {
16953            return;
16954        };
16955
16956        let position = self.selections.newest_anchor().head();
16957
16958        let Some((buffer, buffer_position)) =
16959            self.buffer.read(cx).text_anchor_for_position(position, cx)
16960        else {
16961            return;
16962        };
16963
16964        let project = self.project.clone();
16965
16966        cx.spawn_in(window, async move |_, cx| {
16967            let result = find_file(&buffer, project, buffer_position, cx).await;
16968
16969            if let Some((_, path)) = result {
16970                workspace
16971                    .update_in(cx, |workspace, window, cx| {
16972                        workspace.open_resolved_path(path, window, cx)
16973                    })?
16974                    .await?;
16975            }
16976            anyhow::Ok(())
16977        })
16978        .detach();
16979    }
16980
16981    pub(crate) fn navigate_to_hover_links(
16982        &mut self,
16983        kind: Option<GotoDefinitionKind>,
16984        definitions: Vec<HoverLink>,
16985        split: bool,
16986        window: &mut Window,
16987        cx: &mut Context<Editor>,
16988    ) -> Task<Result<Navigated>> {
16989        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16990        let mut first_url_or_file = None;
16991        let definitions: Vec<_> = definitions
16992            .into_iter()
16993            .filter_map(|def| match def {
16994                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16995                HoverLink::InlayHint(lsp_location, server_id) => {
16996                    let computation =
16997                        self.compute_target_location(lsp_location, server_id, window, cx);
16998                    Some(cx.background_spawn(computation))
16999                }
17000                HoverLink::Url(url) => {
17001                    first_url_or_file = Some(Either::Left(url));
17002                    None
17003                }
17004                HoverLink::File(path) => {
17005                    first_url_or_file = Some(Either::Right(path));
17006                    None
17007                }
17008            })
17009            .collect();
17010
17011        let workspace = self.workspace();
17012
17013        cx.spawn_in(window, async move |editor, cx| {
17014            let locations: Vec<Location> = future::join_all(definitions)
17015                .await
17016                .into_iter()
17017                .filter_map(|location| location.transpose())
17018                .collect::<Result<_>>()
17019                .context("location tasks")?;
17020            let mut locations = cx.update(|_, cx| {
17021                locations
17022                    .into_iter()
17023                    .map(|location| {
17024                        let buffer = location.buffer.read(cx);
17025                        (location.buffer, location.range.to_point(buffer))
17026                    })
17027                    .into_group_map()
17028            })?;
17029            let mut num_locations = 0;
17030            for ranges in locations.values_mut() {
17031                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17032                ranges.dedup();
17033                num_locations += ranges.len();
17034            }
17035
17036            if num_locations > 1 {
17037                let Some(workspace) = workspace else {
17038                    return Ok(Navigated::No);
17039                };
17040
17041                let tab_kind = match kind {
17042                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17043                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17044                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17045                    Some(GotoDefinitionKind::Type) => "Types",
17046                };
17047                let title = editor
17048                    .update_in(cx, |_, _, cx| {
17049                        let target = locations
17050                            .iter()
17051                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17052                            .map(|(buffer, location)| {
17053                                buffer
17054                                    .read(cx)
17055                                    .text_for_range(location.clone())
17056                                    .collect::<String>()
17057                            })
17058                            .filter(|text| !text.contains('\n'))
17059                            .unique()
17060                            .take(3)
17061                            .join(", ");
17062                        if target.is_empty() {
17063                            tab_kind.to_owned()
17064                        } else {
17065                            format!("{tab_kind} for {target}")
17066                        }
17067                    })
17068                    .context("buffer title")?;
17069
17070                let opened = workspace
17071                    .update_in(cx, |workspace, window, cx| {
17072                        Self::open_locations_in_multibuffer(
17073                            workspace,
17074                            locations,
17075                            title,
17076                            split,
17077                            MultibufferSelectionMode::First,
17078                            window,
17079                            cx,
17080                        )
17081                    })
17082                    .is_ok();
17083
17084                anyhow::Ok(Navigated::from_bool(opened))
17085            } else if num_locations == 0 {
17086                // If there is one url or file, open it directly
17087                match first_url_or_file {
17088                    Some(Either::Left(url)) => {
17089                        cx.update(|_, cx| cx.open_url(&url))?;
17090                        Ok(Navigated::Yes)
17091                    }
17092                    Some(Either::Right(path)) => {
17093                        let Some(workspace) = workspace else {
17094                            return Ok(Navigated::No);
17095                        };
17096
17097                        workspace
17098                            .update_in(cx, |workspace, window, cx| {
17099                                workspace.open_resolved_path(path, window, cx)
17100                            })?
17101                            .await?;
17102                        Ok(Navigated::Yes)
17103                    }
17104                    None => Ok(Navigated::No),
17105                }
17106            } else {
17107                let Some(workspace) = workspace else {
17108                    return Ok(Navigated::No);
17109                };
17110
17111                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17112                let target_range = target_ranges.first().unwrap().clone();
17113
17114                editor.update_in(cx, |editor, window, cx| {
17115                    let range = target_range.to_point(target_buffer.read(cx));
17116                    let range = editor.range_for_match(&range);
17117                    let range = collapse_multiline_range(range);
17118
17119                    if !split
17120                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17121                    {
17122                        editor.go_to_singleton_buffer_range(range, window, cx);
17123                    } else {
17124                        let pane = workspace.read(cx).active_pane().clone();
17125                        window.defer(cx, move |window, cx| {
17126                            let target_editor: Entity<Self> =
17127                                workspace.update(cx, |workspace, cx| {
17128                                    let pane = if split {
17129                                        workspace.adjacent_pane(window, cx)
17130                                    } else {
17131                                        workspace.active_pane().clone()
17132                                    };
17133
17134                                    workspace.open_project_item(
17135                                        pane,
17136                                        target_buffer.clone(),
17137                                        true,
17138                                        true,
17139                                        window,
17140                                        cx,
17141                                    )
17142                                });
17143                            target_editor.update(cx, |target_editor, cx| {
17144                                // When selecting a definition in a different buffer, disable the nav history
17145                                // to avoid creating a history entry at the previous cursor location.
17146                                pane.update(cx, |pane, _| pane.disable_history());
17147                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17148                                pane.update(cx, |pane, _| pane.enable_history());
17149                            });
17150                        });
17151                    }
17152                    Navigated::Yes
17153                })
17154            }
17155        })
17156    }
17157
17158    fn compute_target_location(
17159        &self,
17160        lsp_location: lsp::Location,
17161        server_id: LanguageServerId,
17162        window: &mut Window,
17163        cx: &mut Context<Self>,
17164    ) -> Task<anyhow::Result<Option<Location>>> {
17165        let Some(project) = self.project.clone() else {
17166            return Task::ready(Ok(None));
17167        };
17168
17169        cx.spawn_in(window, async move |editor, cx| {
17170            let location_task = editor.update(cx, |_, cx| {
17171                project.update(cx, |project, cx| {
17172                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17173                })
17174            })?;
17175            let location = Some({
17176                let target_buffer_handle = location_task.await.context("open local buffer")?;
17177                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17178                    let target_start = target_buffer
17179                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17180                    let target_end = target_buffer
17181                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17182                    target_buffer.anchor_after(target_start)
17183                        ..target_buffer.anchor_before(target_end)
17184                })?;
17185                Location {
17186                    buffer: target_buffer_handle,
17187                    range,
17188                }
17189            });
17190            Ok(location)
17191        })
17192    }
17193
17194    fn go_to_next_reference(
17195        &mut self,
17196        _: &GoToNextReference,
17197        window: &mut Window,
17198        cx: &mut Context<Self>,
17199    ) {
17200        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17201        if let Some(task) = task {
17202            task.detach();
17203        };
17204    }
17205
17206    fn go_to_prev_reference(
17207        &mut self,
17208        _: &GoToPreviousReference,
17209        window: &mut Window,
17210        cx: &mut Context<Self>,
17211    ) {
17212        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17213        if let Some(task) = task {
17214            task.detach();
17215        };
17216    }
17217
17218    pub fn go_to_reference_before_or_after_position(
17219        &mut self,
17220        direction: Direction,
17221        count: usize,
17222        window: &mut Window,
17223        cx: &mut Context<Self>,
17224    ) -> Option<Task<Result<()>>> {
17225        let selection = self.selections.newest_anchor();
17226        let head = selection.head();
17227
17228        let multi_buffer = self.buffer.read(cx);
17229
17230        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17231        let workspace = self.workspace()?;
17232        let project = workspace.read(cx).project().clone();
17233        let references =
17234            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17235        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17236            let Some(locations) = references.await? else {
17237                return Ok(());
17238            };
17239
17240            if locations.is_empty() {
17241                // totally normal - the cursor may be on something which is not
17242                // a symbol (e.g. a keyword)
17243                log::info!("no references found under cursor");
17244                return Ok(());
17245            }
17246
17247            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17248
17249            let (locations, current_location_index) =
17250                multi_buffer.update(cx, |multi_buffer, cx| {
17251                    let mut locations = locations
17252                        .into_iter()
17253                        .filter_map(|loc| {
17254                            let start = multi_buffer.buffer_anchor_to_anchor(
17255                                &loc.buffer,
17256                                loc.range.start,
17257                                cx,
17258                            )?;
17259                            let end = multi_buffer.buffer_anchor_to_anchor(
17260                                &loc.buffer,
17261                                loc.range.end,
17262                                cx,
17263                            )?;
17264                            Some(start..end)
17265                        })
17266                        .collect::<Vec<_>>();
17267
17268                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17269                    // There is an O(n) implementation, but given this list will be
17270                    // small (usually <100 items), the extra O(log(n)) factor isn't
17271                    // worth the (surprisingly large amount of) extra complexity.
17272                    locations
17273                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17274
17275                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17276
17277                    let current_location_index = locations.iter().position(|loc| {
17278                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17279                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17280                    });
17281
17282                    (locations, current_location_index)
17283                })?;
17284
17285            let Some(current_location_index) = current_location_index else {
17286                // This indicates something has gone wrong, because we already
17287                // handle the "no references" case above
17288                log::error!(
17289                    "failed to find current reference under cursor. Total references: {}",
17290                    locations.len()
17291                );
17292                return Ok(());
17293            };
17294
17295            let destination_location_index = match direction {
17296                Direction::Next => (current_location_index + count) % locations.len(),
17297                Direction::Prev => {
17298                    (current_location_index + locations.len() - count % locations.len())
17299                        % locations.len()
17300                }
17301            };
17302
17303            // TODO(cameron): is this needed?
17304            // the thinking is to avoid "jumping to the current location" (avoid
17305            // polluting "jumplist" in vim terms)
17306            if current_location_index == destination_location_index {
17307                return Ok(());
17308            }
17309
17310            let Range { start, end } = locations[destination_location_index];
17311
17312            editor.update_in(cx, |editor, window, cx| {
17313                let effects = SelectionEffects::default();
17314
17315                editor.unfold_ranges(&[start..end], false, false, cx);
17316                editor.change_selections(effects, window, cx, |s| {
17317                    s.select_ranges([start..start]);
17318                });
17319            })?;
17320
17321            Ok(())
17322        }))
17323    }
17324
17325    pub fn find_all_references(
17326        &mut self,
17327        _: &FindAllReferences,
17328        window: &mut Window,
17329        cx: &mut Context<Self>,
17330    ) -> Option<Task<Result<Navigated>>> {
17331        let selection = self
17332            .selections
17333            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17334        let multi_buffer = self.buffer.read(cx);
17335        let head = selection.head();
17336
17337        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17338        let head_anchor = multi_buffer_snapshot.anchor_at(
17339            head,
17340            if head < selection.tail() {
17341                Bias::Right
17342            } else {
17343                Bias::Left
17344            },
17345        );
17346
17347        match self
17348            .find_all_references_task_sources
17349            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17350        {
17351            Ok(_) => {
17352                log::info!(
17353                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17354                );
17355                return None;
17356            }
17357            Err(i) => {
17358                self.find_all_references_task_sources.insert(i, head_anchor);
17359            }
17360        }
17361
17362        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17363        let workspace = self.workspace()?;
17364        let project = workspace.read(cx).project().clone();
17365        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17366        Some(cx.spawn_in(window, async move |editor, cx| {
17367            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17368                if let Ok(i) = editor
17369                    .find_all_references_task_sources
17370                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17371                {
17372                    editor.find_all_references_task_sources.remove(i);
17373                }
17374            });
17375
17376            let Some(locations) = references.await? else {
17377                return anyhow::Ok(Navigated::No);
17378            };
17379            let mut locations = cx.update(|_, cx| {
17380                locations
17381                    .into_iter()
17382                    .map(|location| {
17383                        let buffer = location.buffer.read(cx);
17384                        (location.buffer, location.range.to_point(buffer))
17385                    })
17386                    .into_group_map()
17387            })?;
17388            if locations.is_empty() {
17389                return anyhow::Ok(Navigated::No);
17390            }
17391            for ranges in locations.values_mut() {
17392                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17393                ranges.dedup();
17394            }
17395
17396            workspace.update_in(cx, |workspace, window, cx| {
17397                let target = locations
17398                    .iter()
17399                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17400                    .map(|(buffer, location)| {
17401                        buffer
17402                            .read(cx)
17403                            .text_for_range(location.clone())
17404                            .collect::<String>()
17405                    })
17406                    .filter(|text| !text.contains('\n'))
17407                    .unique()
17408                    .take(3)
17409                    .join(", ");
17410                let title = if target.is_empty() {
17411                    "References".to_owned()
17412                } else {
17413                    format!("References to {target}")
17414                };
17415                Self::open_locations_in_multibuffer(
17416                    workspace,
17417                    locations,
17418                    title,
17419                    false,
17420                    MultibufferSelectionMode::First,
17421                    window,
17422                    cx,
17423                );
17424                Navigated::Yes
17425            })
17426        }))
17427    }
17428
17429    /// Opens a multibuffer with the given project locations in it
17430    pub fn open_locations_in_multibuffer(
17431        workspace: &mut Workspace,
17432        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17433        title: String,
17434        split: bool,
17435        multibuffer_selection_mode: MultibufferSelectionMode,
17436        window: &mut Window,
17437        cx: &mut Context<Workspace>,
17438    ) {
17439        if locations.is_empty() {
17440            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17441            return;
17442        }
17443
17444        let capability = workspace.project().read(cx).capability();
17445        let mut ranges = <Vec<Range<Anchor>>>::new();
17446
17447        // a key to find existing multibuffer editors with the same set of locations
17448        // to prevent us from opening more and more multibuffer tabs for searches and the like
17449        let mut key = (title.clone(), vec![]);
17450        let excerpt_buffer = cx.new(|cx| {
17451            let key = &mut key.1;
17452            let mut multibuffer = MultiBuffer::new(capability);
17453            for (buffer, mut ranges_for_buffer) in locations {
17454                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17455                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17456                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17457                    PathKey::for_buffer(&buffer, cx),
17458                    buffer.clone(),
17459                    ranges_for_buffer,
17460                    multibuffer_context_lines(cx),
17461                    cx,
17462                );
17463                ranges.extend(new_ranges)
17464            }
17465
17466            multibuffer.with_title(title)
17467        });
17468        let existing = workspace.active_pane().update(cx, |pane, cx| {
17469            pane.items()
17470                .filter_map(|item| item.downcast::<Editor>())
17471                .find(|editor| {
17472                    editor
17473                        .read(cx)
17474                        .lookup_key
17475                        .as_ref()
17476                        .and_then(|it| {
17477                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17478                        })
17479                        .is_some_and(|it| *it == key)
17480                })
17481        });
17482        let editor = existing.unwrap_or_else(|| {
17483            cx.new(|cx| {
17484                let mut editor = Editor::for_multibuffer(
17485                    excerpt_buffer,
17486                    Some(workspace.project().clone()),
17487                    window,
17488                    cx,
17489                );
17490                editor.lookup_key = Some(Box::new(key));
17491                editor
17492            })
17493        });
17494        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17495            MultibufferSelectionMode::First => {
17496                if let Some(first_range) = ranges.first() {
17497                    editor.change_selections(
17498                        SelectionEffects::no_scroll(),
17499                        window,
17500                        cx,
17501                        |selections| {
17502                            selections.clear_disjoint();
17503                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17504                        },
17505                    );
17506                }
17507                editor.highlight_background::<Self>(
17508                    &ranges,
17509                    |theme| theme.colors().editor_highlighted_line_background,
17510                    cx,
17511                );
17512            }
17513            MultibufferSelectionMode::All => {
17514                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17515                    selections.clear_disjoint();
17516                    selections.select_anchor_ranges(ranges);
17517                });
17518            }
17519        });
17520
17521        let item = Box::new(editor);
17522        let item_id = item.item_id();
17523
17524        if split {
17525            let pane = workspace.adjacent_pane(window, cx);
17526            workspace.add_item(pane, item, None, true, true, window, cx);
17527        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17528            let (preview_item_id, preview_item_idx) =
17529                workspace.active_pane().read_with(cx, |pane, _| {
17530                    (pane.preview_item_id(), pane.preview_item_idx())
17531                });
17532
17533            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17534
17535            if let Some(preview_item_id) = preview_item_id {
17536                workspace.active_pane().update(cx, |pane, cx| {
17537                    pane.remove_item(preview_item_id, false, false, window, cx);
17538                });
17539            }
17540        } else {
17541            workspace.add_item_to_active_pane(item, None, true, window, cx);
17542        }
17543        workspace.active_pane().update(cx, |pane, cx| {
17544            pane.set_preview_item_id(Some(item_id), cx);
17545        });
17546    }
17547
17548    pub fn rename(
17549        &mut self,
17550        _: &Rename,
17551        window: &mut Window,
17552        cx: &mut Context<Self>,
17553    ) -> Option<Task<Result<()>>> {
17554        use language::ToOffset as _;
17555
17556        let provider = self.semantics_provider.clone()?;
17557        let selection = self.selections.newest_anchor().clone();
17558        let (cursor_buffer, cursor_buffer_position) = self
17559            .buffer
17560            .read(cx)
17561            .text_anchor_for_position(selection.head(), cx)?;
17562        let (tail_buffer, cursor_buffer_position_end) = self
17563            .buffer
17564            .read(cx)
17565            .text_anchor_for_position(selection.tail(), cx)?;
17566        if tail_buffer != cursor_buffer {
17567            return None;
17568        }
17569
17570        let snapshot = cursor_buffer.read(cx).snapshot();
17571        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17572        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17573        let prepare_rename = provider
17574            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17575            .unwrap_or_else(|| Task::ready(Ok(None)));
17576        drop(snapshot);
17577
17578        Some(cx.spawn_in(window, async move |this, cx| {
17579            let rename_range = if let Some(range) = prepare_rename.await? {
17580                Some(range)
17581            } else {
17582                this.update(cx, |this, cx| {
17583                    let buffer = this.buffer.read(cx).snapshot(cx);
17584                    let mut buffer_highlights = this
17585                        .document_highlights_for_position(selection.head(), &buffer)
17586                        .filter(|highlight| {
17587                            highlight.start.excerpt_id == selection.head().excerpt_id
17588                                && highlight.end.excerpt_id == selection.head().excerpt_id
17589                        });
17590                    buffer_highlights
17591                        .next()
17592                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17593                })?
17594            };
17595            if let Some(rename_range) = rename_range {
17596                this.update_in(cx, |this, window, cx| {
17597                    let snapshot = cursor_buffer.read(cx).snapshot();
17598                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17599                    let cursor_offset_in_rename_range =
17600                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17601                    let cursor_offset_in_rename_range_end =
17602                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17603
17604                    this.take_rename(false, window, cx);
17605                    let buffer = this.buffer.read(cx).read(cx);
17606                    let cursor_offset = selection.head().to_offset(&buffer);
17607                    let rename_start =
17608                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17609                    let rename_end = rename_start + rename_buffer_range.len();
17610                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17611                    let mut old_highlight_id = None;
17612                    let old_name: Arc<str> = buffer
17613                        .chunks(rename_start..rename_end, true)
17614                        .map(|chunk| {
17615                            if old_highlight_id.is_none() {
17616                                old_highlight_id = chunk.syntax_highlight_id;
17617                            }
17618                            chunk.text
17619                        })
17620                        .collect::<String>()
17621                        .into();
17622
17623                    drop(buffer);
17624
17625                    // Position the selection in the rename editor so that it matches the current selection.
17626                    this.show_local_selections = false;
17627                    let rename_editor = cx.new(|cx| {
17628                        let mut editor = Editor::single_line(window, cx);
17629                        editor.buffer.update(cx, |buffer, cx| {
17630                            buffer.edit(
17631                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
17632                                None,
17633                                cx,
17634                            )
17635                        });
17636                        let cursor_offset_in_rename_range =
17637                            MultiBufferOffset(cursor_offset_in_rename_range);
17638                        let cursor_offset_in_rename_range_end =
17639                            MultiBufferOffset(cursor_offset_in_rename_range_end);
17640                        let rename_selection_range = match cursor_offset_in_rename_range
17641                            .cmp(&cursor_offset_in_rename_range_end)
17642                        {
17643                            Ordering::Equal => {
17644                                editor.select_all(&SelectAll, window, cx);
17645                                return editor;
17646                            }
17647                            Ordering::Less => {
17648                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17649                            }
17650                            Ordering::Greater => {
17651                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17652                            }
17653                        };
17654                        if rename_selection_range.end.0 > old_name.len() {
17655                            editor.select_all(&SelectAll, window, cx);
17656                        } else {
17657                            editor.change_selections(Default::default(), window, cx, |s| {
17658                                s.select_ranges([rename_selection_range]);
17659                            });
17660                        }
17661                        editor
17662                    });
17663                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17664                        if e == &EditorEvent::Focused {
17665                            cx.emit(EditorEvent::FocusedIn)
17666                        }
17667                    })
17668                    .detach();
17669
17670                    let write_highlights =
17671                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17672                    let read_highlights =
17673                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17674                    let ranges = write_highlights
17675                        .iter()
17676                        .flat_map(|(_, ranges)| ranges.iter())
17677                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17678                        .cloned()
17679                        .collect();
17680
17681                    this.highlight_text::<Rename>(
17682                        ranges,
17683                        HighlightStyle {
17684                            fade_out: Some(0.6),
17685                            ..Default::default()
17686                        },
17687                        cx,
17688                    );
17689                    let rename_focus_handle = rename_editor.focus_handle(cx);
17690                    window.focus(&rename_focus_handle);
17691                    let block_id = this.insert_blocks(
17692                        [BlockProperties {
17693                            style: BlockStyle::Flex,
17694                            placement: BlockPlacement::Below(range.start),
17695                            height: Some(1),
17696                            render: Arc::new({
17697                                let rename_editor = rename_editor.clone();
17698                                move |cx: &mut BlockContext| {
17699                                    let mut text_style = cx.editor_style.text.clone();
17700                                    if let Some(highlight_style) = old_highlight_id
17701                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17702                                    {
17703                                        text_style = text_style.highlight(highlight_style);
17704                                    }
17705                                    div()
17706                                        .block_mouse_except_scroll()
17707                                        .pl(cx.anchor_x)
17708                                        .child(EditorElement::new(
17709                                            &rename_editor,
17710                                            EditorStyle {
17711                                                background: cx.theme().system().transparent,
17712                                                local_player: cx.editor_style.local_player,
17713                                                text: text_style,
17714                                                scrollbar_width: cx.editor_style.scrollbar_width,
17715                                                syntax: cx.editor_style.syntax.clone(),
17716                                                status: cx.editor_style.status.clone(),
17717                                                inlay_hints_style: HighlightStyle {
17718                                                    font_weight: Some(FontWeight::BOLD),
17719                                                    ..make_inlay_hints_style(cx.app)
17720                                                },
17721                                                edit_prediction_styles: make_suggestion_styles(
17722                                                    cx.app,
17723                                                ),
17724                                                ..EditorStyle::default()
17725                                            },
17726                                        ))
17727                                        .into_any_element()
17728                                }
17729                            }),
17730                            priority: 0,
17731                        }],
17732                        Some(Autoscroll::fit()),
17733                        cx,
17734                    )[0];
17735                    this.pending_rename = Some(RenameState {
17736                        range,
17737                        old_name,
17738                        editor: rename_editor,
17739                        block_id,
17740                    });
17741                })?;
17742            }
17743
17744            Ok(())
17745        }))
17746    }
17747
17748    pub fn confirm_rename(
17749        &mut self,
17750        _: &ConfirmRename,
17751        window: &mut Window,
17752        cx: &mut Context<Self>,
17753    ) -> Option<Task<Result<()>>> {
17754        let rename = self.take_rename(false, window, cx)?;
17755        let workspace = self.workspace()?.downgrade();
17756        let (buffer, start) = self
17757            .buffer
17758            .read(cx)
17759            .text_anchor_for_position(rename.range.start, cx)?;
17760        let (end_buffer, _) = self
17761            .buffer
17762            .read(cx)
17763            .text_anchor_for_position(rename.range.end, cx)?;
17764        if buffer != end_buffer {
17765            return None;
17766        }
17767
17768        let old_name = rename.old_name;
17769        let new_name = rename.editor.read(cx).text(cx);
17770
17771        let rename = self.semantics_provider.as_ref()?.perform_rename(
17772            &buffer,
17773            start,
17774            new_name.clone(),
17775            cx,
17776        )?;
17777
17778        Some(cx.spawn_in(window, async move |editor, cx| {
17779            let project_transaction = rename.await?;
17780            Self::open_project_transaction(
17781                &editor,
17782                workspace,
17783                project_transaction,
17784                format!("Rename: {}{}", old_name, new_name),
17785                cx,
17786            )
17787            .await?;
17788
17789            editor.update(cx, |editor, cx| {
17790                editor.refresh_document_highlights(cx);
17791            })?;
17792            Ok(())
17793        }))
17794    }
17795
17796    fn take_rename(
17797        &mut self,
17798        moving_cursor: bool,
17799        window: &mut Window,
17800        cx: &mut Context<Self>,
17801    ) -> Option<RenameState> {
17802        let rename = self.pending_rename.take()?;
17803        if rename.editor.focus_handle(cx).is_focused(window) {
17804            window.focus(&self.focus_handle);
17805        }
17806
17807        self.remove_blocks(
17808            [rename.block_id].into_iter().collect(),
17809            Some(Autoscroll::fit()),
17810            cx,
17811        );
17812        self.clear_highlights::<Rename>(cx);
17813        self.show_local_selections = true;
17814
17815        if moving_cursor {
17816            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17817                editor
17818                    .selections
17819                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
17820                    .head()
17821            });
17822
17823            // Update the selection to match the position of the selection inside
17824            // the rename editor.
17825            let snapshot = self.buffer.read(cx).read(cx);
17826            let rename_range = rename.range.to_offset(&snapshot);
17827            let cursor_in_editor = snapshot
17828                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17829                .min(rename_range.end);
17830            drop(snapshot);
17831
17832            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17833                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17834            });
17835        } else {
17836            self.refresh_document_highlights(cx);
17837        }
17838
17839        Some(rename)
17840    }
17841
17842    pub fn pending_rename(&self) -> Option<&RenameState> {
17843        self.pending_rename.as_ref()
17844    }
17845
17846    fn format(
17847        &mut self,
17848        _: &Format,
17849        window: &mut Window,
17850        cx: &mut Context<Self>,
17851    ) -> Option<Task<Result<()>>> {
17852        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17853
17854        let project = match &self.project {
17855            Some(project) => project.clone(),
17856            None => return None,
17857        };
17858
17859        Some(self.perform_format(
17860            project,
17861            FormatTrigger::Manual,
17862            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17863            window,
17864            cx,
17865        ))
17866    }
17867
17868    fn format_selections(
17869        &mut self,
17870        _: &FormatSelections,
17871        window: &mut Window,
17872        cx: &mut Context<Self>,
17873    ) -> Option<Task<Result<()>>> {
17874        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17875
17876        let project = match &self.project {
17877            Some(project) => project.clone(),
17878            None => return None,
17879        };
17880
17881        let ranges = self
17882            .selections
17883            .all_adjusted(&self.display_snapshot(cx))
17884            .into_iter()
17885            .map(|selection| selection.range())
17886            .collect_vec();
17887
17888        Some(self.perform_format(
17889            project,
17890            FormatTrigger::Manual,
17891            FormatTarget::Ranges(ranges),
17892            window,
17893            cx,
17894        ))
17895    }
17896
17897    fn perform_format(
17898        &mut self,
17899        project: Entity<Project>,
17900        trigger: FormatTrigger,
17901        target: FormatTarget,
17902        window: &mut Window,
17903        cx: &mut Context<Self>,
17904    ) -> Task<Result<()>> {
17905        let buffer = self.buffer.clone();
17906        let (buffers, target) = match target {
17907            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17908            FormatTarget::Ranges(selection_ranges) => {
17909                let multi_buffer = buffer.read(cx);
17910                let snapshot = multi_buffer.read(cx);
17911                let mut buffers = HashSet::default();
17912                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17913                    BTreeMap::new();
17914                for selection_range in selection_ranges {
17915                    for (buffer, buffer_range, _) in
17916                        snapshot.range_to_buffer_ranges(selection_range)
17917                    {
17918                        let buffer_id = buffer.remote_id();
17919                        let start = buffer.anchor_before(buffer_range.start);
17920                        let end = buffer.anchor_after(buffer_range.end);
17921                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17922                        buffer_id_to_ranges
17923                            .entry(buffer_id)
17924                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17925                            .or_insert_with(|| vec![start..end]);
17926                    }
17927                }
17928                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17929            }
17930        };
17931
17932        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17933        let selections_prev = transaction_id_prev
17934            .and_then(|transaction_id_prev| {
17935                // default to selections as they were after the last edit, if we have them,
17936                // instead of how they are now.
17937                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17938                // will take you back to where you made the last edit, instead of staying where you scrolled
17939                self.selection_history
17940                    .transaction(transaction_id_prev)
17941                    .map(|t| t.0.clone())
17942            })
17943            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17944
17945        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17946        let format = project.update(cx, |project, cx| {
17947            project.format(buffers, target, true, trigger, cx)
17948        });
17949
17950        cx.spawn_in(window, async move |editor, cx| {
17951            let transaction = futures::select_biased! {
17952                transaction = format.log_err().fuse() => transaction,
17953                () = timeout => {
17954                    log::warn!("timed out waiting for formatting");
17955                    None
17956                }
17957            };
17958
17959            buffer
17960                .update(cx, |buffer, cx| {
17961                    if let Some(transaction) = transaction
17962                        && !buffer.is_singleton()
17963                    {
17964                        buffer.push_transaction(&transaction.0, cx);
17965                    }
17966                    cx.notify();
17967                })
17968                .ok();
17969
17970            if let Some(transaction_id_now) =
17971                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17972            {
17973                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17974                if has_new_transaction {
17975                    _ = editor.update(cx, |editor, _| {
17976                        editor
17977                            .selection_history
17978                            .insert_transaction(transaction_id_now, selections_prev);
17979                    });
17980                }
17981            }
17982
17983            Ok(())
17984        })
17985    }
17986
17987    fn organize_imports(
17988        &mut self,
17989        _: &OrganizeImports,
17990        window: &mut Window,
17991        cx: &mut Context<Self>,
17992    ) -> Option<Task<Result<()>>> {
17993        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17994        let project = match &self.project {
17995            Some(project) => project.clone(),
17996            None => return None,
17997        };
17998        Some(self.perform_code_action_kind(
17999            project,
18000            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18001            window,
18002            cx,
18003        ))
18004    }
18005
18006    fn perform_code_action_kind(
18007        &mut self,
18008        project: Entity<Project>,
18009        kind: CodeActionKind,
18010        window: &mut Window,
18011        cx: &mut Context<Self>,
18012    ) -> Task<Result<()>> {
18013        let buffer = self.buffer.clone();
18014        let buffers = buffer.read(cx).all_buffers();
18015        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18016        let apply_action = project.update(cx, |project, cx| {
18017            project.apply_code_action_kind(buffers, kind, true, cx)
18018        });
18019        cx.spawn_in(window, async move |_, cx| {
18020            let transaction = futures::select_biased! {
18021                () = timeout => {
18022                    log::warn!("timed out waiting for executing code action");
18023                    None
18024                }
18025                transaction = apply_action.log_err().fuse() => transaction,
18026            };
18027            buffer
18028                .update(cx, |buffer, cx| {
18029                    // check if we need this
18030                    if let Some(transaction) = transaction
18031                        && !buffer.is_singleton()
18032                    {
18033                        buffer.push_transaction(&transaction.0, cx);
18034                    }
18035                    cx.notify();
18036                })
18037                .ok();
18038            Ok(())
18039        })
18040    }
18041
18042    pub fn restart_language_server(
18043        &mut self,
18044        _: &RestartLanguageServer,
18045        _: &mut Window,
18046        cx: &mut Context<Self>,
18047    ) {
18048        if let Some(project) = self.project.clone() {
18049            self.buffer.update(cx, |multi_buffer, cx| {
18050                project.update(cx, |project, cx| {
18051                    project.restart_language_servers_for_buffers(
18052                        multi_buffer.all_buffers().into_iter().collect(),
18053                        HashSet::default(),
18054                        cx,
18055                    );
18056                });
18057            })
18058        }
18059    }
18060
18061    pub fn stop_language_server(
18062        &mut self,
18063        _: &StopLanguageServer,
18064        _: &mut Window,
18065        cx: &mut Context<Self>,
18066    ) {
18067        if let Some(project) = self.project.clone() {
18068            self.buffer.update(cx, |multi_buffer, cx| {
18069                project.update(cx, |project, cx| {
18070                    project.stop_language_servers_for_buffers(
18071                        multi_buffer.all_buffers().into_iter().collect(),
18072                        HashSet::default(),
18073                        cx,
18074                    );
18075                });
18076            });
18077            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18078        }
18079    }
18080
18081    fn cancel_language_server_work(
18082        workspace: &mut Workspace,
18083        _: &actions::CancelLanguageServerWork,
18084        _: &mut Window,
18085        cx: &mut Context<Workspace>,
18086    ) {
18087        let project = workspace.project();
18088        let buffers = workspace
18089            .active_item(cx)
18090            .and_then(|item| item.act_as::<Editor>(cx))
18091            .map_or(HashSet::default(), |editor| {
18092                editor.read(cx).buffer.read(cx).all_buffers()
18093            });
18094        project.update(cx, |project, cx| {
18095            project.cancel_language_server_work_for_buffers(buffers, cx);
18096        });
18097    }
18098
18099    fn show_character_palette(
18100        &mut self,
18101        _: &ShowCharacterPalette,
18102        window: &mut Window,
18103        _: &mut Context<Self>,
18104    ) {
18105        window.show_character_palette();
18106    }
18107
18108    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18109        if !self.diagnostics_enabled() {
18110            return;
18111        }
18112
18113        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18114            let buffer = self.buffer.read(cx).snapshot(cx);
18115            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18116            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18117            let is_valid = buffer
18118                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18119                .any(|entry| {
18120                    entry.diagnostic.is_primary
18121                        && !entry.range.is_empty()
18122                        && entry.range.start == primary_range_start
18123                        && entry.diagnostic.message == active_diagnostics.active_message
18124                });
18125
18126            if !is_valid {
18127                self.dismiss_diagnostics(cx);
18128            }
18129        }
18130    }
18131
18132    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18133        match &self.active_diagnostics {
18134            ActiveDiagnostic::Group(group) => Some(group),
18135            _ => None,
18136        }
18137    }
18138
18139    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18140        if !self.diagnostics_enabled() {
18141            return;
18142        }
18143        self.dismiss_diagnostics(cx);
18144        self.active_diagnostics = ActiveDiagnostic::All;
18145    }
18146
18147    fn activate_diagnostics(
18148        &mut self,
18149        buffer_id: BufferId,
18150        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18151        window: &mut Window,
18152        cx: &mut Context<Self>,
18153    ) {
18154        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18155            return;
18156        }
18157        self.dismiss_diagnostics(cx);
18158        let snapshot = self.snapshot(window, cx);
18159        let buffer = self.buffer.read(cx).snapshot(cx);
18160        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18161            return;
18162        };
18163
18164        let diagnostic_group = buffer
18165            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18166            .collect::<Vec<_>>();
18167
18168        let language_registry = self
18169            .project()
18170            .map(|project| project.read(cx).languages().clone());
18171
18172        let blocks = renderer.render_group(
18173            diagnostic_group,
18174            buffer_id,
18175            snapshot,
18176            cx.weak_entity(),
18177            language_registry,
18178            cx,
18179        );
18180
18181        let blocks = self.display_map.update(cx, |display_map, cx| {
18182            display_map.insert_blocks(blocks, cx).into_iter().collect()
18183        });
18184        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18185            active_range: buffer.anchor_before(diagnostic.range.start)
18186                ..buffer.anchor_after(diagnostic.range.end),
18187            active_message: diagnostic.diagnostic.message.clone(),
18188            group_id: diagnostic.diagnostic.group_id,
18189            blocks,
18190        });
18191        cx.notify();
18192    }
18193
18194    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18195        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18196            return;
18197        };
18198
18199        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18200        if let ActiveDiagnostic::Group(group) = prev {
18201            self.display_map.update(cx, |display_map, cx| {
18202                display_map.remove_blocks(group.blocks, cx);
18203            });
18204            cx.notify();
18205        }
18206    }
18207
18208    /// Disable inline diagnostics rendering for this editor.
18209    pub fn disable_inline_diagnostics(&mut self) {
18210        self.inline_diagnostics_enabled = false;
18211        self.inline_diagnostics_update = Task::ready(());
18212        self.inline_diagnostics.clear();
18213    }
18214
18215    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18216        self.diagnostics_enabled = false;
18217        self.dismiss_diagnostics(cx);
18218        self.inline_diagnostics_update = Task::ready(());
18219        self.inline_diagnostics.clear();
18220    }
18221
18222    pub fn disable_word_completions(&mut self) {
18223        self.word_completions_enabled = false;
18224    }
18225
18226    pub fn diagnostics_enabled(&self) -> bool {
18227        self.diagnostics_enabled && self.mode.is_full()
18228    }
18229
18230    pub fn inline_diagnostics_enabled(&self) -> bool {
18231        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18232    }
18233
18234    pub fn show_inline_diagnostics(&self) -> bool {
18235        self.show_inline_diagnostics
18236    }
18237
18238    pub fn toggle_inline_diagnostics(
18239        &mut self,
18240        _: &ToggleInlineDiagnostics,
18241        window: &mut Window,
18242        cx: &mut Context<Editor>,
18243    ) {
18244        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18245        self.refresh_inline_diagnostics(false, window, cx);
18246    }
18247
18248    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18249        self.diagnostics_max_severity = severity;
18250        self.display_map.update(cx, |display_map, _| {
18251            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18252        });
18253    }
18254
18255    pub fn toggle_diagnostics(
18256        &mut self,
18257        _: &ToggleDiagnostics,
18258        window: &mut Window,
18259        cx: &mut Context<Editor>,
18260    ) {
18261        if !self.diagnostics_enabled() {
18262            return;
18263        }
18264
18265        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18266            EditorSettings::get_global(cx)
18267                .diagnostics_max_severity
18268                .filter(|severity| severity != &DiagnosticSeverity::Off)
18269                .unwrap_or(DiagnosticSeverity::Hint)
18270        } else {
18271            DiagnosticSeverity::Off
18272        };
18273        self.set_max_diagnostics_severity(new_severity, cx);
18274        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18275            self.active_diagnostics = ActiveDiagnostic::None;
18276            self.inline_diagnostics_update = Task::ready(());
18277            self.inline_diagnostics.clear();
18278        } else {
18279            self.refresh_inline_diagnostics(false, window, cx);
18280        }
18281
18282        cx.notify();
18283    }
18284
18285    pub fn toggle_minimap(
18286        &mut self,
18287        _: &ToggleMinimap,
18288        window: &mut Window,
18289        cx: &mut Context<Editor>,
18290    ) {
18291        if self.supports_minimap(cx) {
18292            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18293        }
18294    }
18295
18296    fn refresh_inline_diagnostics(
18297        &mut self,
18298        debounce: bool,
18299        window: &mut Window,
18300        cx: &mut Context<Self>,
18301    ) {
18302        let max_severity = ProjectSettings::get_global(cx)
18303            .diagnostics
18304            .inline
18305            .max_severity
18306            .unwrap_or(self.diagnostics_max_severity);
18307
18308        if !self.inline_diagnostics_enabled()
18309            || !self.diagnostics_enabled()
18310            || !self.show_inline_diagnostics
18311            || max_severity == DiagnosticSeverity::Off
18312        {
18313            self.inline_diagnostics_update = Task::ready(());
18314            self.inline_diagnostics.clear();
18315            return;
18316        }
18317
18318        let debounce_ms = ProjectSettings::get_global(cx)
18319            .diagnostics
18320            .inline
18321            .update_debounce_ms;
18322        let debounce = if debounce && debounce_ms > 0 {
18323            Some(Duration::from_millis(debounce_ms))
18324        } else {
18325            None
18326        };
18327        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18328            if let Some(debounce) = debounce {
18329                cx.background_executor().timer(debounce).await;
18330            }
18331            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18332                editor
18333                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18334                    .ok()
18335            }) else {
18336                return;
18337            };
18338
18339            let new_inline_diagnostics = cx
18340                .background_spawn(async move {
18341                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18342                    for diagnostic_entry in
18343                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18344                    {
18345                        let message = diagnostic_entry
18346                            .diagnostic
18347                            .message
18348                            .split_once('\n')
18349                            .map(|(line, _)| line)
18350                            .map(SharedString::new)
18351                            .unwrap_or_else(|| {
18352                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18353                            });
18354                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18355                        let (Ok(i) | Err(i)) = inline_diagnostics
18356                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18357                        inline_diagnostics.insert(
18358                            i,
18359                            (
18360                                start_anchor,
18361                                InlineDiagnostic {
18362                                    message,
18363                                    group_id: diagnostic_entry.diagnostic.group_id,
18364                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18365                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18366                                    severity: diagnostic_entry.diagnostic.severity,
18367                                },
18368                            ),
18369                        );
18370                    }
18371                    inline_diagnostics
18372                })
18373                .await;
18374
18375            editor
18376                .update(cx, |editor, cx| {
18377                    editor.inline_diagnostics = new_inline_diagnostics;
18378                    cx.notify();
18379                })
18380                .ok();
18381        });
18382    }
18383
18384    fn pull_diagnostics(
18385        &mut self,
18386        buffer_id: Option<BufferId>,
18387        window: &Window,
18388        cx: &mut Context<Self>,
18389    ) -> Option<()> {
18390        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18391            return None;
18392        }
18393        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18394            .diagnostics
18395            .lsp_pull_diagnostics;
18396        if !pull_diagnostics_settings.enabled {
18397            return None;
18398        }
18399        let project = self.project()?.downgrade();
18400        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18401        let mut buffers = self.buffer.read(cx).all_buffers();
18402        buffers.retain(|buffer| {
18403            let buffer_id_to_retain = buffer.read(cx).remote_id();
18404            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18405                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18406        });
18407        if buffers.is_empty() {
18408            self.pull_diagnostics_task = Task::ready(());
18409            return None;
18410        }
18411
18412        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18413            cx.background_executor().timer(debounce).await;
18414
18415            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18416                buffers
18417                    .into_iter()
18418                    .filter_map(|buffer| {
18419                        project
18420                            .update(cx, |project, cx| {
18421                                project.lsp_store().update(cx, |lsp_store, cx| {
18422                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18423                                })
18424                            })
18425                            .ok()
18426                    })
18427                    .collect::<FuturesUnordered<_>>()
18428            }) else {
18429                return;
18430            };
18431
18432            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18433                match pull_task {
18434                    Ok(()) => {
18435                        if editor
18436                            .update_in(cx, |editor, window, cx| {
18437                                editor.update_diagnostics_state(window, cx);
18438                            })
18439                            .is_err()
18440                        {
18441                            return;
18442                        }
18443                    }
18444                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18445                }
18446            }
18447        });
18448
18449        Some(())
18450    }
18451
18452    pub fn set_selections_from_remote(
18453        &mut self,
18454        selections: Vec<Selection<Anchor>>,
18455        pending_selection: Option<Selection<Anchor>>,
18456        window: &mut Window,
18457        cx: &mut Context<Self>,
18458    ) {
18459        let old_cursor_position = self.selections.newest_anchor().head();
18460        self.selections
18461            .change_with(&self.display_snapshot(cx), |s| {
18462                s.select_anchors(selections);
18463                if let Some(pending_selection) = pending_selection {
18464                    s.set_pending(pending_selection, SelectMode::Character);
18465                } else {
18466                    s.clear_pending();
18467                }
18468            });
18469        self.selections_did_change(
18470            false,
18471            &old_cursor_position,
18472            SelectionEffects::default(),
18473            window,
18474            cx,
18475        );
18476    }
18477
18478    pub fn transact(
18479        &mut self,
18480        window: &mut Window,
18481        cx: &mut Context<Self>,
18482        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18483    ) -> Option<TransactionId> {
18484        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18485            this.start_transaction_at(Instant::now(), window, cx);
18486            update(this, window, cx);
18487            this.end_transaction_at(Instant::now(), cx)
18488        })
18489    }
18490
18491    pub fn start_transaction_at(
18492        &mut self,
18493        now: Instant,
18494        window: &mut Window,
18495        cx: &mut Context<Self>,
18496    ) -> Option<TransactionId> {
18497        self.end_selection(window, cx);
18498        if let Some(tx_id) = self
18499            .buffer
18500            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18501        {
18502            self.selection_history
18503                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18504            cx.emit(EditorEvent::TransactionBegun {
18505                transaction_id: tx_id,
18506            });
18507            Some(tx_id)
18508        } else {
18509            None
18510        }
18511    }
18512
18513    pub fn end_transaction_at(
18514        &mut self,
18515        now: Instant,
18516        cx: &mut Context<Self>,
18517    ) -> Option<TransactionId> {
18518        if let Some(transaction_id) = self
18519            .buffer
18520            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18521        {
18522            if let Some((_, end_selections)) =
18523                self.selection_history.transaction_mut(transaction_id)
18524            {
18525                *end_selections = Some(self.selections.disjoint_anchors_arc());
18526            } else {
18527                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18528            }
18529
18530            cx.emit(EditorEvent::Edited { transaction_id });
18531            Some(transaction_id)
18532        } else {
18533            None
18534        }
18535    }
18536
18537    pub fn modify_transaction_selection_history(
18538        &mut self,
18539        transaction_id: TransactionId,
18540        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18541    ) -> bool {
18542        self.selection_history
18543            .transaction_mut(transaction_id)
18544            .map(modify)
18545            .is_some()
18546    }
18547
18548    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18549        if self.selection_mark_mode {
18550            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18551                s.move_with(|_, sel| {
18552                    sel.collapse_to(sel.head(), SelectionGoal::None);
18553                });
18554            })
18555        }
18556        self.selection_mark_mode = true;
18557        cx.notify();
18558    }
18559
18560    pub fn swap_selection_ends(
18561        &mut self,
18562        _: &actions::SwapSelectionEnds,
18563        window: &mut Window,
18564        cx: &mut Context<Self>,
18565    ) {
18566        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18567            s.move_with(|_, sel| {
18568                if sel.start != sel.end {
18569                    sel.reversed = !sel.reversed
18570                }
18571            });
18572        });
18573        self.request_autoscroll(Autoscroll::newest(), cx);
18574        cx.notify();
18575    }
18576
18577    pub fn toggle_focus(
18578        workspace: &mut Workspace,
18579        _: &actions::ToggleFocus,
18580        window: &mut Window,
18581        cx: &mut Context<Workspace>,
18582    ) {
18583        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18584            return;
18585        };
18586        workspace.activate_item(&item, true, true, window, cx);
18587    }
18588
18589    pub fn toggle_fold(
18590        &mut self,
18591        _: &actions::ToggleFold,
18592        window: &mut Window,
18593        cx: &mut Context<Self>,
18594    ) {
18595        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18596            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18597            let selection = self.selections.newest::<Point>(&display_map);
18598
18599            let range = if selection.is_empty() {
18600                let point = selection.head().to_display_point(&display_map);
18601                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18602                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18603                    .to_point(&display_map);
18604                start..end
18605            } else {
18606                selection.range()
18607            };
18608            if display_map.folds_in_range(range).next().is_some() {
18609                self.unfold_lines(&Default::default(), window, cx)
18610            } else {
18611                self.fold(&Default::default(), window, cx)
18612            }
18613        } else {
18614            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18615            let buffer_ids: HashSet<_> = self
18616                .selections
18617                .disjoint_anchor_ranges()
18618                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18619                .collect();
18620
18621            let should_unfold = buffer_ids
18622                .iter()
18623                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18624
18625            for buffer_id in buffer_ids {
18626                if should_unfold {
18627                    self.unfold_buffer(buffer_id, cx);
18628                } else {
18629                    self.fold_buffer(buffer_id, cx);
18630                }
18631            }
18632        }
18633    }
18634
18635    pub fn toggle_fold_recursive(
18636        &mut self,
18637        _: &actions::ToggleFoldRecursive,
18638        window: &mut Window,
18639        cx: &mut Context<Self>,
18640    ) {
18641        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18642
18643        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18644        let range = if selection.is_empty() {
18645            let point = selection.head().to_display_point(&display_map);
18646            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18647            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18648                .to_point(&display_map);
18649            start..end
18650        } else {
18651            selection.range()
18652        };
18653        if display_map.folds_in_range(range).next().is_some() {
18654            self.unfold_recursive(&Default::default(), window, cx)
18655        } else {
18656            self.fold_recursive(&Default::default(), window, cx)
18657        }
18658    }
18659
18660    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18661        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18662            let mut to_fold = Vec::new();
18663            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18664            let selections = self.selections.all_adjusted(&display_map);
18665
18666            for selection in selections {
18667                let range = selection.range().sorted();
18668                let buffer_start_row = range.start.row;
18669
18670                if range.start.row != range.end.row {
18671                    let mut found = false;
18672                    let mut row = range.start.row;
18673                    while row <= range.end.row {
18674                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18675                        {
18676                            found = true;
18677                            row = crease.range().end.row + 1;
18678                            to_fold.push(crease);
18679                        } else {
18680                            row += 1
18681                        }
18682                    }
18683                    if found {
18684                        continue;
18685                    }
18686                }
18687
18688                for row in (0..=range.start.row).rev() {
18689                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18690                        && crease.range().end.row >= buffer_start_row
18691                    {
18692                        to_fold.push(crease);
18693                        if row <= range.start.row {
18694                            break;
18695                        }
18696                    }
18697                }
18698            }
18699
18700            self.fold_creases(to_fold, true, window, cx);
18701        } else {
18702            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18703            let buffer_ids = self
18704                .selections
18705                .disjoint_anchor_ranges()
18706                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18707                .collect::<HashSet<_>>();
18708            for buffer_id in buffer_ids {
18709                self.fold_buffer(buffer_id, cx);
18710            }
18711        }
18712    }
18713
18714    pub fn toggle_fold_all(
18715        &mut self,
18716        _: &actions::ToggleFoldAll,
18717        window: &mut Window,
18718        cx: &mut Context<Self>,
18719    ) {
18720        if self.buffer.read(cx).is_singleton() {
18721            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18722            let has_folds = display_map
18723                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
18724                .next()
18725                .is_some();
18726
18727            if has_folds {
18728                self.unfold_all(&actions::UnfoldAll, window, cx);
18729            } else {
18730                self.fold_all(&actions::FoldAll, window, cx);
18731            }
18732        } else {
18733            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18734            let should_unfold = buffer_ids
18735                .iter()
18736                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18737
18738            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18739                editor
18740                    .update_in(cx, |editor, _, cx| {
18741                        for buffer_id in buffer_ids {
18742                            if should_unfold {
18743                                editor.unfold_buffer(buffer_id, cx);
18744                            } else {
18745                                editor.fold_buffer(buffer_id, cx);
18746                            }
18747                        }
18748                    })
18749                    .ok();
18750            });
18751        }
18752    }
18753
18754    fn fold_at_level(
18755        &mut self,
18756        fold_at: &FoldAtLevel,
18757        window: &mut Window,
18758        cx: &mut Context<Self>,
18759    ) {
18760        if !self.buffer.read(cx).is_singleton() {
18761            return;
18762        }
18763
18764        let fold_at_level = fold_at.0;
18765        let snapshot = self.buffer.read(cx).snapshot(cx);
18766        let mut to_fold = Vec::new();
18767        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18768
18769        let row_ranges_to_keep: Vec<Range<u32>> = self
18770            .selections
18771            .all::<Point>(&self.display_snapshot(cx))
18772            .into_iter()
18773            .map(|sel| sel.start.row..sel.end.row)
18774            .collect();
18775
18776        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18777            while start_row < end_row {
18778                match self
18779                    .snapshot(window, cx)
18780                    .crease_for_buffer_row(MultiBufferRow(start_row))
18781                {
18782                    Some(crease) => {
18783                        let nested_start_row = crease.range().start.row + 1;
18784                        let nested_end_row = crease.range().end.row;
18785
18786                        if current_level < fold_at_level {
18787                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18788                        } else if current_level == fold_at_level {
18789                            // Fold iff there is no selection completely contained within the fold region
18790                            if !row_ranges_to_keep.iter().any(|selection| {
18791                                selection.end >= nested_start_row
18792                                    && selection.start <= nested_end_row
18793                            }) {
18794                                to_fold.push(crease);
18795                            }
18796                        }
18797
18798                        start_row = nested_end_row + 1;
18799                    }
18800                    None => start_row += 1,
18801                }
18802            }
18803        }
18804
18805        self.fold_creases(to_fold, true, window, cx);
18806    }
18807
18808    pub fn fold_at_level_1(
18809        &mut self,
18810        _: &actions::FoldAtLevel1,
18811        window: &mut Window,
18812        cx: &mut Context<Self>,
18813    ) {
18814        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18815    }
18816
18817    pub fn fold_at_level_2(
18818        &mut self,
18819        _: &actions::FoldAtLevel2,
18820        window: &mut Window,
18821        cx: &mut Context<Self>,
18822    ) {
18823        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18824    }
18825
18826    pub fn fold_at_level_3(
18827        &mut self,
18828        _: &actions::FoldAtLevel3,
18829        window: &mut Window,
18830        cx: &mut Context<Self>,
18831    ) {
18832        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18833    }
18834
18835    pub fn fold_at_level_4(
18836        &mut self,
18837        _: &actions::FoldAtLevel4,
18838        window: &mut Window,
18839        cx: &mut Context<Self>,
18840    ) {
18841        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18842    }
18843
18844    pub fn fold_at_level_5(
18845        &mut self,
18846        _: &actions::FoldAtLevel5,
18847        window: &mut Window,
18848        cx: &mut Context<Self>,
18849    ) {
18850        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18851    }
18852
18853    pub fn fold_at_level_6(
18854        &mut self,
18855        _: &actions::FoldAtLevel6,
18856        window: &mut Window,
18857        cx: &mut Context<Self>,
18858    ) {
18859        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18860    }
18861
18862    pub fn fold_at_level_7(
18863        &mut self,
18864        _: &actions::FoldAtLevel7,
18865        window: &mut Window,
18866        cx: &mut Context<Self>,
18867    ) {
18868        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18869    }
18870
18871    pub fn fold_at_level_8(
18872        &mut self,
18873        _: &actions::FoldAtLevel8,
18874        window: &mut Window,
18875        cx: &mut Context<Self>,
18876    ) {
18877        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18878    }
18879
18880    pub fn fold_at_level_9(
18881        &mut self,
18882        _: &actions::FoldAtLevel9,
18883        window: &mut Window,
18884        cx: &mut Context<Self>,
18885    ) {
18886        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18887    }
18888
18889    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18890        if self.buffer.read(cx).is_singleton() {
18891            let mut fold_ranges = Vec::new();
18892            let snapshot = self.buffer.read(cx).snapshot(cx);
18893
18894            for row in 0..snapshot.max_row().0 {
18895                if let Some(foldable_range) = self
18896                    .snapshot(window, cx)
18897                    .crease_for_buffer_row(MultiBufferRow(row))
18898                {
18899                    fold_ranges.push(foldable_range);
18900                }
18901            }
18902
18903            self.fold_creases(fold_ranges, true, window, cx);
18904        } else {
18905            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18906                editor
18907                    .update_in(cx, |editor, _, cx| {
18908                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18909                            editor.fold_buffer(buffer_id, cx);
18910                        }
18911                    })
18912                    .ok();
18913            });
18914        }
18915    }
18916
18917    pub fn fold_function_bodies(
18918        &mut self,
18919        _: &actions::FoldFunctionBodies,
18920        window: &mut Window,
18921        cx: &mut Context<Self>,
18922    ) {
18923        let snapshot = self.buffer.read(cx).snapshot(cx);
18924
18925        let ranges = snapshot
18926            .text_object_ranges(
18927                MultiBufferOffset(0)..snapshot.len(),
18928                TreeSitterOptions::default(),
18929            )
18930            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18931            .collect::<Vec<_>>();
18932
18933        let creases = ranges
18934            .into_iter()
18935            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18936            .collect();
18937
18938        self.fold_creases(creases, true, window, cx);
18939    }
18940
18941    pub fn fold_recursive(
18942        &mut self,
18943        _: &actions::FoldRecursive,
18944        window: &mut Window,
18945        cx: &mut Context<Self>,
18946    ) {
18947        let mut to_fold = Vec::new();
18948        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18949        let selections = self.selections.all_adjusted(&display_map);
18950
18951        for selection in selections {
18952            let range = selection.range().sorted();
18953            let buffer_start_row = range.start.row;
18954
18955            if range.start.row != range.end.row {
18956                let mut found = false;
18957                for row in range.start.row..=range.end.row {
18958                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18959                        found = true;
18960                        to_fold.push(crease);
18961                    }
18962                }
18963                if found {
18964                    continue;
18965                }
18966            }
18967
18968            for row in (0..=range.start.row).rev() {
18969                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18970                    if crease.range().end.row >= buffer_start_row {
18971                        to_fold.push(crease);
18972                    } else {
18973                        break;
18974                    }
18975                }
18976            }
18977        }
18978
18979        self.fold_creases(to_fold, true, window, cx);
18980    }
18981
18982    pub fn fold_at(
18983        &mut self,
18984        buffer_row: MultiBufferRow,
18985        window: &mut Window,
18986        cx: &mut Context<Self>,
18987    ) {
18988        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18989
18990        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18991            let autoscroll = self
18992                .selections
18993                .all::<Point>(&display_map)
18994                .iter()
18995                .any(|selection| crease.range().overlaps(&selection.range()));
18996
18997            self.fold_creases(vec![crease], autoscroll, window, cx);
18998        }
18999    }
19000
19001    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19002        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19003            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19004            let buffer = display_map.buffer_snapshot();
19005            let selections = self.selections.all::<Point>(&display_map);
19006            let ranges = selections
19007                .iter()
19008                .map(|s| {
19009                    let range = s.display_range(&display_map).sorted();
19010                    let mut start = range.start.to_point(&display_map);
19011                    let mut end = range.end.to_point(&display_map);
19012                    start.column = 0;
19013                    end.column = buffer.line_len(MultiBufferRow(end.row));
19014                    start..end
19015                })
19016                .collect::<Vec<_>>();
19017
19018            self.unfold_ranges(&ranges, true, true, cx);
19019        } else {
19020            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19021            let buffer_ids = self
19022                .selections
19023                .disjoint_anchor_ranges()
19024                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19025                .collect::<HashSet<_>>();
19026            for buffer_id in buffer_ids {
19027                self.unfold_buffer(buffer_id, cx);
19028            }
19029        }
19030    }
19031
19032    pub fn unfold_recursive(
19033        &mut self,
19034        _: &UnfoldRecursive,
19035        _window: &mut Window,
19036        cx: &mut Context<Self>,
19037    ) {
19038        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19039        let selections = self.selections.all::<Point>(&display_map);
19040        let ranges = selections
19041            .iter()
19042            .map(|s| {
19043                let mut range = s.display_range(&display_map).sorted();
19044                *range.start.column_mut() = 0;
19045                *range.end.column_mut() = display_map.line_len(range.end.row());
19046                let start = range.start.to_point(&display_map);
19047                let end = range.end.to_point(&display_map);
19048                start..end
19049            })
19050            .collect::<Vec<_>>();
19051
19052        self.unfold_ranges(&ranges, true, true, cx);
19053    }
19054
19055    pub fn unfold_at(
19056        &mut self,
19057        buffer_row: MultiBufferRow,
19058        _window: &mut Window,
19059        cx: &mut Context<Self>,
19060    ) {
19061        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19062
19063        let intersection_range = Point::new(buffer_row.0, 0)
19064            ..Point::new(
19065                buffer_row.0,
19066                display_map.buffer_snapshot().line_len(buffer_row),
19067            );
19068
19069        let autoscroll = self
19070            .selections
19071            .all::<Point>(&display_map)
19072            .iter()
19073            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19074
19075        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19076    }
19077
19078    pub fn unfold_all(
19079        &mut self,
19080        _: &actions::UnfoldAll,
19081        _window: &mut Window,
19082        cx: &mut Context<Self>,
19083    ) {
19084        if self.buffer.read(cx).is_singleton() {
19085            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19086            self.unfold_ranges(
19087                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19088                true,
19089                true,
19090                cx,
19091            );
19092        } else {
19093            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19094                editor
19095                    .update(cx, |editor, cx| {
19096                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19097                            editor.unfold_buffer(buffer_id, cx);
19098                        }
19099                    })
19100                    .ok();
19101            });
19102        }
19103    }
19104
19105    pub fn fold_selected_ranges(
19106        &mut self,
19107        _: &FoldSelectedRanges,
19108        window: &mut Window,
19109        cx: &mut Context<Self>,
19110    ) {
19111        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19112        let selections = self.selections.all_adjusted(&display_map);
19113        let ranges = selections
19114            .into_iter()
19115            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19116            .collect::<Vec<_>>();
19117        self.fold_creases(ranges, true, window, cx);
19118    }
19119
19120    pub fn fold_ranges<T: ToOffset + Clone>(
19121        &mut self,
19122        ranges: Vec<Range<T>>,
19123        auto_scroll: bool,
19124        window: &mut Window,
19125        cx: &mut Context<Self>,
19126    ) {
19127        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19128        let ranges = ranges
19129            .into_iter()
19130            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19131            .collect::<Vec<_>>();
19132        self.fold_creases(ranges, auto_scroll, window, cx);
19133    }
19134
19135    pub fn fold_creases<T: ToOffset + Clone>(
19136        &mut self,
19137        creases: Vec<Crease<T>>,
19138        auto_scroll: bool,
19139        _window: &mut Window,
19140        cx: &mut Context<Self>,
19141    ) {
19142        if creases.is_empty() {
19143            return;
19144        }
19145
19146        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19147
19148        if auto_scroll {
19149            self.request_autoscroll(Autoscroll::fit(), cx);
19150        }
19151
19152        cx.notify();
19153
19154        self.scrollbar_marker_state.dirty = true;
19155        self.folds_did_change(cx);
19156    }
19157
19158    /// Removes any folds whose ranges intersect any of the given ranges.
19159    pub fn unfold_ranges<T: ToOffset + Clone>(
19160        &mut self,
19161        ranges: &[Range<T>],
19162        inclusive: bool,
19163        auto_scroll: bool,
19164        cx: &mut Context<Self>,
19165    ) {
19166        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19167            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19168        });
19169        self.folds_did_change(cx);
19170    }
19171
19172    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19173        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19174            return;
19175        }
19176
19177        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19178        self.display_map.update(cx, |display_map, cx| {
19179            display_map.fold_buffers([buffer_id], cx)
19180        });
19181
19182        let snapshot = self.display_snapshot(cx);
19183        self.selections.change_with(&snapshot, |selections| {
19184            selections.remove_selections_from_buffer(buffer_id);
19185        });
19186
19187        cx.emit(EditorEvent::BufferFoldToggled {
19188            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19189            folded: true,
19190        });
19191        cx.notify();
19192    }
19193
19194    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19195        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19196            return;
19197        }
19198        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19199        self.display_map.update(cx, |display_map, cx| {
19200            display_map.unfold_buffers([buffer_id], cx);
19201        });
19202        cx.emit(EditorEvent::BufferFoldToggled {
19203            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19204            folded: false,
19205        });
19206        cx.notify();
19207    }
19208
19209    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19210        self.display_map.read(cx).is_buffer_folded(buffer)
19211    }
19212
19213    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19214        self.display_map.read(cx).folded_buffers()
19215    }
19216
19217    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19218        self.display_map.update(cx, |display_map, cx| {
19219            display_map.disable_header_for_buffer(buffer_id, cx);
19220        });
19221        cx.notify();
19222    }
19223
19224    /// Removes any folds with the given ranges.
19225    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19226        &mut self,
19227        ranges: &[Range<T>],
19228        type_id: TypeId,
19229        auto_scroll: bool,
19230        cx: &mut Context<Self>,
19231    ) {
19232        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19233            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19234        });
19235        self.folds_did_change(cx);
19236    }
19237
19238    fn remove_folds_with<T: ToOffset + Clone>(
19239        &mut self,
19240        ranges: &[Range<T>],
19241        auto_scroll: bool,
19242        cx: &mut Context<Self>,
19243        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19244    ) {
19245        if ranges.is_empty() {
19246            return;
19247        }
19248
19249        let mut buffers_affected = HashSet::default();
19250        let multi_buffer = self.buffer().read(cx);
19251        for range in ranges {
19252            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19253                buffers_affected.insert(buffer.read(cx).remote_id());
19254            };
19255        }
19256
19257        self.display_map.update(cx, update);
19258
19259        if auto_scroll {
19260            self.request_autoscroll(Autoscroll::fit(), cx);
19261        }
19262
19263        cx.notify();
19264        self.scrollbar_marker_state.dirty = true;
19265        self.active_indent_guides_state.dirty = true;
19266    }
19267
19268    pub fn update_renderer_widths(
19269        &mut self,
19270        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19271        cx: &mut Context<Self>,
19272    ) -> bool {
19273        self.display_map
19274            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19275    }
19276
19277    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19278        self.display_map.read(cx).fold_placeholder.clone()
19279    }
19280
19281    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19282        self.use_base_text_line_numbers = show;
19283    }
19284
19285    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19286        self.buffer.update(cx, |buffer, cx| {
19287            buffer.set_all_diff_hunks_expanded(cx);
19288        });
19289    }
19290
19291    pub fn expand_all_diff_hunks(
19292        &mut self,
19293        _: &ExpandAllDiffHunks,
19294        _window: &mut Window,
19295        cx: &mut Context<Self>,
19296    ) {
19297        self.buffer.update(cx, |buffer, cx| {
19298            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19299        });
19300    }
19301
19302    pub fn collapse_all_diff_hunks(
19303        &mut self,
19304        _: &CollapseAllDiffHunks,
19305        _window: &mut Window,
19306        cx: &mut Context<Self>,
19307    ) {
19308        self.buffer.update(cx, |buffer, cx| {
19309            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19310        });
19311    }
19312
19313    pub fn toggle_selected_diff_hunks(
19314        &mut self,
19315        _: &ToggleSelectedDiffHunks,
19316        _window: &mut Window,
19317        cx: &mut Context<Self>,
19318    ) {
19319        let ranges: Vec<_> = self
19320            .selections
19321            .disjoint_anchors()
19322            .iter()
19323            .map(|s| s.range())
19324            .collect();
19325        self.toggle_diff_hunks_in_ranges(ranges, cx);
19326    }
19327
19328    pub fn diff_hunks_in_ranges<'a>(
19329        &'a self,
19330        ranges: &'a [Range<Anchor>],
19331        buffer: &'a MultiBufferSnapshot,
19332    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19333        ranges.iter().flat_map(move |range| {
19334            let end_excerpt_id = range.end.excerpt_id;
19335            let range = range.to_point(buffer);
19336            let mut peek_end = range.end;
19337            if range.end.row < buffer.max_row().0 {
19338                peek_end = Point::new(range.end.row + 1, 0);
19339            }
19340            buffer
19341                .diff_hunks_in_range(range.start..peek_end)
19342                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19343        })
19344    }
19345
19346    pub fn has_stageable_diff_hunks_in_ranges(
19347        &self,
19348        ranges: &[Range<Anchor>],
19349        snapshot: &MultiBufferSnapshot,
19350    ) -> bool {
19351        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19352        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19353    }
19354
19355    pub fn toggle_staged_selected_diff_hunks(
19356        &mut self,
19357        _: &::git::ToggleStaged,
19358        _: &mut Window,
19359        cx: &mut Context<Self>,
19360    ) {
19361        let snapshot = self.buffer.read(cx).snapshot(cx);
19362        let ranges: Vec<_> = self
19363            .selections
19364            .disjoint_anchors()
19365            .iter()
19366            .map(|s| s.range())
19367            .collect();
19368        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19369        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19370    }
19371
19372    pub fn set_render_diff_hunk_controls(
19373        &mut self,
19374        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19375        cx: &mut Context<Self>,
19376    ) {
19377        self.render_diff_hunk_controls = render_diff_hunk_controls;
19378        cx.notify();
19379    }
19380
19381    pub fn stage_and_next(
19382        &mut self,
19383        _: &::git::StageAndNext,
19384        window: &mut Window,
19385        cx: &mut Context<Self>,
19386    ) {
19387        self.do_stage_or_unstage_and_next(true, window, cx);
19388    }
19389
19390    pub fn unstage_and_next(
19391        &mut self,
19392        _: &::git::UnstageAndNext,
19393        window: &mut Window,
19394        cx: &mut Context<Self>,
19395    ) {
19396        self.do_stage_or_unstage_and_next(false, window, cx);
19397    }
19398
19399    pub fn stage_or_unstage_diff_hunks(
19400        &mut self,
19401        stage: bool,
19402        ranges: Vec<Range<Anchor>>,
19403        cx: &mut Context<Self>,
19404    ) {
19405        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19406        cx.spawn(async move |this, cx| {
19407            task.await?;
19408            this.update(cx, |this, cx| {
19409                let snapshot = this.buffer.read(cx).snapshot(cx);
19410                let chunk_by = this
19411                    .diff_hunks_in_ranges(&ranges, &snapshot)
19412                    .chunk_by(|hunk| hunk.buffer_id);
19413                for (buffer_id, hunks) in &chunk_by {
19414                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19415                }
19416            })
19417        })
19418        .detach_and_log_err(cx);
19419    }
19420
19421    fn save_buffers_for_ranges_if_needed(
19422        &mut self,
19423        ranges: &[Range<Anchor>],
19424        cx: &mut Context<Editor>,
19425    ) -> Task<Result<()>> {
19426        let multibuffer = self.buffer.read(cx);
19427        let snapshot = multibuffer.read(cx);
19428        let buffer_ids: HashSet<_> = ranges
19429            .iter()
19430            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19431            .collect();
19432        drop(snapshot);
19433
19434        let mut buffers = HashSet::default();
19435        for buffer_id in buffer_ids {
19436            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19437                let buffer = buffer_entity.read(cx);
19438                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19439                {
19440                    buffers.insert(buffer_entity);
19441                }
19442            }
19443        }
19444
19445        if let Some(project) = &self.project {
19446            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19447        } else {
19448            Task::ready(Ok(()))
19449        }
19450    }
19451
19452    fn do_stage_or_unstage_and_next(
19453        &mut self,
19454        stage: bool,
19455        window: &mut Window,
19456        cx: &mut Context<Self>,
19457    ) {
19458        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19459
19460        if ranges.iter().any(|range| range.start != range.end) {
19461            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19462            return;
19463        }
19464
19465        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19466        let snapshot = self.snapshot(window, cx);
19467        let position = self
19468            .selections
19469            .newest::<Point>(&snapshot.display_snapshot)
19470            .head();
19471        let mut row = snapshot
19472            .buffer_snapshot()
19473            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19474            .find(|hunk| hunk.row_range.start.0 > position.row)
19475            .map(|hunk| hunk.row_range.start);
19476
19477        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19478        // Outside of the project diff editor, wrap around to the beginning.
19479        if !all_diff_hunks_expanded {
19480            row = row.or_else(|| {
19481                snapshot
19482                    .buffer_snapshot()
19483                    .diff_hunks_in_range(Point::zero()..position)
19484                    .find(|hunk| hunk.row_range.end.0 < position.row)
19485                    .map(|hunk| hunk.row_range.start)
19486            });
19487        }
19488
19489        if let Some(row) = row {
19490            let destination = Point::new(row.0, 0);
19491            let autoscroll = Autoscroll::center();
19492
19493            self.unfold_ranges(&[destination..destination], false, false, cx);
19494            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19495                s.select_ranges([destination..destination]);
19496            });
19497        }
19498    }
19499
19500    fn do_stage_or_unstage(
19501        &self,
19502        stage: bool,
19503        buffer_id: BufferId,
19504        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19505        cx: &mut App,
19506    ) -> Option<()> {
19507        let project = self.project()?;
19508        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19509        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19510        let buffer_snapshot = buffer.read(cx).snapshot();
19511        let file_exists = buffer_snapshot
19512            .file()
19513            .is_some_and(|file| file.disk_state().exists());
19514        diff.update(cx, |diff, cx| {
19515            diff.stage_or_unstage_hunks(
19516                stage,
19517                &hunks
19518                    .map(|hunk| buffer_diff::DiffHunk {
19519                        buffer_range: hunk.buffer_range,
19520                        // We don't need to pass in word diffs here because they're only used for rendering and
19521                        // this function changes internal state
19522                        base_word_diffs: Vec::default(),
19523                        buffer_word_diffs: Vec::default(),
19524                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19525                            ..hunk.diff_base_byte_range.end.0,
19526                        secondary_status: hunk.secondary_status,
19527                        range: Point::zero()..Point::zero(), // unused
19528                    })
19529                    .collect::<Vec<_>>(),
19530                &buffer_snapshot,
19531                file_exists,
19532                cx,
19533            )
19534        });
19535        None
19536    }
19537
19538    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19539        let ranges: Vec<_> = self
19540            .selections
19541            .disjoint_anchors()
19542            .iter()
19543            .map(|s| s.range())
19544            .collect();
19545        self.buffer
19546            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19547    }
19548
19549    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19550        self.buffer.update(cx, |buffer, cx| {
19551            let ranges = vec![Anchor::min()..Anchor::max()];
19552            if !buffer.all_diff_hunks_expanded()
19553                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19554            {
19555                buffer.collapse_diff_hunks(ranges, cx);
19556                true
19557            } else {
19558                false
19559            }
19560        })
19561    }
19562
19563    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19564        if self.buffer.read(cx).all_diff_hunks_expanded() {
19565            return true;
19566        }
19567        let ranges = vec![Anchor::min()..Anchor::max()];
19568        self.buffer
19569            .read(cx)
19570            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19571    }
19572
19573    fn toggle_diff_hunks_in_ranges(
19574        &mut self,
19575        ranges: Vec<Range<Anchor>>,
19576        cx: &mut Context<Editor>,
19577    ) {
19578        self.buffer.update(cx, |buffer, cx| {
19579            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19580            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19581        })
19582    }
19583
19584    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19585        self.buffer.update(cx, |buffer, cx| {
19586            let snapshot = buffer.snapshot(cx);
19587            let excerpt_id = range.end.excerpt_id;
19588            let point_range = range.to_point(&snapshot);
19589            let expand = !buffer.single_hunk_is_expanded(range, cx);
19590            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19591        })
19592    }
19593
19594    pub(crate) fn apply_all_diff_hunks(
19595        &mut self,
19596        _: &ApplyAllDiffHunks,
19597        window: &mut Window,
19598        cx: &mut Context<Self>,
19599    ) {
19600        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19601
19602        let buffers = self.buffer.read(cx).all_buffers();
19603        for branch_buffer in buffers {
19604            branch_buffer.update(cx, |branch_buffer, cx| {
19605                branch_buffer.merge_into_base(Vec::new(), cx);
19606            });
19607        }
19608
19609        if let Some(project) = self.project.clone() {
19610            self.save(
19611                SaveOptions {
19612                    format: true,
19613                    autosave: false,
19614                },
19615                project,
19616                window,
19617                cx,
19618            )
19619            .detach_and_log_err(cx);
19620        }
19621    }
19622
19623    pub(crate) fn apply_selected_diff_hunks(
19624        &mut self,
19625        _: &ApplyDiffHunk,
19626        window: &mut Window,
19627        cx: &mut Context<Self>,
19628    ) {
19629        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19630        let snapshot = self.snapshot(window, cx);
19631        let hunks = snapshot.hunks_for_ranges(
19632            self.selections
19633                .all(&snapshot.display_snapshot)
19634                .into_iter()
19635                .map(|selection| selection.range()),
19636        );
19637        let mut ranges_by_buffer = HashMap::default();
19638        self.transact(window, cx, |editor, _window, cx| {
19639            for hunk in hunks {
19640                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19641                    ranges_by_buffer
19642                        .entry(buffer.clone())
19643                        .or_insert_with(Vec::new)
19644                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19645                }
19646            }
19647
19648            for (buffer, ranges) in ranges_by_buffer {
19649                buffer.update(cx, |buffer, cx| {
19650                    buffer.merge_into_base(ranges, cx);
19651                });
19652            }
19653        });
19654
19655        if let Some(project) = self.project.clone() {
19656            self.save(
19657                SaveOptions {
19658                    format: true,
19659                    autosave: false,
19660                },
19661                project,
19662                window,
19663                cx,
19664            )
19665            .detach_and_log_err(cx);
19666        }
19667    }
19668
19669    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19670        if hovered != self.gutter_hovered {
19671            self.gutter_hovered = hovered;
19672            cx.notify();
19673        }
19674    }
19675
19676    pub fn insert_blocks(
19677        &mut self,
19678        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19679        autoscroll: Option<Autoscroll>,
19680        cx: &mut Context<Self>,
19681    ) -> Vec<CustomBlockId> {
19682        let blocks = self
19683            .display_map
19684            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19685        if let Some(autoscroll) = autoscroll {
19686            self.request_autoscroll(autoscroll, cx);
19687        }
19688        cx.notify();
19689        blocks
19690    }
19691
19692    pub fn resize_blocks(
19693        &mut self,
19694        heights: HashMap<CustomBlockId, u32>,
19695        autoscroll: Option<Autoscroll>,
19696        cx: &mut Context<Self>,
19697    ) {
19698        self.display_map
19699            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19700        if let Some(autoscroll) = autoscroll {
19701            self.request_autoscroll(autoscroll, cx);
19702        }
19703        cx.notify();
19704    }
19705
19706    pub fn replace_blocks(
19707        &mut self,
19708        renderers: HashMap<CustomBlockId, RenderBlock>,
19709        autoscroll: Option<Autoscroll>,
19710        cx: &mut Context<Self>,
19711    ) {
19712        self.display_map
19713            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19714        if let Some(autoscroll) = autoscroll {
19715            self.request_autoscroll(autoscroll, cx);
19716        }
19717        cx.notify();
19718    }
19719
19720    pub fn remove_blocks(
19721        &mut self,
19722        block_ids: HashSet<CustomBlockId>,
19723        autoscroll: Option<Autoscroll>,
19724        cx: &mut Context<Self>,
19725    ) {
19726        self.display_map.update(cx, |display_map, cx| {
19727            display_map.remove_blocks(block_ids, cx)
19728        });
19729        if let Some(autoscroll) = autoscroll {
19730            self.request_autoscroll(autoscroll, cx);
19731        }
19732        cx.notify();
19733    }
19734
19735    pub fn row_for_block(
19736        &self,
19737        block_id: CustomBlockId,
19738        cx: &mut Context<Self>,
19739    ) -> Option<DisplayRow> {
19740        self.display_map
19741            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19742    }
19743
19744    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19745        self.focused_block = Some(focused_block);
19746    }
19747
19748    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19749        self.focused_block.take()
19750    }
19751
19752    pub fn insert_creases(
19753        &mut self,
19754        creases: impl IntoIterator<Item = Crease<Anchor>>,
19755        cx: &mut Context<Self>,
19756    ) -> Vec<CreaseId> {
19757        self.display_map
19758            .update(cx, |map, cx| map.insert_creases(creases, cx))
19759    }
19760
19761    pub fn remove_creases(
19762        &mut self,
19763        ids: impl IntoIterator<Item = CreaseId>,
19764        cx: &mut Context<Self>,
19765    ) -> Vec<(CreaseId, Range<Anchor>)> {
19766        self.display_map
19767            .update(cx, |map, cx| map.remove_creases(ids, cx))
19768    }
19769
19770    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19771        self.display_map
19772            .update(cx, |map, cx| map.snapshot(cx))
19773            .longest_row()
19774    }
19775
19776    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19777        self.display_map
19778            .update(cx, |map, cx| map.snapshot(cx))
19779            .max_point()
19780    }
19781
19782    pub fn text(&self, cx: &App) -> String {
19783        self.buffer.read(cx).read(cx).text()
19784    }
19785
19786    pub fn is_empty(&self, cx: &App) -> bool {
19787        self.buffer.read(cx).read(cx).is_empty()
19788    }
19789
19790    pub fn text_option(&self, cx: &App) -> Option<String> {
19791        let text = self.text(cx);
19792        let text = text.trim();
19793
19794        if text.is_empty() {
19795            return None;
19796        }
19797
19798        Some(text.to_string())
19799    }
19800
19801    pub fn set_text(
19802        &mut self,
19803        text: impl Into<Arc<str>>,
19804        window: &mut Window,
19805        cx: &mut Context<Self>,
19806    ) {
19807        self.transact(window, cx, |this, _, cx| {
19808            this.buffer
19809                .read(cx)
19810                .as_singleton()
19811                .expect("you can only call set_text on editors for singleton buffers")
19812                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19813        });
19814    }
19815
19816    pub fn display_text(&self, cx: &mut App) -> String {
19817        self.display_map
19818            .update(cx, |map, cx| map.snapshot(cx))
19819            .text()
19820    }
19821
19822    fn create_minimap(
19823        &self,
19824        minimap_settings: MinimapSettings,
19825        window: &mut Window,
19826        cx: &mut Context<Self>,
19827    ) -> Option<Entity<Self>> {
19828        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19829            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19830    }
19831
19832    fn initialize_new_minimap(
19833        &self,
19834        minimap_settings: MinimapSettings,
19835        window: &mut Window,
19836        cx: &mut Context<Self>,
19837    ) -> Entity<Self> {
19838        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19839
19840        let mut minimap = Editor::new_internal(
19841            EditorMode::Minimap {
19842                parent: cx.weak_entity(),
19843            },
19844            self.buffer.clone(),
19845            None,
19846            Some(self.display_map.clone()),
19847            window,
19848            cx,
19849        );
19850        minimap.scroll_manager.clone_state(&self.scroll_manager);
19851        minimap.set_text_style_refinement(TextStyleRefinement {
19852            font_size: Some(MINIMAP_FONT_SIZE),
19853            font_weight: Some(MINIMAP_FONT_WEIGHT),
19854            ..Default::default()
19855        });
19856        minimap.update_minimap_configuration(minimap_settings, cx);
19857        cx.new(|_| minimap)
19858    }
19859
19860    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19861        let current_line_highlight = minimap_settings
19862            .current_line_highlight
19863            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19864        self.set_current_line_highlight(Some(current_line_highlight));
19865    }
19866
19867    pub fn minimap(&self) -> Option<&Entity<Self>> {
19868        self.minimap
19869            .as_ref()
19870            .filter(|_| self.minimap_visibility.visible())
19871    }
19872
19873    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19874        let mut wrap_guides = smallvec![];
19875
19876        if self.show_wrap_guides == Some(false) {
19877            return wrap_guides;
19878        }
19879
19880        let settings = self.buffer.read(cx).language_settings(cx);
19881        if settings.show_wrap_guides {
19882            match self.soft_wrap_mode(cx) {
19883                SoftWrap::Column(soft_wrap) => {
19884                    wrap_guides.push((soft_wrap as usize, true));
19885                }
19886                SoftWrap::Bounded(soft_wrap) => {
19887                    wrap_guides.push((soft_wrap as usize, true));
19888                }
19889                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19890            }
19891            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19892        }
19893
19894        wrap_guides
19895    }
19896
19897    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19898        let settings = self.buffer.read(cx).language_settings(cx);
19899        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19900        match mode {
19901            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19902                SoftWrap::None
19903            }
19904            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19905            language_settings::SoftWrap::PreferredLineLength => {
19906                SoftWrap::Column(settings.preferred_line_length)
19907            }
19908            language_settings::SoftWrap::Bounded => {
19909                SoftWrap::Bounded(settings.preferred_line_length)
19910            }
19911        }
19912    }
19913
19914    pub fn set_soft_wrap_mode(
19915        &mut self,
19916        mode: language_settings::SoftWrap,
19917
19918        cx: &mut Context<Self>,
19919    ) {
19920        self.soft_wrap_mode_override = Some(mode);
19921        cx.notify();
19922    }
19923
19924    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19925        self.hard_wrap = hard_wrap;
19926        cx.notify();
19927    }
19928
19929    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19930        self.text_style_refinement = Some(style);
19931    }
19932
19933    /// called by the Element so we know what style we were most recently rendered with.
19934    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19935        // We intentionally do not inform the display map about the minimap style
19936        // so that wrapping is not recalculated and stays consistent for the editor
19937        // and its linked minimap.
19938        if !self.mode.is_minimap() {
19939            let font = style.text.font();
19940            let font_size = style.text.font_size.to_pixels(window.rem_size());
19941            let display_map = self
19942                .placeholder_display_map
19943                .as_ref()
19944                .filter(|_| self.is_empty(cx))
19945                .unwrap_or(&self.display_map);
19946
19947            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19948        }
19949        self.style = Some(style);
19950    }
19951
19952    pub fn style(&self) -> Option<&EditorStyle> {
19953        self.style.as_ref()
19954    }
19955
19956    // Called by the element. This method is not designed to be called outside of the editor
19957    // element's layout code because it does not notify when rewrapping is computed synchronously.
19958    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19959        if self.is_empty(cx) {
19960            self.placeholder_display_map
19961                .as_ref()
19962                .map_or(false, |display_map| {
19963                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19964                })
19965        } else {
19966            self.display_map
19967                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19968        }
19969    }
19970
19971    pub fn set_soft_wrap(&mut self) {
19972        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19973    }
19974
19975    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19976        if self.soft_wrap_mode_override.is_some() {
19977            self.soft_wrap_mode_override.take();
19978        } else {
19979            let soft_wrap = match self.soft_wrap_mode(cx) {
19980                SoftWrap::GitDiff => return,
19981                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19982                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19983                    language_settings::SoftWrap::None
19984                }
19985            };
19986            self.soft_wrap_mode_override = Some(soft_wrap);
19987        }
19988        cx.notify();
19989    }
19990
19991    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19992        let Some(workspace) = self.workspace() else {
19993            return;
19994        };
19995        let fs = workspace.read(cx).app_state().fs.clone();
19996        let current_show = TabBarSettings::get_global(cx).show;
19997        update_settings_file(fs, cx, move |setting, _| {
19998            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19999        });
20000    }
20001
20002    pub fn toggle_indent_guides(
20003        &mut self,
20004        _: &ToggleIndentGuides,
20005        _: &mut Window,
20006        cx: &mut Context<Self>,
20007    ) {
20008        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20009            self.buffer
20010                .read(cx)
20011                .language_settings(cx)
20012                .indent_guides
20013                .enabled
20014        });
20015        self.show_indent_guides = Some(!currently_enabled);
20016        cx.notify();
20017    }
20018
20019    fn should_show_indent_guides(&self) -> Option<bool> {
20020        self.show_indent_guides
20021    }
20022
20023    pub fn toggle_line_numbers(
20024        &mut self,
20025        _: &ToggleLineNumbers,
20026        _: &mut Window,
20027        cx: &mut Context<Self>,
20028    ) {
20029        let mut editor_settings = EditorSettings::get_global(cx).clone();
20030        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20031        EditorSettings::override_global(editor_settings, cx);
20032    }
20033
20034    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20035        if let Some(show_line_numbers) = self.show_line_numbers {
20036            return show_line_numbers;
20037        }
20038        EditorSettings::get_global(cx).gutter.line_numbers
20039    }
20040
20041    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
20042        match (
20043            self.use_relative_line_numbers,
20044            EditorSettings::get_global(cx).relative_line_numbers,
20045        ) {
20046            (None, setting) => setting,
20047            (Some(false), _) => RelativeLineNumbers::Disabled,
20048            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20049            (Some(true), _) => RelativeLineNumbers::Enabled,
20050        }
20051    }
20052
20053    pub fn toggle_relative_line_numbers(
20054        &mut self,
20055        _: &ToggleRelativeLineNumbers,
20056        _: &mut Window,
20057        cx: &mut Context<Self>,
20058    ) {
20059        let is_relative = self.relative_line_numbers(cx);
20060        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20061    }
20062
20063    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20064        self.use_relative_line_numbers = is_relative;
20065        cx.notify();
20066    }
20067
20068    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20069        self.show_gutter = show_gutter;
20070        cx.notify();
20071    }
20072
20073    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20074        self.show_scrollbars = ScrollbarAxes {
20075            horizontal: show,
20076            vertical: show,
20077        };
20078        cx.notify();
20079    }
20080
20081    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20082        self.show_scrollbars.vertical = show;
20083        cx.notify();
20084    }
20085
20086    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20087        self.show_scrollbars.horizontal = show;
20088        cx.notify();
20089    }
20090
20091    pub fn set_minimap_visibility(
20092        &mut self,
20093        minimap_visibility: MinimapVisibility,
20094        window: &mut Window,
20095        cx: &mut Context<Self>,
20096    ) {
20097        if self.minimap_visibility != minimap_visibility {
20098            if minimap_visibility.visible() && self.minimap.is_none() {
20099                let minimap_settings = EditorSettings::get_global(cx).minimap;
20100                self.minimap =
20101                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20102            }
20103            self.minimap_visibility = minimap_visibility;
20104            cx.notify();
20105        }
20106    }
20107
20108    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20109        self.set_show_scrollbars(false, cx);
20110        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20111    }
20112
20113    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20114        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20115    }
20116
20117    /// Normally the text in full mode and auto height editors is padded on the
20118    /// left side by roughly half a character width for improved hit testing.
20119    ///
20120    /// Use this method to disable this for cases where this is not wanted (e.g.
20121    /// if you want to align the editor text with some other text above or below)
20122    /// or if you want to add this padding to single-line editors.
20123    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20124        self.offset_content = offset_content;
20125        cx.notify();
20126    }
20127
20128    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20129        self.show_line_numbers = Some(show_line_numbers);
20130        cx.notify();
20131    }
20132
20133    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20134        self.disable_expand_excerpt_buttons = true;
20135        cx.notify();
20136    }
20137
20138    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20139        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20140        cx.notify();
20141    }
20142
20143    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20144        self.show_code_actions = Some(show_code_actions);
20145        cx.notify();
20146    }
20147
20148    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20149        self.show_runnables = Some(show_runnables);
20150        cx.notify();
20151    }
20152
20153    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20154        self.show_breakpoints = Some(show_breakpoints);
20155        cx.notify();
20156    }
20157
20158    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20159        if self.display_map.read(cx).masked != masked {
20160            self.display_map.update(cx, |map, _| map.masked = masked);
20161        }
20162        cx.notify()
20163    }
20164
20165    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20166        self.show_wrap_guides = Some(show_wrap_guides);
20167        cx.notify();
20168    }
20169
20170    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20171        self.show_indent_guides = Some(show_indent_guides);
20172        cx.notify();
20173    }
20174
20175    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20176        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20177            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20178                && let Some(dir) = file.abs_path(cx).parent()
20179            {
20180                return Some(dir.to_owned());
20181            }
20182        }
20183
20184        None
20185    }
20186
20187    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20188        self.active_excerpt(cx)?
20189            .1
20190            .read(cx)
20191            .file()
20192            .and_then(|f| f.as_local())
20193    }
20194
20195    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20196        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20197            let buffer = buffer.read(cx);
20198            if let Some(project_path) = buffer.project_path(cx) {
20199                let project = self.project()?.read(cx);
20200                project.absolute_path(&project_path, cx)
20201            } else {
20202                buffer
20203                    .file()
20204                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20205            }
20206        })
20207    }
20208
20209    pub fn reveal_in_finder(
20210        &mut self,
20211        _: &RevealInFileManager,
20212        _window: &mut Window,
20213        cx: &mut Context<Self>,
20214    ) {
20215        if let Some(target) = self.target_file(cx) {
20216            cx.reveal_path(&target.abs_path(cx));
20217        }
20218    }
20219
20220    pub fn copy_path(
20221        &mut self,
20222        _: &zed_actions::workspace::CopyPath,
20223        _window: &mut Window,
20224        cx: &mut Context<Self>,
20225    ) {
20226        if let Some(path) = self.target_file_abs_path(cx)
20227            && let Some(path) = path.to_str()
20228        {
20229            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20230        } else {
20231            cx.propagate();
20232        }
20233    }
20234
20235    pub fn copy_relative_path(
20236        &mut self,
20237        _: &zed_actions::workspace::CopyRelativePath,
20238        _window: &mut Window,
20239        cx: &mut Context<Self>,
20240    ) {
20241        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20242            let project = self.project()?.read(cx);
20243            let path = buffer.read(cx).file()?.path();
20244            let path = path.display(project.path_style(cx));
20245            Some(path)
20246        }) {
20247            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20248        } else {
20249            cx.propagate();
20250        }
20251    }
20252
20253    /// Returns the project path for the editor's buffer, if any buffer is
20254    /// opened in the editor.
20255    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20256        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20257            buffer.read(cx).project_path(cx)
20258        } else {
20259            None
20260        }
20261    }
20262
20263    // Returns true if the editor handled a go-to-line request
20264    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20265        maybe!({
20266            let breakpoint_store = self.breakpoint_store.as_ref()?;
20267
20268            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20269            else {
20270                self.clear_row_highlights::<ActiveDebugLine>();
20271                return None;
20272            };
20273
20274            let position = active_stack_frame.position;
20275            let buffer_id = position.buffer_id?;
20276            let snapshot = self
20277                .project
20278                .as_ref()?
20279                .read(cx)
20280                .buffer_for_id(buffer_id, cx)?
20281                .read(cx)
20282                .snapshot();
20283
20284            let mut handled = false;
20285            for (id, ExcerptRange { context, .. }) in
20286                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20287            {
20288                if context.start.cmp(&position, &snapshot).is_ge()
20289                    || context.end.cmp(&position, &snapshot).is_lt()
20290                {
20291                    continue;
20292                }
20293                let snapshot = self.buffer.read(cx).snapshot(cx);
20294                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20295
20296                handled = true;
20297                self.clear_row_highlights::<ActiveDebugLine>();
20298
20299                self.go_to_line::<ActiveDebugLine>(
20300                    multibuffer_anchor,
20301                    Some(cx.theme().colors().editor_debugger_active_line_background),
20302                    window,
20303                    cx,
20304                );
20305
20306                cx.notify();
20307            }
20308
20309            handled.then_some(())
20310        })
20311        .is_some()
20312    }
20313
20314    pub fn copy_file_name_without_extension(
20315        &mut self,
20316        _: &CopyFileNameWithoutExtension,
20317        _: &mut Window,
20318        cx: &mut Context<Self>,
20319    ) {
20320        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20321            let file = buffer.read(cx).file()?;
20322            file.path().file_stem()
20323        }) {
20324            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20325        }
20326    }
20327
20328    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20329        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20330            let file = buffer.read(cx).file()?;
20331            Some(file.file_name(cx))
20332        }) {
20333            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20334        }
20335    }
20336
20337    pub fn toggle_git_blame(
20338        &mut self,
20339        _: &::git::Blame,
20340        window: &mut Window,
20341        cx: &mut Context<Self>,
20342    ) {
20343        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20344
20345        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20346            self.start_git_blame(true, window, cx);
20347        }
20348
20349        cx.notify();
20350    }
20351
20352    pub fn toggle_git_blame_inline(
20353        &mut self,
20354        _: &ToggleGitBlameInline,
20355        window: &mut Window,
20356        cx: &mut Context<Self>,
20357    ) {
20358        self.toggle_git_blame_inline_internal(true, window, cx);
20359        cx.notify();
20360    }
20361
20362    pub fn open_git_blame_commit(
20363        &mut self,
20364        _: &OpenGitBlameCommit,
20365        window: &mut Window,
20366        cx: &mut Context<Self>,
20367    ) {
20368        self.open_git_blame_commit_internal(window, cx);
20369    }
20370
20371    fn open_git_blame_commit_internal(
20372        &mut self,
20373        window: &mut Window,
20374        cx: &mut Context<Self>,
20375    ) -> Option<()> {
20376        let blame = self.blame.as_ref()?;
20377        let snapshot = self.snapshot(window, cx);
20378        let cursor = self
20379            .selections
20380            .newest::<Point>(&snapshot.display_snapshot)
20381            .head();
20382        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20383        let (_, blame_entry) = blame
20384            .update(cx, |blame, cx| {
20385                blame
20386                    .blame_for_rows(
20387                        &[RowInfo {
20388                            buffer_id: Some(buffer.remote_id()),
20389                            buffer_row: Some(point.row),
20390                            ..Default::default()
20391                        }],
20392                        cx,
20393                    )
20394                    .next()
20395            })
20396            .flatten()?;
20397        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20398        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20399        let workspace = self.workspace()?.downgrade();
20400        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20401        None
20402    }
20403
20404    pub fn git_blame_inline_enabled(&self) -> bool {
20405        self.git_blame_inline_enabled
20406    }
20407
20408    pub fn toggle_selection_menu(
20409        &mut self,
20410        _: &ToggleSelectionMenu,
20411        _: &mut Window,
20412        cx: &mut Context<Self>,
20413    ) {
20414        self.show_selection_menu = self
20415            .show_selection_menu
20416            .map(|show_selections_menu| !show_selections_menu)
20417            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20418
20419        cx.notify();
20420    }
20421
20422    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20423        self.show_selection_menu
20424            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20425    }
20426
20427    fn start_git_blame(
20428        &mut self,
20429        user_triggered: bool,
20430        window: &mut Window,
20431        cx: &mut Context<Self>,
20432    ) {
20433        if let Some(project) = self.project() {
20434            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20435                && buffer.read(cx).file().is_none()
20436            {
20437                return;
20438            }
20439
20440            let focused = self.focus_handle(cx).contains_focused(window, cx);
20441
20442            let project = project.clone();
20443            let blame = cx
20444                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20445            self.blame_subscription =
20446                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20447            self.blame = Some(blame);
20448        }
20449    }
20450
20451    fn toggle_git_blame_inline_internal(
20452        &mut self,
20453        user_triggered: bool,
20454        window: &mut Window,
20455        cx: &mut Context<Self>,
20456    ) {
20457        if self.git_blame_inline_enabled {
20458            self.git_blame_inline_enabled = false;
20459            self.show_git_blame_inline = false;
20460            self.show_git_blame_inline_delay_task.take();
20461        } else {
20462            self.git_blame_inline_enabled = true;
20463            self.start_git_blame_inline(user_triggered, window, cx);
20464        }
20465
20466        cx.notify();
20467    }
20468
20469    fn start_git_blame_inline(
20470        &mut self,
20471        user_triggered: bool,
20472        window: &mut Window,
20473        cx: &mut Context<Self>,
20474    ) {
20475        self.start_git_blame(user_triggered, window, cx);
20476
20477        if ProjectSettings::get_global(cx)
20478            .git
20479            .inline_blame_delay()
20480            .is_some()
20481        {
20482            self.start_inline_blame_timer(window, cx);
20483        } else {
20484            self.show_git_blame_inline = true
20485        }
20486    }
20487
20488    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20489        self.blame.as_ref()
20490    }
20491
20492    pub fn show_git_blame_gutter(&self) -> bool {
20493        self.show_git_blame_gutter
20494    }
20495
20496    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20497        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20498    }
20499
20500    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20501        self.show_git_blame_inline
20502            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20503            && !self.newest_selection_head_on_empty_line(cx)
20504            && self.has_blame_entries(cx)
20505    }
20506
20507    fn has_blame_entries(&self, cx: &App) -> bool {
20508        self.blame()
20509            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20510    }
20511
20512    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20513        let cursor_anchor = self.selections.newest_anchor().head();
20514
20515        let snapshot = self.buffer.read(cx).snapshot(cx);
20516        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20517
20518        snapshot.line_len(buffer_row) == 0
20519    }
20520
20521    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20522        let buffer_and_selection = maybe!({
20523            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20524            let selection_range = selection.range();
20525
20526            let multi_buffer = self.buffer().read(cx);
20527            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20528            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20529
20530            let (buffer, range, _) = if selection.reversed {
20531                buffer_ranges.first()
20532            } else {
20533                buffer_ranges.last()
20534            }?;
20535
20536            let selection = text::ToPoint::to_point(&range.start, buffer).row
20537                ..text::ToPoint::to_point(&range.end, buffer).row;
20538            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20539        });
20540
20541        let Some((buffer, selection)) = buffer_and_selection else {
20542            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20543        };
20544
20545        let Some(project) = self.project() else {
20546            return Task::ready(Err(anyhow!("editor does not have project")));
20547        };
20548
20549        project.update(cx, |project, cx| {
20550            project.get_permalink_to_line(&buffer, selection, cx)
20551        })
20552    }
20553
20554    pub fn copy_permalink_to_line(
20555        &mut self,
20556        _: &CopyPermalinkToLine,
20557        window: &mut Window,
20558        cx: &mut Context<Self>,
20559    ) {
20560        let permalink_task = self.get_permalink_to_line(cx);
20561        let workspace = self.workspace();
20562
20563        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20564            Ok(permalink) => {
20565                cx.update(|_, cx| {
20566                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20567                })
20568                .ok();
20569            }
20570            Err(err) => {
20571                let message = format!("Failed to copy permalink: {err}");
20572
20573                anyhow::Result::<()>::Err(err).log_err();
20574
20575                if let Some(workspace) = workspace {
20576                    workspace
20577                        .update_in(cx, |workspace, _, cx| {
20578                            struct CopyPermalinkToLine;
20579
20580                            workspace.show_toast(
20581                                Toast::new(
20582                                    NotificationId::unique::<CopyPermalinkToLine>(),
20583                                    message,
20584                                ),
20585                                cx,
20586                            )
20587                        })
20588                        .ok();
20589                }
20590            }
20591        })
20592        .detach();
20593    }
20594
20595    pub fn copy_file_location(
20596        &mut self,
20597        _: &CopyFileLocation,
20598        _: &mut Window,
20599        cx: &mut Context<Self>,
20600    ) {
20601        let selection = self
20602            .selections
20603            .newest::<Point>(&self.display_snapshot(cx))
20604            .start
20605            .row
20606            + 1;
20607        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20608            let project = self.project()?.read(cx);
20609            let file = buffer.read(cx).file()?;
20610            let path = file.path().display(project.path_style(cx));
20611
20612            Some(format!("{path}:{selection}"))
20613        }) {
20614            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
20615        }
20616    }
20617
20618    pub fn open_permalink_to_line(
20619        &mut self,
20620        _: &OpenPermalinkToLine,
20621        window: &mut Window,
20622        cx: &mut Context<Self>,
20623    ) {
20624        let permalink_task = self.get_permalink_to_line(cx);
20625        let workspace = self.workspace();
20626
20627        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20628            Ok(permalink) => {
20629                cx.update(|_, cx| {
20630                    cx.open_url(permalink.as_ref());
20631                })
20632                .ok();
20633            }
20634            Err(err) => {
20635                let message = format!("Failed to open permalink: {err}");
20636
20637                anyhow::Result::<()>::Err(err).log_err();
20638
20639                if let Some(workspace) = workspace {
20640                    workspace
20641                        .update(cx, |workspace, cx| {
20642                            struct OpenPermalinkToLine;
20643
20644                            workspace.show_toast(
20645                                Toast::new(
20646                                    NotificationId::unique::<OpenPermalinkToLine>(),
20647                                    message,
20648                                ),
20649                                cx,
20650                            )
20651                        })
20652                        .ok();
20653                }
20654            }
20655        })
20656        .detach();
20657    }
20658
20659    pub fn insert_uuid_v4(
20660        &mut self,
20661        _: &InsertUuidV4,
20662        window: &mut Window,
20663        cx: &mut Context<Self>,
20664    ) {
20665        self.insert_uuid(UuidVersion::V4, window, cx);
20666    }
20667
20668    pub fn insert_uuid_v7(
20669        &mut self,
20670        _: &InsertUuidV7,
20671        window: &mut Window,
20672        cx: &mut Context<Self>,
20673    ) {
20674        self.insert_uuid(UuidVersion::V7, window, cx);
20675    }
20676
20677    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20678        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20679        self.transact(window, cx, |this, window, cx| {
20680            let edits = this
20681                .selections
20682                .all::<Point>(&this.display_snapshot(cx))
20683                .into_iter()
20684                .map(|selection| {
20685                    let uuid = match version {
20686                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20687                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20688                    };
20689
20690                    (selection.range(), uuid.to_string())
20691                });
20692            this.edit(edits, cx);
20693            this.refresh_edit_prediction(true, false, window, cx);
20694        });
20695    }
20696
20697    pub fn open_selections_in_multibuffer(
20698        &mut self,
20699        _: &OpenSelectionsInMultibuffer,
20700        window: &mut Window,
20701        cx: &mut Context<Self>,
20702    ) {
20703        let multibuffer = self.buffer.read(cx);
20704
20705        let Some(buffer) = multibuffer.as_singleton() else {
20706            return;
20707        };
20708
20709        let Some(workspace) = self.workspace() else {
20710            return;
20711        };
20712
20713        let title = multibuffer.title(cx).to_string();
20714
20715        let locations = self
20716            .selections
20717            .all_anchors(&self.display_snapshot(cx))
20718            .iter()
20719            .map(|selection| {
20720                (
20721                    buffer.clone(),
20722                    (selection.start.text_anchor..selection.end.text_anchor)
20723                        .to_point(buffer.read(cx)),
20724                )
20725            })
20726            .into_group_map();
20727
20728        cx.spawn_in(window, async move |_, cx| {
20729            workspace.update_in(cx, |workspace, window, cx| {
20730                Self::open_locations_in_multibuffer(
20731                    workspace,
20732                    locations,
20733                    format!("Selections for '{title}'"),
20734                    false,
20735                    MultibufferSelectionMode::All,
20736                    window,
20737                    cx,
20738                );
20739            })
20740        })
20741        .detach();
20742    }
20743
20744    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20745    /// last highlight added will be used.
20746    ///
20747    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20748    pub fn highlight_rows<T: 'static>(
20749        &mut self,
20750        range: Range<Anchor>,
20751        color: Hsla,
20752        options: RowHighlightOptions,
20753        cx: &mut Context<Self>,
20754    ) {
20755        let snapshot = self.buffer().read(cx).snapshot(cx);
20756        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20757        let ix = row_highlights.binary_search_by(|highlight| {
20758            Ordering::Equal
20759                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20760                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20761        });
20762
20763        if let Err(mut ix) = ix {
20764            let index = post_inc(&mut self.highlight_order);
20765
20766            // If this range intersects with the preceding highlight, then merge it with
20767            // the preceding highlight. Otherwise insert a new highlight.
20768            let mut merged = false;
20769            if ix > 0 {
20770                let prev_highlight = &mut row_highlights[ix - 1];
20771                if prev_highlight
20772                    .range
20773                    .end
20774                    .cmp(&range.start, &snapshot)
20775                    .is_ge()
20776                {
20777                    ix -= 1;
20778                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20779                        prev_highlight.range.end = range.end;
20780                    }
20781                    merged = true;
20782                    prev_highlight.index = index;
20783                    prev_highlight.color = color;
20784                    prev_highlight.options = options;
20785                }
20786            }
20787
20788            if !merged {
20789                row_highlights.insert(
20790                    ix,
20791                    RowHighlight {
20792                        range,
20793                        index,
20794                        color,
20795                        options,
20796                        type_id: TypeId::of::<T>(),
20797                    },
20798                );
20799            }
20800
20801            // If any of the following highlights intersect with this one, merge them.
20802            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20803                let highlight = &row_highlights[ix];
20804                if next_highlight
20805                    .range
20806                    .start
20807                    .cmp(&highlight.range.end, &snapshot)
20808                    .is_le()
20809                {
20810                    if next_highlight
20811                        .range
20812                        .end
20813                        .cmp(&highlight.range.end, &snapshot)
20814                        .is_gt()
20815                    {
20816                        row_highlights[ix].range.end = next_highlight.range.end;
20817                    }
20818                    row_highlights.remove(ix + 1);
20819                } else {
20820                    break;
20821                }
20822            }
20823        }
20824    }
20825
20826    /// Remove any highlighted row ranges of the given type that intersect the
20827    /// given ranges.
20828    pub fn remove_highlighted_rows<T: 'static>(
20829        &mut self,
20830        ranges_to_remove: Vec<Range<Anchor>>,
20831        cx: &mut Context<Self>,
20832    ) {
20833        let snapshot = self.buffer().read(cx).snapshot(cx);
20834        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20835        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20836        row_highlights.retain(|highlight| {
20837            while let Some(range_to_remove) = ranges_to_remove.peek() {
20838                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20839                    Ordering::Less | Ordering::Equal => {
20840                        ranges_to_remove.next();
20841                    }
20842                    Ordering::Greater => {
20843                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20844                            Ordering::Less | Ordering::Equal => {
20845                                return false;
20846                            }
20847                            Ordering::Greater => break,
20848                        }
20849                    }
20850                }
20851            }
20852
20853            true
20854        })
20855    }
20856
20857    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20858    pub fn clear_row_highlights<T: 'static>(&mut self) {
20859        self.highlighted_rows.remove(&TypeId::of::<T>());
20860    }
20861
20862    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20863    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20864        self.highlighted_rows
20865            .get(&TypeId::of::<T>())
20866            .map_or(&[] as &[_], |vec| vec.as_slice())
20867            .iter()
20868            .map(|highlight| (highlight.range.clone(), highlight.color))
20869    }
20870
20871    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20872    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20873    /// Allows to ignore certain kinds of highlights.
20874    pub fn highlighted_display_rows(
20875        &self,
20876        window: &mut Window,
20877        cx: &mut App,
20878    ) -> BTreeMap<DisplayRow, LineHighlight> {
20879        let snapshot = self.snapshot(window, cx);
20880        let mut used_highlight_orders = HashMap::default();
20881        self.highlighted_rows
20882            .iter()
20883            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20884            .fold(
20885                BTreeMap::<DisplayRow, LineHighlight>::new(),
20886                |mut unique_rows, highlight| {
20887                    let start = highlight.range.start.to_display_point(&snapshot);
20888                    let end = highlight.range.end.to_display_point(&snapshot);
20889                    let start_row = start.row().0;
20890                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
20891                    {
20892                        end.row().0.saturating_sub(1)
20893                    } else {
20894                        end.row().0
20895                    };
20896                    for row in start_row..=end_row {
20897                        let used_index =
20898                            used_highlight_orders.entry(row).or_insert(highlight.index);
20899                        if highlight.index >= *used_index {
20900                            *used_index = highlight.index;
20901                            unique_rows.insert(
20902                                DisplayRow(row),
20903                                LineHighlight {
20904                                    include_gutter: highlight.options.include_gutter,
20905                                    border: None,
20906                                    background: highlight.color.into(),
20907                                    type_id: Some(highlight.type_id),
20908                                },
20909                            );
20910                        }
20911                    }
20912                    unique_rows
20913                },
20914            )
20915    }
20916
20917    pub fn highlighted_display_row_for_autoscroll(
20918        &self,
20919        snapshot: &DisplaySnapshot,
20920    ) -> Option<DisplayRow> {
20921        self.highlighted_rows
20922            .values()
20923            .flat_map(|highlighted_rows| highlighted_rows.iter())
20924            .filter_map(|highlight| {
20925                if highlight.options.autoscroll {
20926                    Some(highlight.range.start.to_display_point(snapshot).row())
20927                } else {
20928                    None
20929                }
20930            })
20931            .min()
20932    }
20933
20934    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20935        self.highlight_background::<SearchWithinRange>(
20936            ranges,
20937            |colors| colors.colors().editor_document_highlight_read_background,
20938            cx,
20939        )
20940    }
20941
20942    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20943        self.breadcrumb_header = Some(new_header);
20944    }
20945
20946    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20947        self.clear_background_highlights::<SearchWithinRange>(cx);
20948    }
20949
20950    pub fn highlight_background<T: 'static>(
20951        &mut self,
20952        ranges: &[Range<Anchor>],
20953        color_fetcher: fn(&Theme) -> Hsla,
20954        cx: &mut Context<Self>,
20955    ) {
20956        self.background_highlights.insert(
20957            HighlightKey::Type(TypeId::of::<T>()),
20958            (color_fetcher, Arc::from(ranges)),
20959        );
20960        self.scrollbar_marker_state.dirty = true;
20961        cx.notify();
20962    }
20963
20964    pub fn highlight_background_key<T: 'static>(
20965        &mut self,
20966        key: usize,
20967        ranges: &[Range<Anchor>],
20968        color_fetcher: fn(&Theme) -> Hsla,
20969        cx: &mut Context<Self>,
20970    ) {
20971        self.background_highlights.insert(
20972            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20973            (color_fetcher, Arc::from(ranges)),
20974        );
20975        self.scrollbar_marker_state.dirty = true;
20976        cx.notify();
20977    }
20978
20979    pub fn clear_background_highlights<T: 'static>(
20980        &mut self,
20981        cx: &mut Context<Self>,
20982    ) -> Option<BackgroundHighlight> {
20983        let text_highlights = self
20984            .background_highlights
20985            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20986        if !text_highlights.1.is_empty() {
20987            self.scrollbar_marker_state.dirty = true;
20988            cx.notify();
20989        }
20990        Some(text_highlights)
20991    }
20992
20993    pub fn highlight_gutter<T: 'static>(
20994        &mut self,
20995        ranges: impl Into<Vec<Range<Anchor>>>,
20996        color_fetcher: fn(&App) -> Hsla,
20997        cx: &mut Context<Self>,
20998    ) {
20999        self.gutter_highlights
21000            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21001        cx.notify();
21002    }
21003
21004    pub fn clear_gutter_highlights<T: 'static>(
21005        &mut self,
21006        cx: &mut Context<Self>,
21007    ) -> Option<GutterHighlight> {
21008        cx.notify();
21009        self.gutter_highlights.remove(&TypeId::of::<T>())
21010    }
21011
21012    pub fn insert_gutter_highlight<T: 'static>(
21013        &mut self,
21014        range: Range<Anchor>,
21015        color_fetcher: fn(&App) -> Hsla,
21016        cx: &mut Context<Self>,
21017    ) {
21018        let snapshot = self.buffer().read(cx).snapshot(cx);
21019        let mut highlights = self
21020            .gutter_highlights
21021            .remove(&TypeId::of::<T>())
21022            .map(|(_, highlights)| highlights)
21023            .unwrap_or_default();
21024        let ix = highlights.binary_search_by(|highlight| {
21025            Ordering::Equal
21026                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21027                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21028        });
21029        if let Err(ix) = ix {
21030            highlights.insert(ix, range);
21031        }
21032        self.gutter_highlights
21033            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21034    }
21035
21036    pub fn remove_gutter_highlights<T: 'static>(
21037        &mut self,
21038        ranges_to_remove: Vec<Range<Anchor>>,
21039        cx: &mut Context<Self>,
21040    ) {
21041        let snapshot = self.buffer().read(cx).snapshot(cx);
21042        let Some((color_fetcher, mut gutter_highlights)) =
21043            self.gutter_highlights.remove(&TypeId::of::<T>())
21044        else {
21045            return;
21046        };
21047        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21048        gutter_highlights.retain(|highlight| {
21049            while let Some(range_to_remove) = ranges_to_remove.peek() {
21050                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21051                    Ordering::Less | Ordering::Equal => {
21052                        ranges_to_remove.next();
21053                    }
21054                    Ordering::Greater => {
21055                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21056                            Ordering::Less | Ordering::Equal => {
21057                                return false;
21058                            }
21059                            Ordering::Greater => break,
21060                        }
21061                    }
21062                }
21063            }
21064
21065            true
21066        });
21067        self.gutter_highlights
21068            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21069    }
21070
21071    #[cfg(feature = "test-support")]
21072    pub fn all_text_highlights(
21073        &self,
21074        window: &mut Window,
21075        cx: &mut Context<Self>,
21076    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21077        let snapshot = self.snapshot(window, cx);
21078        self.display_map.update(cx, |display_map, _| {
21079            display_map
21080                .all_text_highlights()
21081                .map(|highlight| {
21082                    let (style, ranges) = highlight.as_ref();
21083                    (
21084                        *style,
21085                        ranges
21086                            .iter()
21087                            .map(|range| range.clone().to_display_points(&snapshot))
21088                            .collect(),
21089                    )
21090                })
21091                .collect()
21092        })
21093    }
21094
21095    #[cfg(feature = "test-support")]
21096    pub fn all_text_background_highlights(
21097        &self,
21098        window: &mut Window,
21099        cx: &mut Context<Self>,
21100    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21101        let snapshot = self.snapshot(window, cx);
21102        let buffer = &snapshot.buffer_snapshot();
21103        let start = buffer.anchor_before(MultiBufferOffset(0));
21104        let end = buffer.anchor_after(buffer.len());
21105        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21106    }
21107
21108    #[cfg(any(test, feature = "test-support"))]
21109    pub fn sorted_background_highlights_in_range(
21110        &self,
21111        search_range: Range<Anchor>,
21112        display_snapshot: &DisplaySnapshot,
21113        theme: &Theme,
21114    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21115        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21116        res.sort_by(|a, b| {
21117            a.0.start
21118                .cmp(&b.0.start)
21119                .then_with(|| a.0.end.cmp(&b.0.end))
21120                .then_with(|| a.1.cmp(&b.1))
21121        });
21122        res
21123    }
21124
21125    #[cfg(feature = "test-support")]
21126    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21127        let snapshot = self.buffer().read(cx).snapshot(cx);
21128
21129        let highlights = self
21130            .background_highlights
21131            .get(&HighlightKey::Type(TypeId::of::<
21132                items::BufferSearchHighlights,
21133            >()));
21134
21135        if let Some((_color, ranges)) = highlights {
21136            ranges
21137                .iter()
21138                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21139                .collect_vec()
21140        } else {
21141            vec![]
21142        }
21143    }
21144
21145    fn document_highlights_for_position<'a>(
21146        &'a self,
21147        position: Anchor,
21148        buffer: &'a MultiBufferSnapshot,
21149    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21150        let read_highlights = self
21151            .background_highlights
21152            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21153            .map(|h| &h.1);
21154        let write_highlights = self
21155            .background_highlights
21156            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21157            .map(|h| &h.1);
21158        let left_position = position.bias_left(buffer);
21159        let right_position = position.bias_right(buffer);
21160        read_highlights
21161            .into_iter()
21162            .chain(write_highlights)
21163            .flat_map(move |ranges| {
21164                let start_ix = match ranges.binary_search_by(|probe| {
21165                    let cmp = probe.end.cmp(&left_position, buffer);
21166                    if cmp.is_ge() {
21167                        Ordering::Greater
21168                    } else {
21169                        Ordering::Less
21170                    }
21171                }) {
21172                    Ok(i) | Err(i) => i,
21173                };
21174
21175                ranges[start_ix..]
21176                    .iter()
21177                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21178            })
21179    }
21180
21181    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21182        self.background_highlights
21183            .get(&HighlightKey::Type(TypeId::of::<T>()))
21184            .is_some_and(|(_, highlights)| !highlights.is_empty())
21185    }
21186
21187    /// Returns all background highlights for a given range.
21188    ///
21189    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21190    pub fn background_highlights_in_range(
21191        &self,
21192        search_range: Range<Anchor>,
21193        display_snapshot: &DisplaySnapshot,
21194        theme: &Theme,
21195    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21196        let mut results = Vec::new();
21197        for (color_fetcher, ranges) in self.background_highlights.values() {
21198            let color = color_fetcher(theme);
21199            let start_ix = match ranges.binary_search_by(|probe| {
21200                let cmp = probe
21201                    .end
21202                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21203                if cmp.is_gt() {
21204                    Ordering::Greater
21205                } else {
21206                    Ordering::Less
21207                }
21208            }) {
21209                Ok(i) | Err(i) => i,
21210            };
21211            for range in &ranges[start_ix..] {
21212                if range
21213                    .start
21214                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21215                    .is_ge()
21216                {
21217                    break;
21218                }
21219
21220                let start = range.start.to_display_point(display_snapshot);
21221                let end = range.end.to_display_point(display_snapshot);
21222                results.push((start..end, color))
21223            }
21224        }
21225        results
21226    }
21227
21228    pub fn gutter_highlights_in_range(
21229        &self,
21230        search_range: Range<Anchor>,
21231        display_snapshot: &DisplaySnapshot,
21232        cx: &App,
21233    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21234        let mut results = Vec::new();
21235        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21236            let color = color_fetcher(cx);
21237            let start_ix = match ranges.binary_search_by(|probe| {
21238                let cmp = probe
21239                    .end
21240                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21241                if cmp.is_gt() {
21242                    Ordering::Greater
21243                } else {
21244                    Ordering::Less
21245                }
21246            }) {
21247                Ok(i) | Err(i) => i,
21248            };
21249            for range in &ranges[start_ix..] {
21250                if range
21251                    .start
21252                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21253                    .is_ge()
21254                {
21255                    break;
21256                }
21257
21258                let start = range.start.to_display_point(display_snapshot);
21259                let end = range.end.to_display_point(display_snapshot);
21260                results.push((start..end, color))
21261            }
21262        }
21263        results
21264    }
21265
21266    /// Get the text ranges corresponding to the redaction query
21267    pub fn redacted_ranges(
21268        &self,
21269        search_range: Range<Anchor>,
21270        display_snapshot: &DisplaySnapshot,
21271        cx: &App,
21272    ) -> Vec<Range<DisplayPoint>> {
21273        display_snapshot
21274            .buffer_snapshot()
21275            .redacted_ranges(search_range, |file| {
21276                if let Some(file) = file {
21277                    file.is_private()
21278                        && EditorSettings::get(
21279                            Some(SettingsLocation {
21280                                worktree_id: file.worktree_id(cx),
21281                                path: file.path().as_ref(),
21282                            }),
21283                            cx,
21284                        )
21285                        .redact_private_values
21286                } else {
21287                    false
21288                }
21289            })
21290            .map(|range| {
21291                range.start.to_display_point(display_snapshot)
21292                    ..range.end.to_display_point(display_snapshot)
21293            })
21294            .collect()
21295    }
21296
21297    pub fn highlight_text_key<T: 'static>(
21298        &mut self,
21299        key: usize,
21300        ranges: Vec<Range<Anchor>>,
21301        style: HighlightStyle,
21302        merge: bool,
21303        cx: &mut Context<Self>,
21304    ) {
21305        self.display_map.update(cx, |map, cx| {
21306            map.highlight_text(
21307                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21308                ranges,
21309                style,
21310                merge,
21311                cx,
21312            );
21313        });
21314        cx.notify();
21315    }
21316
21317    pub fn highlight_text<T: 'static>(
21318        &mut self,
21319        ranges: Vec<Range<Anchor>>,
21320        style: HighlightStyle,
21321        cx: &mut Context<Self>,
21322    ) {
21323        self.display_map.update(cx, |map, cx| {
21324            map.highlight_text(
21325                HighlightKey::Type(TypeId::of::<T>()),
21326                ranges,
21327                style,
21328                false,
21329                cx,
21330            )
21331        });
21332        cx.notify();
21333    }
21334
21335    pub fn text_highlights<'a, T: 'static>(
21336        &'a self,
21337        cx: &'a App,
21338    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21339        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21340    }
21341
21342    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21343        let cleared = self
21344            .display_map
21345            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21346        if cleared {
21347            cx.notify();
21348        }
21349    }
21350
21351    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21352        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21353            && self.focus_handle.is_focused(window)
21354    }
21355
21356    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21357        self.show_cursor_when_unfocused = is_enabled;
21358        cx.notify();
21359    }
21360
21361    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21362        cx.notify();
21363    }
21364
21365    fn on_debug_session_event(
21366        &mut self,
21367        _session: Entity<Session>,
21368        event: &SessionEvent,
21369        cx: &mut Context<Self>,
21370    ) {
21371        if let SessionEvent::InvalidateInlineValue = event {
21372            self.refresh_inline_values(cx);
21373        }
21374    }
21375
21376    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21377        let Some(project) = self.project.clone() else {
21378            return;
21379        };
21380
21381        if !self.inline_value_cache.enabled {
21382            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21383            self.splice_inlays(&inlays, Vec::new(), cx);
21384            return;
21385        }
21386
21387        let current_execution_position = self
21388            .highlighted_rows
21389            .get(&TypeId::of::<ActiveDebugLine>())
21390            .and_then(|lines| lines.last().map(|line| line.range.end));
21391
21392        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21393            let inline_values = editor
21394                .update(cx, |editor, cx| {
21395                    let Some(current_execution_position) = current_execution_position else {
21396                        return Some(Task::ready(Ok(Vec::new())));
21397                    };
21398
21399                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21400                        let snapshot = buffer.snapshot(cx);
21401
21402                        let excerpt = snapshot.excerpt_containing(
21403                            current_execution_position..current_execution_position,
21404                        )?;
21405
21406                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21407                    })?;
21408
21409                    let range =
21410                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21411
21412                    project.inline_values(buffer, range, cx)
21413                })
21414                .ok()
21415                .flatten()?
21416                .await
21417                .context("refreshing debugger inlays")
21418                .log_err()?;
21419
21420            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21421
21422            for (buffer_id, inline_value) in inline_values
21423                .into_iter()
21424                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21425            {
21426                buffer_inline_values
21427                    .entry(buffer_id)
21428                    .or_default()
21429                    .push(inline_value);
21430            }
21431
21432            editor
21433                .update(cx, |editor, cx| {
21434                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21435                    let mut new_inlays = Vec::default();
21436
21437                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21438                        let buffer_id = buffer_snapshot.remote_id();
21439                        buffer_inline_values
21440                            .get(&buffer_id)
21441                            .into_iter()
21442                            .flatten()
21443                            .for_each(|hint| {
21444                                let inlay = Inlay::debugger(
21445                                    post_inc(&mut editor.next_inlay_id),
21446                                    Anchor::in_buffer(excerpt_id, hint.position),
21447                                    hint.text(),
21448                                );
21449                                if !inlay.text().chars().contains(&'\n') {
21450                                    new_inlays.push(inlay);
21451                                }
21452                            });
21453                    }
21454
21455                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21456                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21457
21458                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21459                })
21460                .ok()?;
21461            Some(())
21462        });
21463    }
21464
21465    fn on_buffer_event(
21466        &mut self,
21467        multibuffer: &Entity<MultiBuffer>,
21468        event: &multi_buffer::Event,
21469        window: &mut Window,
21470        cx: &mut Context<Self>,
21471    ) {
21472        match event {
21473            multi_buffer::Event::Edited { edited_buffer } => {
21474                self.scrollbar_marker_state.dirty = true;
21475                self.active_indent_guides_state.dirty = true;
21476                self.refresh_active_diagnostics(cx);
21477                self.refresh_code_actions(window, cx);
21478                self.refresh_single_line_folds(window, cx);
21479                self.refresh_matching_bracket_highlights(window, cx);
21480                if self.has_active_edit_prediction() {
21481                    self.update_visible_edit_prediction(window, cx);
21482                }
21483
21484                if let Some(buffer) = edited_buffer {
21485                    if buffer.read(cx).file().is_none() {
21486                        cx.emit(EditorEvent::TitleChanged);
21487                    }
21488
21489                    if self.project.is_some() {
21490                        let buffer_id = buffer.read(cx).remote_id();
21491                        self.register_buffer(buffer_id, cx);
21492                        self.update_lsp_data(Some(buffer_id), window, cx);
21493                        self.refresh_inlay_hints(
21494                            InlayHintRefreshReason::BufferEdited(buffer_id),
21495                            cx,
21496                        );
21497                    }
21498                }
21499
21500                cx.emit(EditorEvent::BufferEdited);
21501                cx.emit(SearchEvent::MatchesInvalidated);
21502
21503                let Some(project) = &self.project else { return };
21504                let (telemetry, is_via_ssh) = {
21505                    let project = project.read(cx);
21506                    let telemetry = project.client().telemetry().clone();
21507                    let is_via_ssh = project.is_via_remote_server();
21508                    (telemetry, is_via_ssh)
21509                };
21510                telemetry.log_edit_event("editor", is_via_ssh);
21511            }
21512            multi_buffer::Event::ExcerptsAdded {
21513                buffer,
21514                predecessor,
21515                excerpts,
21516            } => {
21517                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21518                let buffer_id = buffer.read(cx).remote_id();
21519                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21520                    && let Some(project) = &self.project
21521                {
21522                    update_uncommitted_diff_for_buffer(
21523                        cx.entity(),
21524                        project,
21525                        [buffer.clone()],
21526                        self.buffer.clone(),
21527                        cx,
21528                    )
21529                    .detach();
21530                }
21531                self.update_lsp_data(Some(buffer_id), window, cx);
21532                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21533                self.colorize_brackets(false, cx);
21534                cx.emit(EditorEvent::ExcerptsAdded {
21535                    buffer: buffer.clone(),
21536                    predecessor: *predecessor,
21537                    excerpts: excerpts.clone(),
21538                });
21539            }
21540            multi_buffer::Event::ExcerptsRemoved {
21541                ids,
21542                removed_buffer_ids,
21543            } => {
21544                if let Some(inlay_hints) = &mut self.inlay_hints {
21545                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21546                }
21547                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21548                for buffer_id in removed_buffer_ids {
21549                    self.registered_buffers.remove(buffer_id);
21550                }
21551                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21552                cx.emit(EditorEvent::ExcerptsRemoved {
21553                    ids: ids.clone(),
21554                    removed_buffer_ids: removed_buffer_ids.clone(),
21555                });
21556            }
21557            multi_buffer::Event::ExcerptsEdited {
21558                excerpt_ids,
21559                buffer_ids,
21560            } => {
21561                self.display_map.update(cx, |map, cx| {
21562                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21563                });
21564                cx.emit(EditorEvent::ExcerptsEdited {
21565                    ids: excerpt_ids.clone(),
21566                });
21567            }
21568            multi_buffer::Event::ExcerptsExpanded { ids } => {
21569                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21570                self.refresh_document_highlights(cx);
21571                for id in ids {
21572                    self.fetched_tree_sitter_chunks.remove(id);
21573                }
21574                self.colorize_brackets(false, cx);
21575                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21576            }
21577            multi_buffer::Event::Reparsed(buffer_id) => {
21578                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21579                self.refresh_selected_text_highlights(true, window, cx);
21580                self.colorize_brackets(true, cx);
21581                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21582
21583                cx.emit(EditorEvent::Reparsed(*buffer_id));
21584            }
21585            multi_buffer::Event::DiffHunksToggled => {
21586                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21587            }
21588            multi_buffer::Event::LanguageChanged(buffer_id) => {
21589                self.registered_buffers.remove(&buffer_id);
21590                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21591                cx.emit(EditorEvent::Reparsed(*buffer_id));
21592                cx.notify();
21593            }
21594            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21595            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21596            multi_buffer::Event::FileHandleChanged
21597            | multi_buffer::Event::Reloaded
21598            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21599            multi_buffer::Event::DiagnosticsUpdated => {
21600                self.update_diagnostics_state(window, cx);
21601            }
21602            _ => {}
21603        };
21604    }
21605
21606    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21607        if !self.diagnostics_enabled() {
21608            return;
21609        }
21610        self.refresh_active_diagnostics(cx);
21611        self.refresh_inline_diagnostics(true, window, cx);
21612        self.scrollbar_marker_state.dirty = true;
21613        cx.notify();
21614    }
21615
21616    pub fn start_temporary_diff_override(&mut self) {
21617        self.load_diff_task.take();
21618        self.temporary_diff_override = true;
21619    }
21620
21621    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21622        self.temporary_diff_override = false;
21623        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21624        self.buffer.update(cx, |buffer, cx| {
21625            buffer.set_all_diff_hunks_collapsed(cx);
21626        });
21627
21628        if let Some(project) = self.project.clone() {
21629            self.load_diff_task = Some(
21630                update_uncommitted_diff_for_buffer(
21631                    cx.entity(),
21632                    &project,
21633                    self.buffer.read(cx).all_buffers(),
21634                    self.buffer.clone(),
21635                    cx,
21636                )
21637                .shared(),
21638            );
21639        }
21640    }
21641
21642    fn on_display_map_changed(
21643        &mut self,
21644        _: Entity<DisplayMap>,
21645        _: &mut Window,
21646        cx: &mut Context<Self>,
21647    ) {
21648        cx.notify();
21649    }
21650
21651    fn fetch_accent_overrides(&self, cx: &App) -> Vec<SharedString> {
21652        if !self.mode.is_full() {
21653            return Vec::new();
21654        }
21655
21656        let theme_settings = theme::ThemeSettings::get_global(cx);
21657
21658        theme_settings
21659            .theme_overrides
21660            .get(cx.theme().name.as_ref())
21661            .map(|theme_style| &theme_style.accents)
21662            .into_iter()
21663            .flatten()
21664            .chain(
21665                theme_settings
21666                    .experimental_theme_overrides
21667                    .as_ref()
21668                    .map(|overrides| &overrides.accents)
21669                    .into_iter()
21670                    .flatten(),
21671            )
21672            .flat_map(|accent| accent.0.clone())
21673            .collect()
21674    }
21675
21676    fn fetch_applicable_language_settings(
21677        &self,
21678        cx: &App,
21679    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
21680        if !self.mode.is_full() {
21681            return HashMap::default();
21682        }
21683
21684        self.buffer().read(cx).all_buffers().into_iter().fold(
21685            HashMap::default(),
21686            |mut acc, buffer| {
21687                let buffer = buffer.read(cx);
21688                let language = buffer.language().map(|language| language.name());
21689                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
21690                    let file = buffer.file();
21691                    v.insert(language_settings(language, file, cx).into_owned());
21692                }
21693                acc
21694            },
21695        )
21696    }
21697
21698    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21699        let new_language_settings = self.fetch_applicable_language_settings(cx);
21700        let language_settings_changed = new_language_settings != self.applicable_language_settings;
21701        self.applicable_language_settings = new_language_settings;
21702
21703        let new_accent_overrides = self.fetch_accent_overrides(cx);
21704        let accent_overrides_changed = new_accent_overrides != self.accent_overrides;
21705        self.accent_overrides = new_accent_overrides;
21706
21707        if self.diagnostics_enabled() {
21708            let new_severity = EditorSettings::get_global(cx)
21709                .diagnostics_max_severity
21710                .unwrap_or(DiagnosticSeverity::Hint);
21711            self.set_max_diagnostics_severity(new_severity, cx);
21712        }
21713        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21714        self.update_edit_prediction_settings(cx);
21715        self.refresh_edit_prediction(true, false, window, cx);
21716        self.refresh_inline_values(cx);
21717        self.refresh_inlay_hints(
21718            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21719                self.selections.newest_anchor().head(),
21720                &self.buffer.read(cx).snapshot(cx),
21721                cx,
21722            )),
21723            cx,
21724        );
21725
21726        let old_cursor_shape = self.cursor_shape;
21727        let old_show_breadcrumbs = self.show_breadcrumbs;
21728
21729        {
21730            let editor_settings = EditorSettings::get_global(cx);
21731            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21732            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21733            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21734            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21735        }
21736
21737        if old_cursor_shape != self.cursor_shape {
21738            cx.emit(EditorEvent::CursorShapeChanged);
21739        }
21740
21741        if old_show_breadcrumbs != self.show_breadcrumbs {
21742            cx.emit(EditorEvent::BreadcrumbsChanged);
21743        }
21744
21745        let project_settings = ProjectSettings::get_global(cx);
21746        self.buffer_serialization = self
21747            .should_serialize_buffer()
21748            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21749
21750        if self.mode.is_full() {
21751            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21752            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21753            if self.show_inline_diagnostics != show_inline_diagnostics {
21754                self.show_inline_diagnostics = show_inline_diagnostics;
21755                self.refresh_inline_diagnostics(false, window, cx);
21756            }
21757
21758            if self.git_blame_inline_enabled != inline_blame_enabled {
21759                self.toggle_git_blame_inline_internal(false, window, cx);
21760            }
21761
21762            let minimap_settings = EditorSettings::get_global(cx).minimap;
21763            if self.minimap_visibility != MinimapVisibility::Disabled {
21764                if self.minimap_visibility.settings_visibility()
21765                    != minimap_settings.minimap_enabled()
21766                {
21767                    self.set_minimap_visibility(
21768                        MinimapVisibility::for_mode(self.mode(), cx),
21769                        window,
21770                        cx,
21771                    );
21772                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21773                    minimap_entity.update(cx, |minimap_editor, cx| {
21774                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21775                    })
21776                }
21777            }
21778
21779            if language_settings_changed || accent_overrides_changed {
21780                self.colorize_brackets(true, cx);
21781            }
21782
21783            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21784                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21785            }) {
21786                if !inlay_splice.is_empty() {
21787                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21788                }
21789                self.refresh_colors_for_visible_range(None, window, cx);
21790            }
21791        }
21792
21793        cx.notify();
21794    }
21795
21796    pub fn set_searchable(&mut self, searchable: bool) {
21797        self.searchable = searchable;
21798    }
21799
21800    pub fn searchable(&self) -> bool {
21801        self.searchable
21802    }
21803
21804    pub fn open_excerpts_in_split(
21805        &mut self,
21806        _: &OpenExcerptsSplit,
21807        window: &mut Window,
21808        cx: &mut Context<Self>,
21809    ) {
21810        self.open_excerpts_common(None, true, window, cx)
21811    }
21812
21813    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21814        self.open_excerpts_common(None, false, window, cx)
21815    }
21816
21817    fn open_excerpts_common(
21818        &mut self,
21819        jump_data: Option<JumpData>,
21820        split: bool,
21821        window: &mut Window,
21822        cx: &mut Context<Self>,
21823    ) {
21824        let Some(workspace) = self.workspace() else {
21825            cx.propagate();
21826            return;
21827        };
21828
21829        if self.buffer.read(cx).is_singleton() {
21830            cx.propagate();
21831            return;
21832        }
21833
21834        let mut new_selections_by_buffer = HashMap::default();
21835        match &jump_data {
21836            Some(JumpData::MultiBufferPoint {
21837                excerpt_id,
21838                position,
21839                anchor,
21840                line_offset_from_top,
21841            }) => {
21842                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21843                if let Some(buffer) = multi_buffer_snapshot
21844                    .buffer_id_for_excerpt(*excerpt_id)
21845                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21846                {
21847                    let buffer_snapshot = buffer.read(cx).snapshot();
21848                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21849                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21850                    } else {
21851                        buffer_snapshot.clip_point(*position, Bias::Left)
21852                    };
21853                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21854                    new_selections_by_buffer.insert(
21855                        buffer,
21856                        (
21857                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
21858                            Some(*line_offset_from_top),
21859                        ),
21860                    );
21861                }
21862            }
21863            Some(JumpData::MultiBufferRow {
21864                row,
21865                line_offset_from_top,
21866            }) => {
21867                let point = MultiBufferPoint::new(row.0, 0);
21868                if let Some((buffer, buffer_point, _)) =
21869                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21870                {
21871                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21872                    new_selections_by_buffer
21873                        .entry(buffer)
21874                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21875                        .0
21876                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
21877                }
21878            }
21879            None => {
21880                let selections = self
21881                    .selections
21882                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
21883                let multi_buffer = self.buffer.read(cx);
21884                for selection in selections {
21885                    for (snapshot, range, _, anchor) in multi_buffer
21886                        .snapshot(cx)
21887                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21888                    {
21889                        if let Some(anchor) = anchor {
21890                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21891                            else {
21892                                continue;
21893                            };
21894                            let offset = text::ToOffset::to_offset(
21895                                &anchor.text_anchor,
21896                                &buffer_handle.read(cx).snapshot(),
21897                            );
21898                            let range = BufferOffset(offset)..BufferOffset(offset);
21899                            new_selections_by_buffer
21900                                .entry(buffer_handle)
21901                                .or_insert((Vec::new(), None))
21902                                .0
21903                                .push(range)
21904                        } else {
21905                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21906                            else {
21907                                continue;
21908                            };
21909                            new_selections_by_buffer
21910                                .entry(buffer_handle)
21911                                .or_insert((Vec::new(), None))
21912                                .0
21913                                .push(range)
21914                        }
21915                    }
21916                }
21917            }
21918        }
21919
21920        new_selections_by_buffer
21921            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21922
21923        if new_selections_by_buffer.is_empty() {
21924            return;
21925        }
21926
21927        // We defer the pane interaction because we ourselves are a workspace item
21928        // and activating a new item causes the pane to call a method on us reentrantly,
21929        // which panics if we're on the stack.
21930        window.defer(cx, move |window, cx| {
21931            workspace.update(cx, |workspace, cx| {
21932                let pane = if split {
21933                    workspace.adjacent_pane(window, cx)
21934                } else {
21935                    workspace.active_pane().clone()
21936                };
21937
21938                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21939                    let editor = buffer
21940                        .read(cx)
21941                        .file()
21942                        .is_none()
21943                        .then(|| {
21944                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21945                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21946                            // Instead, we try to activate the existing editor in the pane first.
21947                            let (editor, pane_item_index) =
21948                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21949                                    let editor = item.downcast::<Editor>()?;
21950                                    let singleton_buffer =
21951                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21952                                    if singleton_buffer == buffer {
21953                                        Some((editor, i))
21954                                    } else {
21955                                        None
21956                                    }
21957                                })?;
21958                            pane.update(cx, |pane, cx| {
21959                                pane.activate_item(pane_item_index, true, true, window, cx)
21960                            });
21961                            Some(editor)
21962                        })
21963                        .flatten()
21964                        .unwrap_or_else(|| {
21965                            workspace.open_project_item::<Self>(
21966                                pane.clone(),
21967                                buffer,
21968                                true,
21969                                true,
21970                                window,
21971                                cx,
21972                            )
21973                        });
21974
21975                    editor.update(cx, |editor, cx| {
21976                        let autoscroll = match scroll_offset {
21977                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21978                            None => Autoscroll::newest(),
21979                        };
21980                        let nav_history = editor.nav_history.take();
21981                        editor.change_selections(
21982                            SelectionEffects::scroll(autoscroll),
21983                            window,
21984                            cx,
21985                            |s| {
21986                                s.select_ranges(ranges.into_iter().map(|range| {
21987                                    // we checked that the editor is a singleton editor so the offsets are valid
21988                                    MultiBufferOffset(range.start.0)..MultiBufferOffset(range.end.0)
21989                                }));
21990                            },
21991                        );
21992                        editor.nav_history = nav_history;
21993                    });
21994                }
21995            })
21996        });
21997    }
21998
21999    // For now, don't allow opening excerpts in buffers that aren't backed by
22000    // regular project files.
22001    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
22002        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
22003    }
22004
22005    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22006        let snapshot = self.buffer.read(cx).read(cx);
22007        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22008        Some(
22009            ranges
22010                .iter()
22011                .map(move |range| {
22012                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22013                })
22014                .collect(),
22015        )
22016    }
22017
22018    fn selection_replacement_ranges(
22019        &self,
22020        range: Range<MultiBufferOffsetUtf16>,
22021        cx: &mut App,
22022    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22023        let selections = self
22024            .selections
22025            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22026        let newest_selection = selections
22027            .iter()
22028            .max_by_key(|selection| selection.id)
22029            .unwrap();
22030        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22031        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22032        let snapshot = self.buffer.read(cx).read(cx);
22033        selections
22034            .into_iter()
22035            .map(|mut selection| {
22036                selection.start.0.0 =
22037                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22038                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22039                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22040                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22041            })
22042            .collect()
22043    }
22044
22045    fn report_editor_event(
22046        &self,
22047        reported_event: ReportEditorEvent,
22048        file_extension: Option<String>,
22049        cx: &App,
22050    ) {
22051        if cfg!(any(test, feature = "test-support")) {
22052            return;
22053        }
22054
22055        let Some(project) = &self.project else { return };
22056
22057        // If None, we are in a file without an extension
22058        let file = self
22059            .buffer
22060            .read(cx)
22061            .as_singleton()
22062            .and_then(|b| b.read(cx).file());
22063        let file_extension = file_extension.or(file
22064            .as_ref()
22065            .and_then(|file| Path::new(file.file_name(cx)).extension())
22066            .and_then(|e| e.to_str())
22067            .map(|a| a.to_string()));
22068
22069        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22070            .map(|vim_mode| vim_mode.0)
22071            .unwrap_or(false);
22072
22073        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22074        let copilot_enabled = edit_predictions_provider
22075            == language::language_settings::EditPredictionProvider::Copilot;
22076        let copilot_enabled_for_language = self
22077            .buffer
22078            .read(cx)
22079            .language_settings(cx)
22080            .show_edit_predictions;
22081
22082        let project = project.read(cx);
22083        let event_type = reported_event.event_type();
22084
22085        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22086            telemetry::event!(
22087                event_type,
22088                type = if auto_saved {"autosave"} else {"manual"},
22089                file_extension,
22090                vim_mode,
22091                copilot_enabled,
22092                copilot_enabled_for_language,
22093                edit_predictions_provider,
22094                is_via_ssh = project.is_via_remote_server(),
22095            );
22096        } else {
22097            telemetry::event!(
22098                event_type,
22099                file_extension,
22100                vim_mode,
22101                copilot_enabled,
22102                copilot_enabled_for_language,
22103                edit_predictions_provider,
22104                is_via_ssh = project.is_via_remote_server(),
22105            );
22106        };
22107    }
22108
22109    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22110    /// with each line being an array of {text, highlight} objects.
22111    fn copy_highlight_json(
22112        &mut self,
22113        _: &CopyHighlightJson,
22114        window: &mut Window,
22115        cx: &mut Context<Self>,
22116    ) {
22117        #[derive(Serialize)]
22118        struct Chunk<'a> {
22119            text: String,
22120            highlight: Option<&'a str>,
22121        }
22122
22123        let snapshot = self.buffer.read(cx).snapshot(cx);
22124        let range = self
22125            .selected_text_range(false, window, cx)
22126            .and_then(|selection| {
22127                if selection.range.is_empty() {
22128                    None
22129                } else {
22130                    Some(
22131                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22132                            selection.range.start,
22133                        )))
22134                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22135                                selection.range.end,
22136                            ))),
22137                    )
22138                }
22139            })
22140            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22141
22142        let chunks = snapshot.chunks(range, true);
22143        let mut lines = Vec::new();
22144        let mut line: VecDeque<Chunk> = VecDeque::new();
22145
22146        let Some(style) = self.style.as_ref() else {
22147            return;
22148        };
22149
22150        for chunk in chunks {
22151            let highlight = chunk
22152                .syntax_highlight_id
22153                .and_then(|id| id.name(&style.syntax));
22154            let mut chunk_lines = chunk.text.split('\n').peekable();
22155            while let Some(text) = chunk_lines.next() {
22156                let mut merged_with_last_token = false;
22157                if let Some(last_token) = line.back_mut()
22158                    && last_token.highlight == highlight
22159                {
22160                    last_token.text.push_str(text);
22161                    merged_with_last_token = true;
22162                }
22163
22164                if !merged_with_last_token {
22165                    line.push_back(Chunk {
22166                        text: text.into(),
22167                        highlight,
22168                    });
22169                }
22170
22171                if chunk_lines.peek().is_some() {
22172                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22173                        line.pop_front();
22174                    }
22175                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22176                        line.pop_back();
22177                    }
22178
22179                    lines.push(mem::take(&mut line));
22180                }
22181            }
22182        }
22183
22184        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22185            return;
22186        };
22187        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22188    }
22189
22190    pub fn open_context_menu(
22191        &mut self,
22192        _: &OpenContextMenu,
22193        window: &mut Window,
22194        cx: &mut Context<Self>,
22195    ) {
22196        self.request_autoscroll(Autoscroll::newest(), cx);
22197        let position = self
22198            .selections
22199            .newest_display(&self.display_snapshot(cx))
22200            .start;
22201        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22202    }
22203
22204    pub fn replay_insert_event(
22205        &mut self,
22206        text: &str,
22207        relative_utf16_range: Option<Range<isize>>,
22208        window: &mut Window,
22209        cx: &mut Context<Self>,
22210    ) {
22211        if !self.input_enabled {
22212            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22213            return;
22214        }
22215        if let Some(relative_utf16_range) = relative_utf16_range {
22216            let selections = self
22217                .selections
22218                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22219            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22220                let new_ranges = selections.into_iter().map(|range| {
22221                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22222                        range
22223                            .head()
22224                            .0
22225                            .0
22226                            .saturating_add_signed(relative_utf16_range.start),
22227                    ));
22228                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22229                        range
22230                            .head()
22231                            .0
22232                            .0
22233                            .saturating_add_signed(relative_utf16_range.end),
22234                    ));
22235                    start..end
22236                });
22237                s.select_ranges(new_ranges);
22238            });
22239        }
22240
22241        self.handle_input(text, window, cx);
22242    }
22243
22244    pub fn is_focused(&self, window: &Window) -> bool {
22245        self.focus_handle.is_focused(window)
22246    }
22247
22248    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22249        cx.emit(EditorEvent::Focused);
22250
22251        if let Some(descendant) = self
22252            .last_focused_descendant
22253            .take()
22254            .and_then(|descendant| descendant.upgrade())
22255        {
22256            window.focus(&descendant);
22257        } else {
22258            if let Some(blame) = self.blame.as_ref() {
22259                blame.update(cx, GitBlame::focus)
22260            }
22261
22262            self.blink_manager.update(cx, BlinkManager::enable);
22263            self.show_cursor_names(window, cx);
22264            self.buffer.update(cx, |buffer, cx| {
22265                buffer.finalize_last_transaction(cx);
22266                if self.leader_id.is_none() {
22267                    buffer.set_active_selections(
22268                        &self.selections.disjoint_anchors_arc(),
22269                        self.selections.line_mode(),
22270                        self.cursor_shape,
22271                        cx,
22272                    );
22273                }
22274            });
22275
22276            if let Some(position_map) = self.last_position_map.clone() {
22277                EditorElement::mouse_moved(
22278                    self,
22279                    &MouseMoveEvent {
22280                        position: window.mouse_position(),
22281                        pressed_button: None,
22282                        modifiers: window.modifiers(),
22283                    },
22284                    &position_map,
22285                    window,
22286                    cx,
22287                );
22288            }
22289        }
22290    }
22291
22292    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22293        cx.emit(EditorEvent::FocusedIn)
22294    }
22295
22296    fn handle_focus_out(
22297        &mut self,
22298        event: FocusOutEvent,
22299        _window: &mut Window,
22300        cx: &mut Context<Self>,
22301    ) {
22302        if event.blurred != self.focus_handle {
22303            self.last_focused_descendant = Some(event.blurred);
22304        }
22305        self.selection_drag_state = SelectionDragState::None;
22306        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22307    }
22308
22309    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22310        self.blink_manager.update(cx, BlinkManager::disable);
22311        self.buffer
22312            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22313
22314        if let Some(blame) = self.blame.as_ref() {
22315            blame.update(cx, GitBlame::blur)
22316        }
22317        if !self.hover_state.focused(window, cx) {
22318            hide_hover(self, cx);
22319        }
22320        if !self
22321            .context_menu
22322            .borrow()
22323            .as_ref()
22324            .is_some_and(|context_menu| context_menu.focused(window, cx))
22325        {
22326            self.hide_context_menu(window, cx);
22327        }
22328        self.take_active_edit_prediction(cx);
22329        cx.emit(EditorEvent::Blurred);
22330        cx.notify();
22331    }
22332
22333    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22334        let mut pending: String = window
22335            .pending_input_keystrokes()
22336            .into_iter()
22337            .flatten()
22338            .filter_map(|keystroke| keystroke.key_char.clone())
22339            .collect();
22340
22341        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22342            pending = "".to_string();
22343        }
22344
22345        let existing_pending = self
22346            .text_highlights::<PendingInput>(cx)
22347            .map(|(_, ranges)| ranges.to_vec());
22348        if existing_pending.is_none() && pending.is_empty() {
22349            return;
22350        }
22351        let transaction =
22352            self.transact(window, cx, |this, window, cx| {
22353                let selections = this
22354                    .selections
22355                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22356                let edits = selections
22357                    .iter()
22358                    .map(|selection| (selection.end..selection.end, pending.clone()));
22359                this.edit(edits, cx);
22360                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22361                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22362                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22363                    }));
22364                });
22365                if let Some(existing_ranges) = existing_pending {
22366                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22367                    this.edit(edits, cx);
22368                }
22369            });
22370
22371        let snapshot = self.snapshot(window, cx);
22372        let ranges = self
22373            .selections
22374            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22375            .into_iter()
22376            .map(|selection| {
22377                snapshot.buffer_snapshot().anchor_after(selection.end)
22378                    ..snapshot
22379                        .buffer_snapshot()
22380                        .anchor_before(selection.end + pending.len())
22381            })
22382            .collect();
22383
22384        if pending.is_empty() {
22385            self.clear_highlights::<PendingInput>(cx);
22386        } else {
22387            self.highlight_text::<PendingInput>(
22388                ranges,
22389                HighlightStyle {
22390                    underline: Some(UnderlineStyle {
22391                        thickness: px(1.),
22392                        color: None,
22393                        wavy: false,
22394                    }),
22395                    ..Default::default()
22396                },
22397                cx,
22398            );
22399        }
22400
22401        self.ime_transaction = self.ime_transaction.or(transaction);
22402        if let Some(transaction) = self.ime_transaction {
22403            self.buffer.update(cx, |buffer, cx| {
22404                buffer.group_until_transaction(transaction, cx);
22405            });
22406        }
22407
22408        if self.text_highlights::<PendingInput>(cx).is_none() {
22409            self.ime_transaction.take();
22410        }
22411    }
22412
22413    pub fn register_action_renderer(
22414        &mut self,
22415        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22416    ) -> Subscription {
22417        let id = self.next_editor_action_id.post_inc();
22418        self.editor_actions
22419            .borrow_mut()
22420            .insert(id, Box::new(listener));
22421
22422        let editor_actions = self.editor_actions.clone();
22423        Subscription::new(move || {
22424            editor_actions.borrow_mut().remove(&id);
22425        })
22426    }
22427
22428    pub fn register_action<A: Action>(
22429        &mut self,
22430        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22431    ) -> Subscription {
22432        let id = self.next_editor_action_id.post_inc();
22433        let listener = Arc::new(listener);
22434        self.editor_actions.borrow_mut().insert(
22435            id,
22436            Box::new(move |_, window, _| {
22437                let listener = listener.clone();
22438                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22439                    let action = action.downcast_ref().unwrap();
22440                    if phase == DispatchPhase::Bubble {
22441                        listener(action, window, cx)
22442                    }
22443                })
22444            }),
22445        );
22446
22447        let editor_actions = self.editor_actions.clone();
22448        Subscription::new(move || {
22449            editor_actions.borrow_mut().remove(&id);
22450        })
22451    }
22452
22453    pub fn file_header_size(&self) -> u32 {
22454        FILE_HEADER_HEIGHT
22455    }
22456
22457    pub fn restore(
22458        &mut self,
22459        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22460        window: &mut Window,
22461        cx: &mut Context<Self>,
22462    ) {
22463        let workspace = self.workspace();
22464        let project = self.project();
22465        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22466            let mut tasks = Vec::new();
22467            for (buffer_id, changes) in revert_changes {
22468                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22469                    buffer.update(cx, |buffer, cx| {
22470                        buffer.edit(
22471                            changes
22472                                .into_iter()
22473                                .map(|(range, text)| (range, text.to_string())),
22474                            None,
22475                            cx,
22476                        );
22477                    });
22478
22479                    if let Some(project) =
22480                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22481                    {
22482                        project.update(cx, |project, cx| {
22483                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22484                        })
22485                    }
22486                }
22487            }
22488            tasks
22489        });
22490        cx.spawn_in(window, async move |_, cx| {
22491            for (buffer, task) in save_tasks {
22492                let result = task.await;
22493                if result.is_err() {
22494                    let Some(path) = buffer
22495                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22496                        .ok()
22497                    else {
22498                        continue;
22499                    };
22500                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22501                        let Some(task) = cx
22502                            .update_window_entity(workspace, |workspace, window, cx| {
22503                                workspace
22504                                    .open_path_preview(path, None, false, false, false, window, cx)
22505                            })
22506                            .ok()
22507                        else {
22508                            continue;
22509                        };
22510                        task.await.log_err();
22511                    }
22512                }
22513            }
22514        })
22515        .detach();
22516        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22517            selections.refresh()
22518        });
22519    }
22520
22521    pub fn to_pixel_point(
22522        &self,
22523        source: multi_buffer::Anchor,
22524        editor_snapshot: &EditorSnapshot,
22525        window: &mut Window,
22526    ) -> Option<gpui::Point<Pixels>> {
22527        let source_point = source.to_display_point(editor_snapshot);
22528        self.display_to_pixel_point(source_point, editor_snapshot, window)
22529    }
22530
22531    pub fn display_to_pixel_point(
22532        &self,
22533        source: DisplayPoint,
22534        editor_snapshot: &EditorSnapshot,
22535        window: &mut Window,
22536    ) -> Option<gpui::Point<Pixels>> {
22537        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22538        let text_layout_details = self.text_layout_details(window);
22539        let scroll_top = text_layout_details
22540            .scroll_anchor
22541            .scroll_position(editor_snapshot)
22542            .y;
22543
22544        if source.row().as_f64() < scroll_top.floor() {
22545            return None;
22546        }
22547        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22548        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22549        Some(gpui::Point::new(source_x, source_y))
22550    }
22551
22552    pub fn has_visible_completions_menu(&self) -> bool {
22553        !self.edit_prediction_preview_is_active()
22554            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22555                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22556            })
22557    }
22558
22559    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22560        if self.mode.is_minimap() {
22561            return;
22562        }
22563        self.addons
22564            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22565    }
22566
22567    pub fn unregister_addon<T: Addon>(&mut self) {
22568        self.addons.remove(&std::any::TypeId::of::<T>());
22569    }
22570
22571    pub fn addon<T: Addon>(&self) -> Option<&T> {
22572        let type_id = std::any::TypeId::of::<T>();
22573        self.addons
22574            .get(&type_id)
22575            .and_then(|item| item.to_any().downcast_ref::<T>())
22576    }
22577
22578    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22579        let type_id = std::any::TypeId::of::<T>();
22580        self.addons
22581            .get_mut(&type_id)
22582            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22583    }
22584
22585    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22586        let text_layout_details = self.text_layout_details(window);
22587        let style = &text_layout_details.editor_style;
22588        let font_id = window.text_system().resolve_font(&style.text.font());
22589        let font_size = style.text.font_size.to_pixels(window.rem_size());
22590        let line_height = style.text.line_height_in_pixels(window.rem_size());
22591        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22592        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22593
22594        CharacterDimensions {
22595            em_width,
22596            em_advance,
22597            line_height,
22598        }
22599    }
22600
22601    pub fn last_gutter_dimensions(&self) -> &GutterDimensions {
22602        &self.gutter_dimensions
22603    }
22604
22605    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22606        self.load_diff_task.clone()
22607    }
22608
22609    fn read_metadata_from_db(
22610        &mut self,
22611        item_id: u64,
22612        workspace_id: WorkspaceId,
22613        window: &mut Window,
22614        cx: &mut Context<Editor>,
22615    ) {
22616        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22617            && !self.mode.is_minimap()
22618            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22619        {
22620            let buffer_snapshot = OnceCell::new();
22621
22622            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22623                && !folds.is_empty()
22624            {
22625                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22626                self.fold_ranges(
22627                    folds
22628                        .into_iter()
22629                        .map(|(start, end)| {
22630                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22631                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22632                        })
22633                        .collect(),
22634                    false,
22635                    window,
22636                    cx,
22637                );
22638            }
22639
22640            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22641                && !selections.is_empty()
22642            {
22643                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22644                // skip adding the initial selection to selection history
22645                self.selection_history.mode = SelectionHistoryMode::Skipping;
22646                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22647                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22648                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22649                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22650                    }));
22651                });
22652                self.selection_history.mode = SelectionHistoryMode::Normal;
22653            };
22654        }
22655
22656        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22657    }
22658
22659    fn update_lsp_data(
22660        &mut self,
22661        for_buffer: Option<BufferId>,
22662        window: &mut Window,
22663        cx: &mut Context<'_, Self>,
22664    ) {
22665        self.pull_diagnostics(for_buffer, window, cx);
22666        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22667    }
22668
22669    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22670        if self.ignore_lsp_data() {
22671            return;
22672        }
22673        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
22674            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22675        }
22676    }
22677
22678    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22679        if self.ignore_lsp_data() {
22680            return;
22681        }
22682
22683        if !self.registered_buffers.contains_key(&buffer_id)
22684            && let Some(project) = self.project.as_ref()
22685        {
22686            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22687                project.update(cx, |project, cx| {
22688                    self.registered_buffers.insert(
22689                        buffer_id,
22690                        project.register_buffer_with_language_servers(&buffer, cx),
22691                    );
22692                });
22693            } else {
22694                self.registered_buffers.remove(&buffer_id);
22695            }
22696        }
22697    }
22698
22699    fn ignore_lsp_data(&self) -> bool {
22700        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22701        // skip any LSP updates for it.
22702        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22703    }
22704}
22705
22706fn edit_for_markdown_paste<'a>(
22707    buffer: &MultiBufferSnapshot,
22708    range: Range<MultiBufferOffset>,
22709    to_insert: &'a str,
22710    url: Option<url::Url>,
22711) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
22712    if url.is_none() {
22713        return (range, Cow::Borrowed(to_insert));
22714    };
22715
22716    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22717
22718    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22719        Cow::Borrowed(to_insert)
22720    } else {
22721        Cow::Owned(format!("[{old_text}]({to_insert})"))
22722    };
22723    (range, new_text)
22724}
22725
22726fn process_completion_for_edit(
22727    completion: &Completion,
22728    intent: CompletionIntent,
22729    buffer: &Entity<Buffer>,
22730    cursor_position: &text::Anchor,
22731    cx: &mut Context<Editor>,
22732) -> CompletionEdit {
22733    let buffer = buffer.read(cx);
22734    let buffer_snapshot = buffer.snapshot();
22735    let (snippet, new_text) = if completion.is_snippet() {
22736        let mut snippet_source = completion.new_text.clone();
22737        // Workaround for typescript language server issues so that methods don't expand within
22738        // strings and functions with type expressions. The previous point is used because the query
22739        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22740        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22741        let previous_point = if previous_point.column > 0 {
22742            cursor_position.to_previous_offset(&buffer_snapshot)
22743        } else {
22744            cursor_position.to_offset(&buffer_snapshot)
22745        };
22746        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22747            && scope.prefers_label_for_snippet_in_completion()
22748            && let Some(label) = completion.label()
22749            && matches!(
22750                completion.kind(),
22751                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22752            )
22753        {
22754            snippet_source = label;
22755        }
22756        match Snippet::parse(&snippet_source).log_err() {
22757            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22758            None => (None, completion.new_text.clone()),
22759        }
22760    } else {
22761        (None, completion.new_text.clone())
22762    };
22763
22764    let mut range_to_replace = {
22765        let replace_range = &completion.replace_range;
22766        if let CompletionSource::Lsp {
22767            insert_range: Some(insert_range),
22768            ..
22769        } = &completion.source
22770        {
22771            debug_assert_eq!(
22772                insert_range.start, replace_range.start,
22773                "insert_range and replace_range should start at the same position"
22774            );
22775            debug_assert!(
22776                insert_range
22777                    .start
22778                    .cmp(cursor_position, &buffer_snapshot)
22779                    .is_le(),
22780                "insert_range should start before or at cursor position"
22781            );
22782            debug_assert!(
22783                replace_range
22784                    .start
22785                    .cmp(cursor_position, &buffer_snapshot)
22786                    .is_le(),
22787                "replace_range should start before or at cursor position"
22788            );
22789
22790            let should_replace = match intent {
22791                CompletionIntent::CompleteWithInsert => false,
22792                CompletionIntent::CompleteWithReplace => true,
22793                CompletionIntent::Complete | CompletionIntent::Compose => {
22794                    let insert_mode =
22795                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22796                            .completions
22797                            .lsp_insert_mode;
22798                    match insert_mode {
22799                        LspInsertMode::Insert => false,
22800                        LspInsertMode::Replace => true,
22801                        LspInsertMode::ReplaceSubsequence => {
22802                            let mut text_to_replace = buffer.chars_for_range(
22803                                buffer.anchor_before(replace_range.start)
22804                                    ..buffer.anchor_after(replace_range.end),
22805                            );
22806                            let mut current_needle = text_to_replace.next();
22807                            for haystack_ch in completion.label.text.chars() {
22808                                if let Some(needle_ch) = current_needle
22809                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22810                                {
22811                                    current_needle = text_to_replace.next();
22812                                }
22813                            }
22814                            current_needle.is_none()
22815                        }
22816                        LspInsertMode::ReplaceSuffix => {
22817                            if replace_range
22818                                .end
22819                                .cmp(cursor_position, &buffer_snapshot)
22820                                .is_gt()
22821                            {
22822                                let range_after_cursor = *cursor_position..replace_range.end;
22823                                let text_after_cursor = buffer
22824                                    .text_for_range(
22825                                        buffer.anchor_before(range_after_cursor.start)
22826                                            ..buffer.anchor_after(range_after_cursor.end),
22827                                    )
22828                                    .collect::<String>()
22829                                    .to_ascii_lowercase();
22830                                completion
22831                                    .label
22832                                    .text
22833                                    .to_ascii_lowercase()
22834                                    .ends_with(&text_after_cursor)
22835                            } else {
22836                                true
22837                            }
22838                        }
22839                    }
22840                }
22841            };
22842
22843            if should_replace {
22844                replace_range.clone()
22845            } else {
22846                insert_range.clone()
22847            }
22848        } else {
22849            replace_range.clone()
22850        }
22851    };
22852
22853    if range_to_replace
22854        .end
22855        .cmp(cursor_position, &buffer_snapshot)
22856        .is_lt()
22857    {
22858        range_to_replace.end = *cursor_position;
22859    }
22860
22861    let replace_range = range_to_replace.to_offset(buffer);
22862    CompletionEdit {
22863        new_text,
22864        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
22865        snippet,
22866    }
22867}
22868
22869struct CompletionEdit {
22870    new_text: String,
22871    replace_range: Range<BufferOffset>,
22872    snippet: Option<Snippet>,
22873}
22874
22875fn insert_extra_newline_brackets(
22876    buffer: &MultiBufferSnapshot,
22877    range: Range<MultiBufferOffset>,
22878    language: &language::LanguageScope,
22879) -> bool {
22880    let leading_whitespace_len = buffer
22881        .reversed_chars_at(range.start)
22882        .take_while(|c| c.is_whitespace() && *c != '\n')
22883        .map(|c| c.len_utf8())
22884        .sum::<usize>();
22885    let trailing_whitespace_len = buffer
22886        .chars_at(range.end)
22887        .take_while(|c| c.is_whitespace() && *c != '\n')
22888        .map(|c| c.len_utf8())
22889        .sum::<usize>();
22890    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22891
22892    language.brackets().any(|(pair, enabled)| {
22893        let pair_start = pair.start.trim_end();
22894        let pair_end = pair.end.trim_start();
22895
22896        enabled
22897            && pair.newline
22898            && buffer.contains_str_at(range.end, pair_end)
22899            && buffer.contains_str_at(
22900                range.start.saturating_sub_usize(pair_start.len()),
22901                pair_start,
22902            )
22903    })
22904}
22905
22906fn insert_extra_newline_tree_sitter(
22907    buffer: &MultiBufferSnapshot,
22908    range: Range<MultiBufferOffset>,
22909) -> bool {
22910    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22911        [(buffer, range, _)] => (*buffer, range.clone()),
22912        _ => return false,
22913    };
22914    let pair = {
22915        let mut result: Option<BracketMatch<usize>> = None;
22916
22917        for pair in buffer
22918            .all_bracket_ranges(range.start.0..range.end.0)
22919            .filter(move |pair| {
22920                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
22921            })
22922        {
22923            let len = pair.close_range.end - pair.open_range.start;
22924
22925            if let Some(existing) = &result {
22926                let existing_len = existing.close_range.end - existing.open_range.start;
22927                if len > existing_len {
22928                    continue;
22929                }
22930            }
22931
22932            result = Some(pair);
22933        }
22934
22935        result
22936    };
22937    let Some(pair) = pair else {
22938        return false;
22939    };
22940    pair.newline_only
22941        && buffer
22942            .chars_for_range(pair.open_range.end..range.start.0)
22943            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
22944            .all(|c| c.is_whitespace() && c != '\n')
22945}
22946
22947fn update_uncommitted_diff_for_buffer(
22948    editor: Entity<Editor>,
22949    project: &Entity<Project>,
22950    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22951    buffer: Entity<MultiBuffer>,
22952    cx: &mut App,
22953) -> Task<()> {
22954    let mut tasks = Vec::new();
22955    project.update(cx, |project, cx| {
22956        for buffer in buffers {
22957            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22958                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22959            }
22960        }
22961    });
22962    cx.spawn(async move |cx| {
22963        let diffs = future::join_all(tasks).await;
22964        if editor
22965            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22966            .unwrap_or(false)
22967        {
22968            return;
22969        }
22970
22971        buffer
22972            .update(cx, |buffer, cx| {
22973                for diff in diffs.into_iter().flatten() {
22974                    buffer.add_diff(diff, cx);
22975                }
22976            })
22977            .ok();
22978    })
22979}
22980
22981fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22982    let tab_size = tab_size.get() as usize;
22983    let mut width = offset;
22984
22985    for ch in text.chars() {
22986        width += if ch == '\t' {
22987            tab_size - (width % tab_size)
22988        } else {
22989            1
22990        };
22991    }
22992
22993    width - offset
22994}
22995
22996#[cfg(test)]
22997mod tests {
22998    use super::*;
22999
23000    #[test]
23001    fn test_string_size_with_expanded_tabs() {
23002        let nz = |val| NonZeroU32::new(val).unwrap();
23003        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
23004        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
23005        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
23006        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
23007        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
23008        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
23009        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
23010        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
23011    }
23012}
23013
23014/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
23015struct WordBreakingTokenizer<'a> {
23016    input: &'a str,
23017}
23018
23019impl<'a> WordBreakingTokenizer<'a> {
23020    fn new(input: &'a str) -> Self {
23021        Self { input }
23022    }
23023}
23024
23025fn is_char_ideographic(ch: char) -> bool {
23026    use unicode_script::Script::*;
23027    use unicode_script::UnicodeScript;
23028    matches!(ch.script(), Han | Tangut | Yi)
23029}
23030
23031fn is_grapheme_ideographic(text: &str) -> bool {
23032    text.chars().any(is_char_ideographic)
23033}
23034
23035fn is_grapheme_whitespace(text: &str) -> bool {
23036    text.chars().any(|x| x.is_whitespace())
23037}
23038
23039fn should_stay_with_preceding_ideograph(text: &str) -> bool {
23040    text.chars()
23041        .next()
23042        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
23043}
23044
23045#[derive(PartialEq, Eq, Debug, Clone, Copy)]
23046enum WordBreakToken<'a> {
23047    Word { token: &'a str, grapheme_len: usize },
23048    InlineWhitespace { token: &'a str, grapheme_len: usize },
23049    Newline,
23050}
23051
23052impl<'a> Iterator for WordBreakingTokenizer<'a> {
23053    /// Yields a span, the count of graphemes in the token, and whether it was
23054    /// whitespace. Note that it also breaks at word boundaries.
23055    type Item = WordBreakToken<'a>;
23056
23057    fn next(&mut self) -> Option<Self::Item> {
23058        use unicode_segmentation::UnicodeSegmentation;
23059        if self.input.is_empty() {
23060            return None;
23061        }
23062
23063        let mut iter = self.input.graphemes(true).peekable();
23064        let mut offset = 0;
23065        let mut grapheme_len = 0;
23066        if let Some(first_grapheme) = iter.next() {
23067            let is_newline = first_grapheme == "\n";
23068            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23069            offset += first_grapheme.len();
23070            grapheme_len += 1;
23071            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
23072                if let Some(grapheme) = iter.peek().copied()
23073                    && should_stay_with_preceding_ideograph(grapheme)
23074                {
23075                    offset += grapheme.len();
23076                    grapheme_len += 1;
23077                }
23078            } else {
23079                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23080                let mut next_word_bound = words.peek().copied();
23081                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23082                    next_word_bound = words.next();
23083                }
23084                while let Some(grapheme) = iter.peek().copied() {
23085                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23086                        break;
23087                    };
23088                    if is_grapheme_whitespace(grapheme) != is_whitespace
23089                        || (grapheme == "\n") != is_newline
23090                    {
23091                        break;
23092                    };
23093                    offset += grapheme.len();
23094                    grapheme_len += 1;
23095                    iter.next();
23096                }
23097            }
23098            let token = &self.input[..offset];
23099            self.input = &self.input[offset..];
23100            if token == "\n" {
23101                Some(WordBreakToken::Newline)
23102            } else if is_whitespace {
23103                Some(WordBreakToken::InlineWhitespace {
23104                    token,
23105                    grapheme_len,
23106                })
23107            } else {
23108                Some(WordBreakToken::Word {
23109                    token,
23110                    grapheme_len,
23111                })
23112            }
23113        } else {
23114            None
23115        }
23116    }
23117}
23118
23119#[test]
23120fn test_word_breaking_tokenizer() {
23121    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23122        ("", &[]),
23123        ("  ", &[whitespace("  ", 2)]),
23124        ("Ʒ", &[word("Ʒ", 1)]),
23125        ("Ǽ", &[word("Ǽ", 1)]),
23126        ("", &[word("", 1)]),
23127        ("⋑⋑", &[word("⋑⋑", 2)]),
23128        (
23129            "原理,进而",
23130            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23131        ),
23132        (
23133            "hello world",
23134            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23135        ),
23136        (
23137            "hello, world",
23138            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23139        ),
23140        (
23141            "  hello world",
23142            &[
23143                whitespace("  ", 2),
23144                word("hello", 5),
23145                whitespace(" ", 1),
23146                word("world", 5),
23147            ],
23148        ),
23149        (
23150            "这是什么 \n 钢笔",
23151            &[
23152                word("", 1),
23153                word("", 1),
23154                word("", 1),
23155                word("", 1),
23156                whitespace(" ", 1),
23157                newline(),
23158                whitespace(" ", 1),
23159                word("", 1),
23160                word("", 1),
23161            ],
23162        ),
23163        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23164    ];
23165
23166    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23167        WordBreakToken::Word {
23168            token,
23169            grapheme_len,
23170        }
23171    }
23172
23173    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23174        WordBreakToken::InlineWhitespace {
23175            token,
23176            grapheme_len,
23177        }
23178    }
23179
23180    fn newline() -> WordBreakToken<'static> {
23181        WordBreakToken::Newline
23182    }
23183
23184    for (input, result) in tests {
23185        assert_eq!(
23186            WordBreakingTokenizer::new(input)
23187                .collect::<Vec<_>>()
23188                .as_slice(),
23189            *result,
23190        );
23191    }
23192}
23193
23194fn wrap_with_prefix(
23195    first_line_prefix: String,
23196    subsequent_lines_prefix: String,
23197    unwrapped_text: String,
23198    wrap_column: usize,
23199    tab_size: NonZeroU32,
23200    preserve_existing_whitespace: bool,
23201) -> String {
23202    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23203    let subsequent_lines_prefix_len =
23204        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23205    let mut wrapped_text = String::new();
23206    let mut current_line = first_line_prefix;
23207    let mut is_first_line = true;
23208
23209    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23210    let mut current_line_len = first_line_prefix_len;
23211    let mut in_whitespace = false;
23212    for token in tokenizer {
23213        let have_preceding_whitespace = in_whitespace;
23214        match token {
23215            WordBreakToken::Word {
23216                token,
23217                grapheme_len,
23218            } => {
23219                in_whitespace = false;
23220                let current_prefix_len = if is_first_line {
23221                    first_line_prefix_len
23222                } else {
23223                    subsequent_lines_prefix_len
23224                };
23225                if current_line_len + grapheme_len > wrap_column
23226                    && current_line_len != current_prefix_len
23227                {
23228                    wrapped_text.push_str(current_line.trim_end());
23229                    wrapped_text.push('\n');
23230                    is_first_line = false;
23231                    current_line = subsequent_lines_prefix.clone();
23232                    current_line_len = subsequent_lines_prefix_len;
23233                }
23234                current_line.push_str(token);
23235                current_line_len += grapheme_len;
23236            }
23237            WordBreakToken::InlineWhitespace {
23238                mut token,
23239                mut grapheme_len,
23240            } => {
23241                in_whitespace = true;
23242                if have_preceding_whitespace && !preserve_existing_whitespace {
23243                    continue;
23244                }
23245                if !preserve_existing_whitespace {
23246                    // Keep a single whitespace grapheme as-is
23247                    if let Some(first) =
23248                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23249                    {
23250                        token = first;
23251                    } else {
23252                        token = " ";
23253                    }
23254                    grapheme_len = 1;
23255                }
23256                let current_prefix_len = if is_first_line {
23257                    first_line_prefix_len
23258                } else {
23259                    subsequent_lines_prefix_len
23260                };
23261                if current_line_len + grapheme_len > wrap_column {
23262                    wrapped_text.push_str(current_line.trim_end());
23263                    wrapped_text.push('\n');
23264                    is_first_line = false;
23265                    current_line = subsequent_lines_prefix.clone();
23266                    current_line_len = subsequent_lines_prefix_len;
23267                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23268                    current_line.push_str(token);
23269                    current_line_len += grapheme_len;
23270                }
23271            }
23272            WordBreakToken::Newline => {
23273                in_whitespace = true;
23274                let current_prefix_len = if is_first_line {
23275                    first_line_prefix_len
23276                } else {
23277                    subsequent_lines_prefix_len
23278                };
23279                if preserve_existing_whitespace {
23280                    wrapped_text.push_str(current_line.trim_end());
23281                    wrapped_text.push('\n');
23282                    is_first_line = false;
23283                    current_line = subsequent_lines_prefix.clone();
23284                    current_line_len = subsequent_lines_prefix_len;
23285                } else if have_preceding_whitespace {
23286                    continue;
23287                } else if current_line_len + 1 > wrap_column
23288                    && current_line_len != current_prefix_len
23289                {
23290                    wrapped_text.push_str(current_line.trim_end());
23291                    wrapped_text.push('\n');
23292                    is_first_line = false;
23293                    current_line = subsequent_lines_prefix.clone();
23294                    current_line_len = subsequent_lines_prefix_len;
23295                } else if current_line_len != current_prefix_len {
23296                    current_line.push(' ');
23297                    current_line_len += 1;
23298                }
23299            }
23300        }
23301    }
23302
23303    if !current_line.is_empty() {
23304        wrapped_text.push_str(&current_line);
23305    }
23306    wrapped_text
23307}
23308
23309#[test]
23310fn test_wrap_with_prefix() {
23311    assert_eq!(
23312        wrap_with_prefix(
23313            "# ".to_string(),
23314            "# ".to_string(),
23315            "abcdefg".to_string(),
23316            4,
23317            NonZeroU32::new(4).unwrap(),
23318            false,
23319        ),
23320        "# abcdefg"
23321    );
23322    assert_eq!(
23323        wrap_with_prefix(
23324            "".to_string(),
23325            "".to_string(),
23326            "\thello world".to_string(),
23327            8,
23328            NonZeroU32::new(4).unwrap(),
23329            false,
23330        ),
23331        "hello\nworld"
23332    );
23333    assert_eq!(
23334        wrap_with_prefix(
23335            "// ".to_string(),
23336            "// ".to_string(),
23337            "xx \nyy zz aa bb cc".to_string(),
23338            12,
23339            NonZeroU32::new(4).unwrap(),
23340            false,
23341        ),
23342        "// xx yy zz\n// aa bb cc"
23343    );
23344    assert_eq!(
23345        wrap_with_prefix(
23346            String::new(),
23347            String::new(),
23348            "这是什么 \n 钢笔".to_string(),
23349            3,
23350            NonZeroU32::new(4).unwrap(),
23351            false,
23352        ),
23353        "这是什\n么 钢\n"
23354    );
23355    assert_eq!(
23356        wrap_with_prefix(
23357            String::new(),
23358            String::new(),
23359            format!("foo{}bar", '\u{2009}'), // thin space
23360            80,
23361            NonZeroU32::new(4).unwrap(),
23362            false,
23363        ),
23364        format!("foo{}bar", '\u{2009}')
23365    );
23366}
23367
23368pub trait CollaborationHub {
23369    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23370    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23371    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23372}
23373
23374impl CollaborationHub for Entity<Project> {
23375    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23376        self.read(cx).collaborators()
23377    }
23378
23379    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23380        self.read(cx).user_store().read(cx).participant_indices()
23381    }
23382
23383    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23384        let this = self.read(cx);
23385        let user_ids = this.collaborators().values().map(|c| c.user_id);
23386        this.user_store().read(cx).participant_names(user_ids, cx)
23387    }
23388}
23389
23390pub trait SemanticsProvider {
23391    fn hover(
23392        &self,
23393        buffer: &Entity<Buffer>,
23394        position: text::Anchor,
23395        cx: &mut App,
23396    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23397
23398    fn inline_values(
23399        &self,
23400        buffer_handle: Entity<Buffer>,
23401        range: Range<text::Anchor>,
23402        cx: &mut App,
23403    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23404
23405    fn applicable_inlay_chunks(
23406        &self,
23407        buffer: &Entity<Buffer>,
23408        ranges: &[Range<text::Anchor>],
23409        cx: &mut App,
23410    ) -> Vec<Range<BufferRow>>;
23411
23412    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23413
23414    fn inlay_hints(
23415        &self,
23416        invalidate: InvalidationStrategy,
23417        buffer: Entity<Buffer>,
23418        ranges: Vec<Range<text::Anchor>>,
23419        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23420        cx: &mut App,
23421    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23422
23423    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23424
23425    fn document_highlights(
23426        &self,
23427        buffer: &Entity<Buffer>,
23428        position: text::Anchor,
23429        cx: &mut App,
23430    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23431
23432    fn definitions(
23433        &self,
23434        buffer: &Entity<Buffer>,
23435        position: text::Anchor,
23436        kind: GotoDefinitionKind,
23437        cx: &mut App,
23438    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23439
23440    fn range_for_rename(
23441        &self,
23442        buffer: &Entity<Buffer>,
23443        position: text::Anchor,
23444        cx: &mut App,
23445    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23446
23447    fn perform_rename(
23448        &self,
23449        buffer: &Entity<Buffer>,
23450        position: text::Anchor,
23451        new_name: String,
23452        cx: &mut App,
23453    ) -> Option<Task<Result<ProjectTransaction>>>;
23454}
23455
23456pub trait CompletionProvider {
23457    fn completions(
23458        &self,
23459        excerpt_id: ExcerptId,
23460        buffer: &Entity<Buffer>,
23461        buffer_position: text::Anchor,
23462        trigger: CompletionContext,
23463        window: &mut Window,
23464        cx: &mut Context<Editor>,
23465    ) -> Task<Result<Vec<CompletionResponse>>>;
23466
23467    fn resolve_completions(
23468        &self,
23469        _buffer: Entity<Buffer>,
23470        _completion_indices: Vec<usize>,
23471        _completions: Rc<RefCell<Box<[Completion]>>>,
23472        _cx: &mut Context<Editor>,
23473    ) -> Task<Result<bool>> {
23474        Task::ready(Ok(false))
23475    }
23476
23477    fn apply_additional_edits_for_completion(
23478        &self,
23479        _buffer: Entity<Buffer>,
23480        _completions: Rc<RefCell<Box<[Completion]>>>,
23481        _completion_index: usize,
23482        _push_to_history: bool,
23483        _cx: &mut Context<Editor>,
23484    ) -> Task<Result<Option<language::Transaction>>> {
23485        Task::ready(Ok(None))
23486    }
23487
23488    fn is_completion_trigger(
23489        &self,
23490        buffer: &Entity<Buffer>,
23491        position: language::Anchor,
23492        text: &str,
23493        trigger_in_words: bool,
23494        cx: &mut Context<Editor>,
23495    ) -> bool;
23496
23497    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23498
23499    fn sort_completions(&self) -> bool {
23500        true
23501    }
23502
23503    fn filter_completions(&self) -> bool {
23504        true
23505    }
23506
23507    fn show_snippets(&self) -> bool {
23508        false
23509    }
23510}
23511
23512pub trait CodeActionProvider {
23513    fn id(&self) -> Arc<str>;
23514
23515    fn code_actions(
23516        &self,
23517        buffer: &Entity<Buffer>,
23518        range: Range<text::Anchor>,
23519        window: &mut Window,
23520        cx: &mut App,
23521    ) -> Task<Result<Vec<CodeAction>>>;
23522
23523    fn apply_code_action(
23524        &self,
23525        buffer_handle: Entity<Buffer>,
23526        action: CodeAction,
23527        excerpt_id: ExcerptId,
23528        push_to_history: bool,
23529        window: &mut Window,
23530        cx: &mut App,
23531    ) -> Task<Result<ProjectTransaction>>;
23532}
23533
23534impl CodeActionProvider for Entity<Project> {
23535    fn id(&self) -> Arc<str> {
23536        "project".into()
23537    }
23538
23539    fn code_actions(
23540        &self,
23541        buffer: &Entity<Buffer>,
23542        range: Range<text::Anchor>,
23543        _window: &mut Window,
23544        cx: &mut App,
23545    ) -> Task<Result<Vec<CodeAction>>> {
23546        self.update(cx, |project, cx| {
23547            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23548            let code_actions = project.code_actions(buffer, range, None, cx);
23549            cx.background_spawn(async move {
23550                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23551                Ok(code_lens_actions
23552                    .context("code lens fetch")?
23553                    .into_iter()
23554                    .flatten()
23555                    .chain(
23556                        code_actions
23557                            .context("code action fetch")?
23558                            .into_iter()
23559                            .flatten(),
23560                    )
23561                    .collect())
23562            })
23563        })
23564    }
23565
23566    fn apply_code_action(
23567        &self,
23568        buffer_handle: Entity<Buffer>,
23569        action: CodeAction,
23570        _excerpt_id: ExcerptId,
23571        push_to_history: bool,
23572        _window: &mut Window,
23573        cx: &mut App,
23574    ) -> Task<Result<ProjectTransaction>> {
23575        self.update(cx, |project, cx| {
23576            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23577        })
23578    }
23579}
23580
23581fn snippet_completions(
23582    project: &Project,
23583    buffer: &Entity<Buffer>,
23584    buffer_anchor: text::Anchor,
23585    classifier: CharClassifier,
23586    cx: &mut App,
23587) -> Task<Result<CompletionResponse>> {
23588    let languages = buffer.read(cx).languages_at(buffer_anchor);
23589    let snippet_store = project.snippets().read(cx);
23590
23591    let scopes: Vec<_> = languages
23592        .iter()
23593        .filter_map(|language| {
23594            let language_name = language.lsp_id();
23595            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23596
23597            if snippets.is_empty() {
23598                None
23599            } else {
23600                Some((language.default_scope(), snippets))
23601            }
23602        })
23603        .collect();
23604
23605    if scopes.is_empty() {
23606        return Task::ready(Ok(CompletionResponse {
23607            completions: vec![],
23608            display_options: CompletionDisplayOptions::default(),
23609            is_incomplete: false,
23610        }));
23611    }
23612
23613    let snapshot = buffer.read(cx).text_snapshot();
23614    let executor = cx.background_executor().clone();
23615
23616    cx.background_spawn(async move {
23617        let is_word_char = |c| classifier.is_word(c);
23618
23619        let mut is_incomplete = false;
23620        let mut completions: Vec<Completion> = Vec::new();
23621
23622        const MAX_PREFIX_LEN: usize = 128;
23623        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
23624        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
23625        let window_start = snapshot.clip_offset(window_start, Bias::Left);
23626
23627        let max_buffer_window: String = snapshot
23628            .text_for_range(window_start..buffer_offset)
23629            .collect();
23630
23631        if max_buffer_window.is_empty() {
23632            return Ok(CompletionResponse {
23633                completions: vec![],
23634                display_options: CompletionDisplayOptions::default(),
23635                is_incomplete: true,
23636            });
23637        }
23638
23639        for (_scope, snippets) in scopes.into_iter() {
23640            // Sort snippets by word count to match longer snippet prefixes first.
23641            let mut sorted_snippet_candidates = snippets
23642                .iter()
23643                .enumerate()
23644                .flat_map(|(snippet_ix, snippet)| {
23645                    snippet
23646                        .prefix
23647                        .iter()
23648                        .enumerate()
23649                        .map(move |(prefix_ix, prefix)| {
23650                            let word_count =
23651                                snippet_candidate_suffixes(prefix, is_word_char).count();
23652                            ((snippet_ix, prefix_ix), prefix, word_count)
23653                        })
23654                })
23655                .collect_vec();
23656            sorted_snippet_candidates
23657                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
23658
23659            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
23660
23661            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
23662                .take(
23663                    sorted_snippet_candidates
23664                        .first()
23665                        .map(|(_, _, word_count)| *word_count)
23666                        .unwrap_or_default(),
23667                )
23668                .collect_vec();
23669
23670            const MAX_RESULTS: usize = 100;
23671            // Each match also remembers how many characters from the buffer it consumed
23672            let mut matches: Vec<(StringMatch, usize)> = vec![];
23673
23674            let mut snippet_list_cutoff_index = 0;
23675            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
23676                let word_count = buffer_index + 1;
23677                // Increase `snippet_list_cutoff_index` until we have all of the
23678                // snippets with sufficiently many words.
23679                while sorted_snippet_candidates
23680                    .get(snippet_list_cutoff_index)
23681                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
23682                        *snippet_word_count >= word_count
23683                    })
23684                {
23685                    snippet_list_cutoff_index += 1;
23686                }
23687
23688                // Take only the candidates with at least `word_count` many words
23689                let snippet_candidates_at_word_len =
23690                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
23691
23692                let candidates = snippet_candidates_at_word_len
23693                    .iter()
23694                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
23695                    .enumerate() // index in `sorted_snippet_candidates`
23696                    // First char must match
23697                    .filter(|(_ix, prefix)| {
23698                        itertools::equal(
23699                            prefix
23700                                .chars()
23701                                .next()
23702                                .into_iter()
23703                                .flat_map(|c| c.to_lowercase()),
23704                            buffer_window
23705                                .chars()
23706                                .next()
23707                                .into_iter()
23708                                .flat_map(|c| c.to_lowercase()),
23709                        )
23710                    })
23711                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
23712                    .collect::<Vec<StringMatchCandidate>>();
23713
23714                matches.extend(
23715                    fuzzy::match_strings(
23716                        &candidates,
23717                        &buffer_window,
23718                        buffer_window.chars().any(|c| c.is_uppercase()),
23719                        true,
23720                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
23721                        &Default::default(),
23722                        executor.clone(),
23723                    )
23724                    .await
23725                    .into_iter()
23726                    .map(|string_match| (string_match, buffer_window.len())),
23727                );
23728
23729                if matches.len() >= MAX_RESULTS {
23730                    break;
23731                }
23732            }
23733
23734            let to_lsp = |point: &text::Anchor| {
23735                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23736                point_to_lsp(end)
23737            };
23738            let lsp_end = to_lsp(&buffer_anchor);
23739
23740            if matches.len() >= MAX_RESULTS {
23741                is_incomplete = true;
23742            }
23743
23744            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
23745                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
23746                    sorted_snippet_candidates[string_match.candidate_id];
23747                let snippet = &snippets[snippet_index];
23748                let start = buffer_offset - buffer_window_len;
23749                let start = snapshot.anchor_before(start);
23750                let range = start..buffer_anchor;
23751                let lsp_start = to_lsp(&start);
23752                let lsp_range = lsp::Range {
23753                    start: lsp_start,
23754                    end: lsp_end,
23755                };
23756                Completion {
23757                    replace_range: range,
23758                    new_text: snippet.body.clone(),
23759                    source: CompletionSource::Lsp {
23760                        insert_range: None,
23761                        server_id: LanguageServerId(usize::MAX),
23762                        resolved: true,
23763                        lsp_completion: Box::new(lsp::CompletionItem {
23764                            label: snippet.prefix.first().unwrap().clone(),
23765                            kind: Some(CompletionItemKind::SNIPPET),
23766                            label_details: snippet.description.as_ref().map(|description| {
23767                                lsp::CompletionItemLabelDetails {
23768                                    detail: Some(description.clone()),
23769                                    description: None,
23770                                }
23771                            }),
23772                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23773                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23774                                lsp::InsertReplaceEdit {
23775                                    new_text: snippet.body.clone(),
23776                                    insert: lsp_range,
23777                                    replace: lsp_range,
23778                                },
23779                            )),
23780                            filter_text: Some(snippet.body.clone()),
23781                            sort_text: Some(char::MAX.to_string()),
23782                            ..lsp::CompletionItem::default()
23783                        }),
23784                        lsp_defaults: None,
23785                    },
23786                    label: CodeLabel {
23787                        text: matching_prefix.clone(),
23788                        runs: Vec::new(),
23789                        filter_range: 0..matching_prefix.len(),
23790                    },
23791                    icon_path: None,
23792                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23793                        single_line: snippet.name.clone().into(),
23794                        plain_text: snippet
23795                            .description
23796                            .clone()
23797                            .map(|description| description.into()),
23798                    }),
23799                    insert_text_mode: None,
23800                    confirm: None,
23801                    match_start: Some(start),
23802                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
23803                }
23804            }));
23805        }
23806
23807        Ok(CompletionResponse {
23808            completions,
23809            display_options: CompletionDisplayOptions::default(),
23810            is_incomplete,
23811        })
23812    })
23813}
23814
23815impl CompletionProvider for Entity<Project> {
23816    fn completions(
23817        &self,
23818        _excerpt_id: ExcerptId,
23819        buffer: &Entity<Buffer>,
23820        buffer_position: text::Anchor,
23821        options: CompletionContext,
23822        _window: &mut Window,
23823        cx: &mut Context<Editor>,
23824    ) -> Task<Result<Vec<CompletionResponse>>> {
23825        self.update(cx, |project, cx| {
23826            let task = project.completions(buffer, buffer_position, options, cx);
23827            cx.background_spawn(task)
23828        })
23829    }
23830
23831    fn resolve_completions(
23832        &self,
23833        buffer: Entity<Buffer>,
23834        completion_indices: Vec<usize>,
23835        completions: Rc<RefCell<Box<[Completion]>>>,
23836        cx: &mut Context<Editor>,
23837    ) -> Task<Result<bool>> {
23838        self.update(cx, |project, cx| {
23839            project.lsp_store().update(cx, |lsp_store, cx| {
23840                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23841            })
23842        })
23843    }
23844
23845    fn apply_additional_edits_for_completion(
23846        &self,
23847        buffer: Entity<Buffer>,
23848        completions: Rc<RefCell<Box<[Completion]>>>,
23849        completion_index: usize,
23850        push_to_history: bool,
23851        cx: &mut Context<Editor>,
23852    ) -> Task<Result<Option<language::Transaction>>> {
23853        self.update(cx, |project, cx| {
23854            project.lsp_store().update(cx, |lsp_store, cx| {
23855                lsp_store.apply_additional_edits_for_completion(
23856                    buffer,
23857                    completions,
23858                    completion_index,
23859                    push_to_history,
23860                    cx,
23861                )
23862            })
23863        })
23864    }
23865
23866    fn is_completion_trigger(
23867        &self,
23868        buffer: &Entity<Buffer>,
23869        position: language::Anchor,
23870        text: &str,
23871        trigger_in_words: bool,
23872        cx: &mut Context<Editor>,
23873    ) -> bool {
23874        let mut chars = text.chars();
23875        let char = if let Some(char) = chars.next() {
23876            char
23877        } else {
23878            return false;
23879        };
23880        if chars.next().is_some() {
23881            return false;
23882        }
23883
23884        let buffer = buffer.read(cx);
23885        let snapshot = buffer.snapshot();
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}