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_types::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, bail};
   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_types::{EditPredictionDelegate, EditPredictionDelegateHandle};
   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, TextRun, 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::{ControlFlow, 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    AccentColors, 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: &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: &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 = (
  730    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  731    Arc<[Range<Anchor>]>,
  732);
  733type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  734
  735#[derive(Default)]
  736struct ScrollbarMarkerState {
  737    scrollbar_size: Size<Pixels>,
  738    dirty: bool,
  739    markers: Arc<[PaintQuad]>,
  740    pending_refresh: Option<Task<Result<()>>>,
  741}
  742
  743impl ScrollbarMarkerState {
  744    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  745        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  746    }
  747}
  748
  749#[derive(Clone, Copy, PartialEq, Eq)]
  750pub enum MinimapVisibility {
  751    Disabled,
  752    Enabled {
  753        /// The configuration currently present in the users settings.
  754        setting_configuration: bool,
  755        /// Whether to override the currently set visibility from the users setting.
  756        toggle_override: bool,
  757    },
  758}
  759
  760impl MinimapVisibility {
  761    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  762        if mode.is_full() {
  763            Self::Enabled {
  764                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  765                toggle_override: false,
  766            }
  767        } else {
  768            Self::Disabled
  769        }
  770    }
  771
  772    fn hidden(&self) -> Self {
  773        match *self {
  774            Self::Enabled {
  775                setting_configuration,
  776                ..
  777            } => Self::Enabled {
  778                setting_configuration,
  779                toggle_override: setting_configuration,
  780            },
  781            Self::Disabled => Self::Disabled,
  782        }
  783    }
  784
  785    fn disabled(&self) -> bool {
  786        matches!(*self, Self::Disabled)
  787    }
  788
  789    fn settings_visibility(&self) -> bool {
  790        match *self {
  791            Self::Enabled {
  792                setting_configuration,
  793                ..
  794            } => setting_configuration,
  795            _ => false,
  796        }
  797    }
  798
  799    fn visible(&self) -> bool {
  800        match *self {
  801            Self::Enabled {
  802                setting_configuration,
  803                toggle_override,
  804            } => setting_configuration ^ toggle_override,
  805            _ => false,
  806        }
  807    }
  808
  809    fn toggle_visibility(&self) -> Self {
  810        match *self {
  811            Self::Enabled {
  812                toggle_override,
  813                setting_configuration,
  814            } => Self::Enabled {
  815                setting_configuration,
  816                toggle_override: !toggle_override,
  817            },
  818            Self::Disabled => Self::Disabled,
  819        }
  820    }
  821}
  822
  823#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  824pub enum BufferSerialization {
  825    All,
  826    NonDirtyBuffers,
  827}
  828
  829impl BufferSerialization {
  830    fn new(restore_unsaved_buffers: bool) -> Self {
  831        if restore_unsaved_buffers {
  832            Self::All
  833        } else {
  834            Self::NonDirtyBuffers
  835        }
  836    }
  837}
  838
  839#[derive(Clone, Debug)]
  840struct RunnableTasks {
  841    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  842    offset: multi_buffer::Anchor,
  843    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  844    column: u32,
  845    // Values of all named captures, including those starting with '_'
  846    extra_variables: HashMap<String, String>,
  847    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  848    context_range: Range<BufferOffset>,
  849}
  850
  851impl RunnableTasks {
  852    fn resolve<'a>(
  853        &'a self,
  854        cx: &'a task::TaskContext,
  855    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  856        self.templates.iter().filter_map(|(kind, template)| {
  857            template
  858                .resolve_task(&kind.to_id_base(), cx)
  859                .map(|task| (kind.clone(), task))
  860        })
  861    }
  862}
  863
  864#[derive(Clone)]
  865pub struct ResolvedTasks {
  866    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  867    position: Anchor,
  868}
  869
  870/// Addons allow storing per-editor state in other crates (e.g. Vim)
  871pub trait Addon: 'static {
  872    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  873
  874    fn render_buffer_header_controls(
  875        &self,
  876        _: &ExcerptInfo,
  877        _: &Window,
  878        _: &App,
  879    ) -> Option<AnyElement> {
  880        None
  881    }
  882
  883    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  884        None
  885    }
  886
  887    fn to_any(&self) -> &dyn std::any::Any;
  888
  889    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  890        None
  891    }
  892}
  893
  894struct ChangeLocation {
  895    current: Option<Vec<Anchor>>,
  896    original: Vec<Anchor>,
  897}
  898impl ChangeLocation {
  899    fn locations(&self) -> &[Anchor] {
  900        self.current.as_ref().unwrap_or(&self.original)
  901    }
  902}
  903
  904/// A set of caret positions, registered when the editor was edited.
  905pub struct ChangeList {
  906    changes: Vec<ChangeLocation>,
  907    /// Currently "selected" change.
  908    position: Option<usize>,
  909}
  910
  911impl ChangeList {
  912    pub fn new() -> Self {
  913        Self {
  914            changes: Vec::new(),
  915            position: None,
  916        }
  917    }
  918
  919    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  920    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  921    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  922        if self.changes.is_empty() {
  923            return None;
  924        }
  925
  926        let prev = self.position.unwrap_or(self.changes.len());
  927        let next = if direction == Direction::Prev {
  928            prev.saturating_sub(count)
  929        } else {
  930            (prev + count).min(self.changes.len() - 1)
  931        };
  932        self.position = Some(next);
  933        self.changes.get(next).map(|change| change.locations())
  934    }
  935
  936    /// Adds a new change to the list, resetting the change list position.
  937    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  938        self.position.take();
  939        if let Some(last) = self.changes.last_mut()
  940            && group
  941        {
  942            last.current = Some(new_positions)
  943        } else {
  944            self.changes.push(ChangeLocation {
  945                original: new_positions,
  946                current: None,
  947            });
  948        }
  949    }
  950
  951    pub fn last(&self) -> Option<&[Anchor]> {
  952        self.changes.last().map(|change| change.locations())
  953    }
  954
  955    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  956        self.changes.last().map(|change| change.original.as_slice())
  957    }
  958
  959    pub fn invert_last_group(&mut self) {
  960        if let Some(last) = self.changes.last_mut()
  961            && let Some(current) = last.current.as_mut()
  962        {
  963            mem::swap(&mut last.original, current);
  964        }
  965    }
  966}
  967
  968#[derive(Clone)]
  969struct InlineBlamePopoverState {
  970    scroll_handle: ScrollHandle,
  971    commit_message: Option<ParsedCommitMessage>,
  972    markdown: Entity<Markdown>,
  973}
  974
  975struct InlineBlamePopover {
  976    position: gpui::Point<Pixels>,
  977    hide_task: Option<Task<()>>,
  978    popover_bounds: Option<Bounds<Pixels>>,
  979    popover_state: InlineBlamePopoverState,
  980    keyboard_grace: bool,
  981}
  982
  983enum SelectionDragState {
  984    /// State when no drag related activity is detected.
  985    None,
  986    /// State when the mouse is down on a selection that is about to be dragged.
  987    ReadyToDrag {
  988        selection: Selection<Anchor>,
  989        click_position: gpui::Point<Pixels>,
  990        mouse_down_time: Instant,
  991    },
  992    /// State when the mouse is dragging the selection in the editor.
  993    Dragging {
  994        selection: Selection<Anchor>,
  995        drop_cursor: Selection<Anchor>,
  996        hide_drop_cursor: bool,
  997    },
  998}
  999
 1000enum ColumnarSelectionState {
 1001    FromMouse {
 1002        selection_tail: Anchor,
 1003        display_point: Option<DisplayPoint>,
 1004    },
 1005    FromSelection {
 1006        selection_tail: Anchor,
 1007    },
 1008}
 1009
 1010/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1011/// a breakpoint on them.
 1012#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1013struct PhantomBreakpointIndicator {
 1014    display_row: DisplayRow,
 1015    /// There's a small debounce between hovering over the line and showing the indicator.
 1016    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1017    is_active: bool,
 1018    collides_with_existing_breakpoint: bool,
 1019}
 1020
 1021/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1022///
 1023/// See the [module level documentation](self) for more information.
 1024pub struct Editor {
 1025    focus_handle: FocusHandle,
 1026    last_focused_descendant: Option<WeakFocusHandle>,
 1027    /// The text buffer being edited
 1028    buffer: Entity<MultiBuffer>,
 1029    /// Map of how text in the buffer should be displayed.
 1030    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1031    pub display_map: Entity<DisplayMap>,
 1032    placeholder_display_map: Option<Entity<DisplayMap>>,
 1033    pub selections: SelectionsCollection,
 1034    pub scroll_manager: ScrollManager,
 1035    /// When inline assist editors are linked, they all render cursors because
 1036    /// typing enters text into each of them, even the ones that aren't focused.
 1037    pub(crate) show_cursor_when_unfocused: bool,
 1038    columnar_selection_state: Option<ColumnarSelectionState>,
 1039    add_selections_state: Option<AddSelectionsState>,
 1040    select_next_state: Option<SelectNextState>,
 1041    select_prev_state: Option<SelectNextState>,
 1042    selection_history: SelectionHistory,
 1043    defer_selection_effects: bool,
 1044    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1045    autoclose_regions: Vec<AutocloseRegion>,
 1046    snippet_stack: InvalidationStack<SnippetState>,
 1047    select_syntax_node_history: SelectSyntaxNodeHistory,
 1048    ime_transaction: Option<TransactionId>,
 1049    pub diagnostics_max_severity: DiagnosticSeverity,
 1050    active_diagnostics: ActiveDiagnostic,
 1051    show_inline_diagnostics: bool,
 1052    inline_diagnostics_update: Task<()>,
 1053    inline_diagnostics_enabled: bool,
 1054    diagnostics_enabled: bool,
 1055    word_completions_enabled: bool,
 1056    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1057    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1058    hard_wrap: Option<usize>,
 1059    project: Option<Entity<Project>>,
 1060    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1061    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1062    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1063    blink_manager: Entity<BlinkManager>,
 1064    show_cursor_names: bool,
 1065    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1066    pub show_local_selections: bool,
 1067    mode: EditorMode,
 1068    show_breadcrumbs: bool,
 1069    show_gutter: bool,
 1070    show_scrollbars: ScrollbarAxes,
 1071    minimap_visibility: MinimapVisibility,
 1072    offset_content: bool,
 1073    disable_expand_excerpt_buttons: bool,
 1074    show_line_numbers: Option<bool>,
 1075    use_relative_line_numbers: Option<bool>,
 1076    show_git_diff_gutter: Option<bool>,
 1077    show_code_actions: Option<bool>,
 1078    show_runnables: Option<bool>,
 1079    show_breakpoints: Option<bool>,
 1080    show_wrap_guides: Option<bool>,
 1081    show_indent_guides: Option<bool>,
 1082    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1083    highlight_order: usize,
 1084    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1085    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1086    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1087    scrollbar_marker_state: ScrollbarMarkerState,
 1088    active_indent_guides_state: ActiveIndentGuidesState,
 1089    nav_history: Option<ItemNavHistory>,
 1090    context_menu: RefCell<Option<CodeContextMenu>>,
 1091    context_menu_options: Option<ContextMenuOptions>,
 1092    mouse_context_menu: Option<MouseContextMenu>,
 1093    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1094    inline_blame_popover: Option<InlineBlamePopover>,
 1095    inline_blame_popover_show_task: Option<Task<()>>,
 1096    signature_help_state: SignatureHelpState,
 1097    auto_signature_help: Option<bool>,
 1098    find_all_references_task_sources: Vec<Anchor>,
 1099    next_completion_id: CompletionId,
 1100    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1101    code_actions_task: Option<Task<Result<()>>>,
 1102    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1103    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1104    document_highlights_task: Option<Task<()>>,
 1105    linked_editing_range_task: Option<Task<Option<()>>>,
 1106    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1107    pending_rename: Option<RenameState>,
 1108    searchable: bool,
 1109    cursor_shape: CursorShape,
 1110    current_line_highlight: Option<CurrentLineHighlight>,
 1111    pub collapse_matches: bool,
 1112    autoindent_mode: Option<AutoindentMode>,
 1113    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1114    input_enabled: bool,
 1115    use_modal_editing: bool,
 1116    read_only: bool,
 1117    leader_id: Option<CollaboratorId>,
 1118    remote_id: Option<ViewId>,
 1119    pub hover_state: HoverState,
 1120    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1121    gutter_hovered: bool,
 1122    hovered_link_state: Option<HoveredLinkState>,
 1123    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1124    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1125    active_edit_prediction: Option<EditPredictionState>,
 1126    /// Used to prevent flickering as the user types while the menu is open
 1127    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1128    edit_prediction_settings: EditPredictionSettings,
 1129    edit_predictions_hidden_for_vim_mode: bool,
 1130    show_edit_predictions_override: Option<bool>,
 1131    show_completions_on_input_override: Option<bool>,
 1132    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1133    edit_prediction_preview: EditPredictionPreview,
 1134    edit_prediction_indent_conflict: bool,
 1135    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1136    next_inlay_id: usize,
 1137    next_color_inlay_id: usize,
 1138    _subscriptions: Vec<Subscription>,
 1139    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1140    gutter_dimensions: GutterDimensions,
 1141    style: Option<EditorStyle>,
 1142    text_style_refinement: Option<TextStyleRefinement>,
 1143    next_editor_action_id: EditorActionId,
 1144    editor_actions: Rc<
 1145        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1146    >,
 1147    use_autoclose: bool,
 1148    use_auto_surround: bool,
 1149    auto_replace_emoji_shortcode: bool,
 1150    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1151    show_git_blame_gutter: bool,
 1152    show_git_blame_inline: bool,
 1153    show_git_blame_inline_delay_task: Option<Task<()>>,
 1154    git_blame_inline_enabled: bool,
 1155    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1156    buffer_serialization: Option<BufferSerialization>,
 1157    show_selection_menu: Option<bool>,
 1158    blame: Option<Entity<GitBlame>>,
 1159    blame_subscription: Option<Subscription>,
 1160    custom_context_menu: Option<
 1161        Box<
 1162            dyn 'static
 1163                + Fn(
 1164                    &mut Self,
 1165                    DisplayPoint,
 1166                    &mut Window,
 1167                    &mut Context<Self>,
 1168                ) -> Option<Entity<ui::ContextMenu>>,
 1169        >,
 1170    >,
 1171    last_bounds: Option<Bounds<Pixels>>,
 1172    last_position_map: Option<Rc<PositionMap>>,
 1173    expect_bounds_change: Option<Bounds<Pixels>>,
 1174    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1175    tasks_update_task: Option<Task<()>>,
 1176    breakpoint_store: Option<Entity<BreakpointStore>>,
 1177    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1178    hovered_diff_hunk_row: Option<DisplayRow>,
 1179    pull_diagnostics_task: Task<()>,
 1180    pull_diagnostics_background_task: Task<()>,
 1181    in_project_search: bool,
 1182    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1183    breadcrumb_header: Option<String>,
 1184    focused_block: Option<FocusedBlock>,
 1185    next_scroll_position: NextScrollCursorCenterTopBottom,
 1186    addons: HashMap<TypeId, Box<dyn Addon>>,
 1187    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1188    load_diff_task: Option<Shared<Task<()>>>,
 1189    /// Whether we are temporarily displaying a diff other than git's
 1190    temporary_diff_override: bool,
 1191    selection_mark_mode: bool,
 1192    toggle_fold_multiple_buffers: Task<()>,
 1193    _scroll_cursor_center_top_bottom_task: Task<()>,
 1194    serialize_selections: Task<()>,
 1195    serialize_folds: Task<()>,
 1196    mouse_cursor_hidden: bool,
 1197    minimap: Option<Entity<Self>>,
 1198    hide_mouse_mode: HideMouseMode,
 1199    pub change_list: ChangeList,
 1200    inline_value_cache: InlineValueCache,
 1201
 1202    selection_drag_state: SelectionDragState,
 1203    colors: Option<LspColorData>,
 1204    post_scroll_update: Task<()>,
 1205    refresh_colors_task: Task<()>,
 1206    inlay_hints: Option<LspInlayHintData>,
 1207    folding_newlines: Task<()>,
 1208    select_next_is_case_sensitive: Option<bool>,
 1209    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1210    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1211    accent_data: Option<AccentData>,
 1212    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1213    use_base_text_line_numbers: bool,
 1214}
 1215
 1216#[derive(Debug, PartialEq)]
 1217struct AccentData {
 1218    colors: AccentColors,
 1219    overrides: Vec<SharedString>,
 1220}
 1221
 1222fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1223    if debounce_ms > 0 {
 1224        Some(Duration::from_millis(debounce_ms))
 1225    } else {
 1226        None
 1227    }
 1228}
 1229
 1230#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1231enum NextScrollCursorCenterTopBottom {
 1232    #[default]
 1233    Center,
 1234    Top,
 1235    Bottom,
 1236}
 1237
 1238impl NextScrollCursorCenterTopBottom {
 1239    fn next(&self) -> Self {
 1240        match self {
 1241            Self::Center => Self::Top,
 1242            Self::Top => Self::Bottom,
 1243            Self::Bottom => Self::Center,
 1244        }
 1245    }
 1246}
 1247
 1248#[derive(Clone)]
 1249pub struct EditorSnapshot {
 1250    pub mode: EditorMode,
 1251    show_gutter: bool,
 1252    offset_content: bool,
 1253    show_line_numbers: Option<bool>,
 1254    show_git_diff_gutter: Option<bool>,
 1255    show_code_actions: Option<bool>,
 1256    show_runnables: Option<bool>,
 1257    show_breakpoints: Option<bool>,
 1258    git_blame_gutter_max_author_length: Option<usize>,
 1259    pub display_snapshot: DisplaySnapshot,
 1260    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1261    is_focused: bool,
 1262    scroll_anchor: ScrollAnchor,
 1263    ongoing_scroll: OngoingScroll,
 1264    current_line_highlight: CurrentLineHighlight,
 1265    gutter_hovered: bool,
 1266}
 1267
 1268#[derive(Default, Debug, Clone, Copy)]
 1269pub struct GutterDimensions {
 1270    pub left_padding: Pixels,
 1271    pub right_padding: Pixels,
 1272    pub width: Pixels,
 1273    pub margin: Pixels,
 1274    pub git_blame_entries_width: Option<Pixels>,
 1275}
 1276
 1277impl GutterDimensions {
 1278    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1279        Self {
 1280            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1281            ..Default::default()
 1282        }
 1283    }
 1284
 1285    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1286        -cx.text_system().descent(font_id, font_size)
 1287    }
 1288    /// The full width of the space taken up by the gutter.
 1289    pub fn full_width(&self) -> Pixels {
 1290        self.margin + self.width
 1291    }
 1292
 1293    /// The width of the space reserved for the fold indicators,
 1294    /// use alongside 'justify_end' and `gutter_width` to
 1295    /// right align content with the line numbers
 1296    pub fn fold_area_width(&self) -> Pixels {
 1297        self.margin + self.right_padding
 1298    }
 1299}
 1300
 1301struct CharacterDimensions {
 1302    em_width: Pixels,
 1303    em_advance: Pixels,
 1304    line_height: Pixels,
 1305}
 1306
 1307#[derive(Debug)]
 1308pub struct RemoteSelection {
 1309    pub replica_id: ReplicaId,
 1310    pub selection: Selection<Anchor>,
 1311    pub cursor_shape: CursorShape,
 1312    pub collaborator_id: CollaboratorId,
 1313    pub line_mode: bool,
 1314    pub user_name: Option<SharedString>,
 1315    pub color: PlayerColor,
 1316}
 1317
 1318#[derive(Clone, Debug)]
 1319struct SelectionHistoryEntry {
 1320    selections: Arc<[Selection<Anchor>]>,
 1321    select_next_state: Option<SelectNextState>,
 1322    select_prev_state: Option<SelectNextState>,
 1323    add_selections_state: Option<AddSelectionsState>,
 1324}
 1325
 1326#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1327enum SelectionHistoryMode {
 1328    #[default]
 1329    Normal,
 1330    Undoing,
 1331    Redoing,
 1332    Skipping,
 1333}
 1334
 1335#[derive(Clone, PartialEq, Eq, Hash)]
 1336struct HoveredCursor {
 1337    replica_id: ReplicaId,
 1338    selection_id: usize,
 1339}
 1340
 1341#[derive(Debug)]
 1342/// SelectionEffects controls the side-effects of updating the selection.
 1343///
 1344/// The default behaviour does "what you mostly want":
 1345/// - it pushes to the nav history if the cursor moved by >10 lines
 1346/// - it re-triggers completion requests
 1347/// - it scrolls to fit
 1348///
 1349/// You might want to modify these behaviours. For example when doing a "jump"
 1350/// like go to definition, we always want to add to nav history; but when scrolling
 1351/// in vim mode we never do.
 1352///
 1353/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1354/// move.
 1355#[derive(Clone)]
 1356pub struct SelectionEffects {
 1357    nav_history: Option<bool>,
 1358    completions: bool,
 1359    scroll: Option<Autoscroll>,
 1360}
 1361
 1362impl Default for SelectionEffects {
 1363    fn default() -> Self {
 1364        Self {
 1365            nav_history: None,
 1366            completions: true,
 1367            scroll: Some(Autoscroll::fit()),
 1368        }
 1369    }
 1370}
 1371impl SelectionEffects {
 1372    pub fn scroll(scroll: Autoscroll) -> Self {
 1373        Self {
 1374            scroll: Some(scroll),
 1375            ..Default::default()
 1376        }
 1377    }
 1378
 1379    pub fn no_scroll() -> Self {
 1380        Self {
 1381            scroll: None,
 1382            ..Default::default()
 1383        }
 1384    }
 1385
 1386    pub fn completions(self, completions: bool) -> Self {
 1387        Self {
 1388            completions,
 1389            ..self
 1390        }
 1391    }
 1392
 1393    pub fn nav_history(self, nav_history: bool) -> Self {
 1394        Self {
 1395            nav_history: Some(nav_history),
 1396            ..self
 1397        }
 1398    }
 1399}
 1400
 1401struct DeferredSelectionEffectsState {
 1402    changed: bool,
 1403    effects: SelectionEffects,
 1404    old_cursor_position: Anchor,
 1405    history_entry: SelectionHistoryEntry,
 1406}
 1407
 1408#[derive(Default)]
 1409struct SelectionHistory {
 1410    #[allow(clippy::type_complexity)]
 1411    selections_by_transaction:
 1412        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1413    mode: SelectionHistoryMode,
 1414    undo_stack: VecDeque<SelectionHistoryEntry>,
 1415    redo_stack: VecDeque<SelectionHistoryEntry>,
 1416}
 1417
 1418impl SelectionHistory {
 1419    #[track_caller]
 1420    fn insert_transaction(
 1421        &mut self,
 1422        transaction_id: TransactionId,
 1423        selections: Arc<[Selection<Anchor>]>,
 1424    ) {
 1425        if selections.is_empty() {
 1426            log::error!(
 1427                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1428                std::panic::Location::caller()
 1429            );
 1430            return;
 1431        }
 1432        self.selections_by_transaction
 1433            .insert(transaction_id, (selections, None));
 1434    }
 1435
 1436    #[allow(clippy::type_complexity)]
 1437    fn transaction(
 1438        &self,
 1439        transaction_id: TransactionId,
 1440    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1441        self.selections_by_transaction.get(&transaction_id)
 1442    }
 1443
 1444    #[allow(clippy::type_complexity)]
 1445    fn transaction_mut(
 1446        &mut self,
 1447        transaction_id: TransactionId,
 1448    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1449        self.selections_by_transaction.get_mut(&transaction_id)
 1450    }
 1451
 1452    fn push(&mut self, entry: SelectionHistoryEntry) {
 1453        if !entry.selections.is_empty() {
 1454            match self.mode {
 1455                SelectionHistoryMode::Normal => {
 1456                    self.push_undo(entry);
 1457                    self.redo_stack.clear();
 1458                }
 1459                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1460                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1461                SelectionHistoryMode::Skipping => {}
 1462            }
 1463        }
 1464    }
 1465
 1466    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1467        if self
 1468            .undo_stack
 1469            .back()
 1470            .is_none_or(|e| e.selections != entry.selections)
 1471        {
 1472            self.undo_stack.push_back(entry);
 1473            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1474                self.undo_stack.pop_front();
 1475            }
 1476        }
 1477    }
 1478
 1479    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1480        if self
 1481            .redo_stack
 1482            .back()
 1483            .is_none_or(|e| e.selections != entry.selections)
 1484        {
 1485            self.redo_stack.push_back(entry);
 1486            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1487                self.redo_stack.pop_front();
 1488            }
 1489        }
 1490    }
 1491}
 1492
 1493#[derive(Clone, Copy)]
 1494pub struct RowHighlightOptions {
 1495    pub autoscroll: bool,
 1496    pub include_gutter: bool,
 1497}
 1498
 1499impl Default for RowHighlightOptions {
 1500    fn default() -> Self {
 1501        Self {
 1502            autoscroll: Default::default(),
 1503            include_gutter: true,
 1504        }
 1505    }
 1506}
 1507
 1508struct RowHighlight {
 1509    index: usize,
 1510    range: Range<Anchor>,
 1511    color: Hsla,
 1512    options: RowHighlightOptions,
 1513    type_id: TypeId,
 1514}
 1515
 1516#[derive(Clone, Debug)]
 1517struct AddSelectionsState {
 1518    groups: Vec<AddSelectionsGroup>,
 1519}
 1520
 1521#[derive(Clone, Debug)]
 1522struct AddSelectionsGroup {
 1523    above: bool,
 1524    stack: Vec<usize>,
 1525}
 1526
 1527#[derive(Clone)]
 1528struct SelectNextState {
 1529    query: AhoCorasick,
 1530    wordwise: bool,
 1531    done: bool,
 1532}
 1533
 1534impl std::fmt::Debug for SelectNextState {
 1535    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1536        f.debug_struct(std::any::type_name::<Self>())
 1537            .field("wordwise", &self.wordwise)
 1538            .field("done", &self.done)
 1539            .finish()
 1540    }
 1541}
 1542
 1543#[derive(Debug)]
 1544struct AutocloseRegion {
 1545    selection_id: usize,
 1546    range: Range<Anchor>,
 1547    pair: BracketPair,
 1548}
 1549
 1550#[derive(Debug)]
 1551struct SnippetState {
 1552    ranges: Vec<Vec<Range<Anchor>>>,
 1553    active_index: usize,
 1554    choices: Vec<Option<Vec<String>>>,
 1555}
 1556
 1557#[doc(hidden)]
 1558pub struct RenameState {
 1559    pub range: Range<Anchor>,
 1560    pub old_name: Arc<str>,
 1561    pub editor: Entity<Editor>,
 1562    block_id: CustomBlockId,
 1563}
 1564
 1565struct InvalidationStack<T>(Vec<T>);
 1566
 1567struct RegisteredEditPredictionDelegate {
 1568    provider: Arc<dyn EditPredictionDelegateHandle>,
 1569    _subscription: Subscription,
 1570}
 1571
 1572#[derive(Debug, PartialEq, Eq)]
 1573pub struct ActiveDiagnosticGroup {
 1574    pub active_range: Range<Anchor>,
 1575    pub active_message: String,
 1576    pub group_id: usize,
 1577    pub blocks: HashSet<CustomBlockId>,
 1578}
 1579
 1580#[derive(Debug, PartialEq, Eq)]
 1581
 1582pub(crate) enum ActiveDiagnostic {
 1583    None,
 1584    All,
 1585    Group(ActiveDiagnosticGroup),
 1586}
 1587
 1588#[derive(Serialize, Deserialize, Clone, Debug)]
 1589pub struct ClipboardSelection {
 1590    /// The number of bytes in this selection.
 1591    pub len: usize,
 1592    /// Whether this was a full-line selection.
 1593    pub is_entire_line: bool,
 1594    /// The indentation of the first line when this content was originally copied.
 1595    pub first_line_indent: u32,
 1596    #[serde(default)]
 1597    pub file_path: Option<PathBuf>,
 1598    #[serde(default)]
 1599    pub line_range: Option<RangeInclusive<u32>>,
 1600}
 1601
 1602impl ClipboardSelection {
 1603    pub fn for_buffer(
 1604        len: usize,
 1605        is_entire_line: bool,
 1606        range: Range<Point>,
 1607        buffer: &MultiBufferSnapshot,
 1608        project: Option<&Entity<Project>>,
 1609        cx: &App,
 1610    ) -> Self {
 1611        let first_line_indent = buffer
 1612            .indent_size_for_line(MultiBufferRow(range.start.row))
 1613            .len;
 1614
 1615        let file_path = util::maybe!({
 1616            let project = project?.read(cx);
 1617            let file = buffer.file_at(range.start)?;
 1618            let project_path = ProjectPath {
 1619                worktree_id: file.worktree_id(cx),
 1620                path: file.path().clone(),
 1621            };
 1622            project.absolute_path(&project_path, cx)
 1623        });
 1624
 1625        let line_range = file_path.as_ref().map(|_| range.start.row..=range.end.row);
 1626
 1627        Self {
 1628            len,
 1629            is_entire_line,
 1630            first_line_indent,
 1631            file_path,
 1632            line_range,
 1633        }
 1634    }
 1635}
 1636
 1637// selections, scroll behavior, was newest selection reversed
 1638type SelectSyntaxNodeHistoryState = (
 1639    Box<[Selection<MultiBufferOffset>]>,
 1640    SelectSyntaxNodeScrollBehavior,
 1641    bool,
 1642);
 1643
 1644#[derive(Default)]
 1645struct SelectSyntaxNodeHistory {
 1646    stack: Vec<SelectSyntaxNodeHistoryState>,
 1647    // disable temporarily to allow changing selections without losing the stack
 1648    pub disable_clearing: bool,
 1649}
 1650
 1651impl SelectSyntaxNodeHistory {
 1652    pub fn try_clear(&mut self) {
 1653        if !self.disable_clearing {
 1654            self.stack.clear();
 1655        }
 1656    }
 1657
 1658    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1659        self.stack.push(selection);
 1660    }
 1661
 1662    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1663        self.stack.pop()
 1664    }
 1665}
 1666
 1667enum SelectSyntaxNodeScrollBehavior {
 1668    CursorTop,
 1669    FitSelection,
 1670    CursorBottom,
 1671}
 1672
 1673#[derive(Debug)]
 1674pub(crate) struct NavigationData {
 1675    cursor_anchor: Anchor,
 1676    cursor_position: Point,
 1677    scroll_anchor: ScrollAnchor,
 1678    scroll_top_row: u32,
 1679}
 1680
 1681#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1682pub enum GotoDefinitionKind {
 1683    Symbol,
 1684    Declaration,
 1685    Type,
 1686    Implementation,
 1687}
 1688
 1689pub enum FormatTarget {
 1690    Buffers(HashSet<Entity<Buffer>>),
 1691    Ranges(Vec<Range<MultiBufferPoint>>),
 1692}
 1693
 1694pub(crate) struct FocusedBlock {
 1695    id: BlockId,
 1696    focus_handle: WeakFocusHandle,
 1697}
 1698
 1699#[derive(Clone, Debug)]
 1700enum JumpData {
 1701    MultiBufferRow {
 1702        row: MultiBufferRow,
 1703        line_offset_from_top: u32,
 1704    },
 1705    MultiBufferPoint {
 1706        excerpt_id: ExcerptId,
 1707        position: Point,
 1708        anchor: text::Anchor,
 1709        line_offset_from_top: u32,
 1710    },
 1711}
 1712
 1713pub enum MultibufferSelectionMode {
 1714    First,
 1715    All,
 1716}
 1717
 1718#[derive(Clone, Copy, Debug, Default)]
 1719pub struct RewrapOptions {
 1720    pub override_language_settings: bool,
 1721    pub preserve_existing_whitespace: bool,
 1722}
 1723
 1724impl Editor {
 1725    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1726        let buffer = cx.new(|cx| Buffer::local("", cx));
 1727        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1728        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1729    }
 1730
 1731    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1732        let buffer = cx.new(|cx| Buffer::local("", cx));
 1733        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1734        Self::new(EditorMode::full(), buffer, None, window, cx)
 1735    }
 1736
 1737    pub fn auto_height(
 1738        min_lines: usize,
 1739        max_lines: usize,
 1740        window: &mut Window,
 1741        cx: &mut Context<Self>,
 1742    ) -> Self {
 1743        let buffer = cx.new(|cx| Buffer::local("", cx));
 1744        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1745        Self::new(
 1746            EditorMode::AutoHeight {
 1747                min_lines,
 1748                max_lines: Some(max_lines),
 1749            },
 1750            buffer,
 1751            None,
 1752            window,
 1753            cx,
 1754        )
 1755    }
 1756
 1757    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1758    /// The editor grows as tall as needed to fit its content.
 1759    pub fn auto_height_unbounded(
 1760        min_lines: usize,
 1761        window: &mut Window,
 1762        cx: &mut Context<Self>,
 1763    ) -> Self {
 1764        let buffer = cx.new(|cx| Buffer::local("", cx));
 1765        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1766        Self::new(
 1767            EditorMode::AutoHeight {
 1768                min_lines,
 1769                max_lines: None,
 1770            },
 1771            buffer,
 1772            None,
 1773            window,
 1774            cx,
 1775        )
 1776    }
 1777
 1778    pub fn for_buffer(
 1779        buffer: Entity<Buffer>,
 1780        project: Option<Entity<Project>>,
 1781        window: &mut Window,
 1782        cx: &mut Context<Self>,
 1783    ) -> Self {
 1784        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1785        Self::new(EditorMode::full(), buffer, project, window, cx)
 1786    }
 1787
 1788    pub fn for_multibuffer(
 1789        buffer: Entity<MultiBuffer>,
 1790        project: Option<Entity<Project>>,
 1791        window: &mut Window,
 1792        cx: &mut Context<Self>,
 1793    ) -> Self {
 1794        Self::new(EditorMode::full(), buffer, project, window, cx)
 1795    }
 1796
 1797    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1798        let mut clone = Self::new(
 1799            self.mode.clone(),
 1800            self.buffer.clone(),
 1801            self.project.clone(),
 1802            window,
 1803            cx,
 1804        );
 1805        self.display_map.update(cx, |display_map, cx| {
 1806            let snapshot = display_map.snapshot(cx);
 1807            clone.display_map.update(cx, |display_map, cx| {
 1808                display_map.set_state(&snapshot, cx);
 1809            });
 1810        });
 1811        clone.folds_did_change(cx);
 1812        clone.selections.clone_state(&self.selections);
 1813        clone.scroll_manager.clone_state(&self.scroll_manager);
 1814        clone.searchable = self.searchable;
 1815        clone.read_only = self.read_only;
 1816        clone
 1817    }
 1818
 1819    pub fn new(
 1820        mode: EditorMode,
 1821        buffer: Entity<MultiBuffer>,
 1822        project: Option<Entity<Project>>,
 1823        window: &mut Window,
 1824        cx: &mut Context<Self>,
 1825    ) -> Self {
 1826        Editor::new_internal(mode, buffer, project, None, window, cx)
 1827    }
 1828
 1829    pub fn sticky_headers(
 1830        &self,
 1831        style: &EditorStyle,
 1832        cx: &App,
 1833    ) -> Option<Vec<OutlineItem<Anchor>>> {
 1834        let multi_buffer = self.buffer().read(cx);
 1835        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1836        let multi_buffer_visible_start = self
 1837            .scroll_manager
 1838            .anchor()
 1839            .anchor
 1840            .to_point(&multi_buffer_snapshot);
 1841        let max_row = multi_buffer_snapshot.max_point().row;
 1842
 1843        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1844        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1845
 1846        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1847            let outline_items = buffer
 1848                .outline_items_containing(
 1849                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1850                    true,
 1851                    Some(style.syntax.as_ref()),
 1852                )
 1853                .into_iter()
 1854                .map(|outline_item| OutlineItem {
 1855                    depth: outline_item.depth,
 1856                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1857                    source_range_for_text: Anchor::range_in_buffer(
 1858                        *excerpt_id,
 1859                        outline_item.source_range_for_text,
 1860                    ),
 1861                    text: outline_item.text,
 1862                    highlight_ranges: outline_item.highlight_ranges,
 1863                    name_ranges: outline_item.name_ranges,
 1864                    body_range: outline_item
 1865                        .body_range
 1866                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1867                    annotation_range: outline_item
 1868                        .annotation_range
 1869                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1870                });
 1871            return Some(outline_items.collect());
 1872        }
 1873
 1874        None
 1875    }
 1876
 1877    fn new_internal(
 1878        mode: EditorMode,
 1879        multi_buffer: Entity<MultiBuffer>,
 1880        project: Option<Entity<Project>>,
 1881        display_map: Option<Entity<DisplayMap>>,
 1882        window: &mut Window,
 1883        cx: &mut Context<Self>,
 1884    ) -> Self {
 1885        debug_assert!(
 1886            display_map.is_none() || mode.is_minimap(),
 1887            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1888        );
 1889
 1890        let full_mode = mode.is_full();
 1891        let is_minimap = mode.is_minimap();
 1892        let diagnostics_max_severity = if full_mode {
 1893            EditorSettings::get_global(cx)
 1894                .diagnostics_max_severity
 1895                .unwrap_or(DiagnosticSeverity::Hint)
 1896        } else {
 1897            DiagnosticSeverity::Off
 1898        };
 1899        let style = window.text_style();
 1900        let font_size = style.font_size.to_pixels(window.rem_size());
 1901        let editor = cx.entity().downgrade();
 1902        let fold_placeholder = FoldPlaceholder {
 1903            constrain_width: false,
 1904            render: Arc::new(move |fold_id, fold_range, cx| {
 1905                let editor = editor.clone();
 1906                div()
 1907                    .id(fold_id)
 1908                    .bg(cx.theme().colors().ghost_element_background)
 1909                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1910                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1911                    .rounded_xs()
 1912                    .size_full()
 1913                    .cursor_pointer()
 1914                    .child("")
 1915                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1916                    .on_click(move |_, _window, cx| {
 1917                        editor
 1918                            .update(cx, |editor, cx| {
 1919                                editor.unfold_ranges(
 1920                                    &[fold_range.start..fold_range.end],
 1921                                    true,
 1922                                    false,
 1923                                    cx,
 1924                                );
 1925                                cx.stop_propagation();
 1926                            })
 1927                            .ok();
 1928                    })
 1929                    .into_any()
 1930            }),
 1931            merge_adjacent: true,
 1932            ..FoldPlaceholder::default()
 1933        };
 1934        let display_map = display_map.unwrap_or_else(|| {
 1935            cx.new(|cx| {
 1936                DisplayMap::new(
 1937                    multi_buffer.clone(),
 1938                    style.font(),
 1939                    font_size,
 1940                    None,
 1941                    FILE_HEADER_HEIGHT,
 1942                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1943                    fold_placeholder,
 1944                    diagnostics_max_severity,
 1945                    cx,
 1946                )
 1947            })
 1948        });
 1949
 1950        let selections = SelectionsCollection::new();
 1951
 1952        let blink_manager = cx.new(|cx| {
 1953            let mut blink_manager = BlinkManager::new(
 1954                CURSOR_BLINK_INTERVAL,
 1955                |cx| EditorSettings::get_global(cx).cursor_blink,
 1956                cx,
 1957            );
 1958            if is_minimap {
 1959                blink_manager.disable(cx);
 1960            }
 1961            blink_manager
 1962        });
 1963
 1964        let soft_wrap_mode_override =
 1965            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1966
 1967        let mut project_subscriptions = Vec::new();
 1968        if full_mode && let Some(project) = project.as_ref() {
 1969            project_subscriptions.push(cx.subscribe_in(
 1970                project,
 1971                window,
 1972                |editor, _, event, window, cx| match event {
 1973                    project::Event::RefreshCodeLens => {
 1974                        // we always query lens with actions, without storing them, always refreshing them
 1975                    }
 1976                    project::Event::RefreshInlayHints {
 1977                        server_id,
 1978                        request_id,
 1979                    } => {
 1980                        editor.refresh_inlay_hints(
 1981                            InlayHintRefreshReason::RefreshRequested {
 1982                                server_id: *server_id,
 1983                                request_id: *request_id,
 1984                            },
 1985                            cx,
 1986                        );
 1987                    }
 1988                    project::Event::LanguageServerRemoved(..) => {
 1989                        if editor.tasks_update_task.is_none() {
 1990                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1991                        }
 1992                        editor.registered_buffers.clear();
 1993                        editor.register_visible_buffers(cx);
 1994                    }
 1995                    project::Event::LanguageServerAdded(..) => {
 1996                        if editor.tasks_update_task.is_none() {
 1997                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1998                        }
 1999                    }
 2000                    project::Event::SnippetEdit(id, snippet_edits) => {
 2001                        // todo(lw): Non singletons
 2002                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2003                            let snapshot = buffer.read(cx).snapshot();
 2004                            let focus_handle = editor.focus_handle(cx);
 2005                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2006                                for (range, snippet) in snippet_edits {
 2007                                    let buffer_range =
 2008                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2009                                    editor
 2010                                        .insert_snippet(
 2011                                            &[MultiBufferOffset(buffer_range.start)
 2012                                                ..MultiBufferOffset(buffer_range.end)],
 2013                                            snippet.clone(),
 2014                                            window,
 2015                                            cx,
 2016                                        )
 2017                                        .ok();
 2018                                }
 2019                            }
 2020                        }
 2021                    }
 2022                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2023                        let buffer_id = *buffer_id;
 2024                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2025                            editor.register_buffer(buffer_id, cx);
 2026                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2027                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2028                            refresh_linked_ranges(editor, window, cx);
 2029                            editor.refresh_code_actions(window, cx);
 2030                            editor.refresh_document_highlights(cx);
 2031                        }
 2032                    }
 2033
 2034                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2035                        let Some(workspace) = editor.workspace() else {
 2036                            return;
 2037                        };
 2038                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2039                        else {
 2040                            return;
 2041                        };
 2042
 2043                        if active_editor.entity_id() == cx.entity_id() {
 2044                            let entity_id = cx.entity_id();
 2045                            workspace.update(cx, |this, cx| {
 2046                                this.panes_mut()
 2047                                    .iter_mut()
 2048                                    .filter(|pane| pane.entity_id() != entity_id)
 2049                                    .for_each(|p| {
 2050                                        p.update(cx, |pane, _| {
 2051                                            pane.nav_history_mut().rename_item(
 2052                                                entity_id,
 2053                                                project_path.clone(),
 2054                                                abs_path.clone().into(),
 2055                                            );
 2056                                        })
 2057                                    });
 2058                            });
 2059                            let edited_buffers_already_open = {
 2060                                let other_editors: Vec<Entity<Editor>> = workspace
 2061                                    .read(cx)
 2062                                    .panes()
 2063                                    .iter()
 2064                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 2065                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 2066                                    .collect();
 2067
 2068                                transaction.0.keys().all(|buffer| {
 2069                                    other_editors.iter().any(|editor| {
 2070                                        let multi_buffer = editor.read(cx).buffer();
 2071                                        multi_buffer.read(cx).is_singleton()
 2072                                            && multi_buffer.read(cx).as_singleton().map_or(
 2073                                                false,
 2074                                                |singleton| {
 2075                                                    singleton.entity_id() == buffer.entity_id()
 2076                                                },
 2077                                            )
 2078                                    })
 2079                                })
 2080                            };
 2081                            if !edited_buffers_already_open {
 2082                                let workspace = workspace.downgrade();
 2083                                let transaction = transaction.clone();
 2084                                cx.defer_in(window, move |_, window, cx| {
 2085                                    cx.spawn_in(window, async move |editor, cx| {
 2086                                        Self::open_project_transaction(
 2087                                            &editor,
 2088                                            workspace,
 2089                                            transaction,
 2090                                            "Rename".to_string(),
 2091                                            cx,
 2092                                        )
 2093                                        .await
 2094                                        .ok()
 2095                                    })
 2096                                    .detach();
 2097                                });
 2098                            }
 2099                        }
 2100                    }
 2101
 2102                    _ => {}
 2103                },
 2104            ));
 2105            if let Some(task_inventory) = project
 2106                .read(cx)
 2107                .task_store()
 2108                .read(cx)
 2109                .task_inventory()
 2110                .cloned()
 2111            {
 2112                project_subscriptions.push(cx.observe_in(
 2113                    &task_inventory,
 2114                    window,
 2115                    |editor, _, window, cx| {
 2116                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2117                    },
 2118                ));
 2119            };
 2120
 2121            project_subscriptions.push(cx.subscribe_in(
 2122                &project.read(cx).breakpoint_store(),
 2123                window,
 2124                |editor, _, event, window, cx| match event {
 2125                    BreakpointStoreEvent::ClearDebugLines => {
 2126                        editor.clear_row_highlights::<ActiveDebugLine>();
 2127                        editor.refresh_inline_values(cx);
 2128                    }
 2129                    BreakpointStoreEvent::SetDebugLine => {
 2130                        if editor.go_to_active_debug_line(window, cx) {
 2131                            cx.stop_propagation();
 2132                        }
 2133
 2134                        editor.refresh_inline_values(cx);
 2135                    }
 2136                    _ => {}
 2137                },
 2138            ));
 2139            let git_store = project.read(cx).git_store().clone();
 2140            let project = project.clone();
 2141            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2142                if let GitStoreEvent::RepositoryAdded = event {
 2143                    this.load_diff_task = Some(
 2144                        update_uncommitted_diff_for_buffer(
 2145                            cx.entity(),
 2146                            &project,
 2147                            this.buffer.read(cx).all_buffers(),
 2148                            this.buffer.clone(),
 2149                            cx,
 2150                        )
 2151                        .shared(),
 2152                    );
 2153                }
 2154            }));
 2155        }
 2156
 2157        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2158
 2159        let inlay_hint_settings =
 2160            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2161        let focus_handle = cx.focus_handle();
 2162        if !is_minimap {
 2163            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2164                .detach();
 2165            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2166                .detach();
 2167            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2168                .detach();
 2169            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2170                .detach();
 2171            cx.observe_pending_input(window, Self::observe_pending_input)
 2172                .detach();
 2173        }
 2174
 2175        let show_indent_guides =
 2176            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2177                Some(false)
 2178            } else {
 2179                None
 2180            };
 2181
 2182        let breakpoint_store = match (&mode, project.as_ref()) {
 2183            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2184            _ => None,
 2185        };
 2186
 2187        let mut code_action_providers = Vec::new();
 2188        let mut load_uncommitted_diff = None;
 2189        if let Some(project) = project.clone() {
 2190            load_uncommitted_diff = Some(
 2191                update_uncommitted_diff_for_buffer(
 2192                    cx.entity(),
 2193                    &project,
 2194                    multi_buffer.read(cx).all_buffers(),
 2195                    multi_buffer.clone(),
 2196                    cx,
 2197                )
 2198                .shared(),
 2199            );
 2200            code_action_providers.push(Rc::new(project) as Rc<_>);
 2201        }
 2202
 2203        let mut editor = Self {
 2204            focus_handle,
 2205            show_cursor_when_unfocused: false,
 2206            last_focused_descendant: None,
 2207            buffer: multi_buffer.clone(),
 2208            display_map: display_map.clone(),
 2209            placeholder_display_map: None,
 2210            selections,
 2211            scroll_manager: ScrollManager::new(cx),
 2212            columnar_selection_state: None,
 2213            add_selections_state: None,
 2214            select_next_state: None,
 2215            select_prev_state: None,
 2216            selection_history: SelectionHistory::default(),
 2217            defer_selection_effects: false,
 2218            deferred_selection_effects_state: None,
 2219            autoclose_regions: Vec::new(),
 2220            snippet_stack: InvalidationStack::default(),
 2221            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2222            ime_transaction: None,
 2223            active_diagnostics: ActiveDiagnostic::None,
 2224            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2225            inline_diagnostics_update: Task::ready(()),
 2226            inline_diagnostics: Vec::new(),
 2227            soft_wrap_mode_override,
 2228            diagnostics_max_severity,
 2229            hard_wrap: None,
 2230            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2231            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2232            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2233            project,
 2234            blink_manager: blink_manager.clone(),
 2235            show_local_selections: true,
 2236            show_scrollbars: ScrollbarAxes {
 2237                horizontal: full_mode,
 2238                vertical: full_mode,
 2239            },
 2240            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2241            offset_content: !matches!(mode, EditorMode::SingleLine),
 2242            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2243            show_gutter: full_mode,
 2244            show_line_numbers: (!full_mode).then_some(false),
 2245            use_relative_line_numbers: None,
 2246            disable_expand_excerpt_buttons: !full_mode,
 2247            show_git_diff_gutter: None,
 2248            show_code_actions: None,
 2249            show_runnables: None,
 2250            show_breakpoints: None,
 2251            show_wrap_guides: None,
 2252            show_indent_guides,
 2253            buffers_with_disabled_indent_guides: HashSet::default(),
 2254            highlight_order: 0,
 2255            highlighted_rows: HashMap::default(),
 2256            background_highlights: HashMap::default(),
 2257            gutter_highlights: HashMap::default(),
 2258            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2259            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2260            nav_history: None,
 2261            context_menu: RefCell::new(None),
 2262            context_menu_options: None,
 2263            mouse_context_menu: None,
 2264            completion_tasks: Vec::new(),
 2265            inline_blame_popover: None,
 2266            inline_blame_popover_show_task: None,
 2267            signature_help_state: SignatureHelpState::default(),
 2268            auto_signature_help: None,
 2269            find_all_references_task_sources: Vec::new(),
 2270            next_completion_id: 0,
 2271            next_inlay_id: 0,
 2272            code_action_providers,
 2273            available_code_actions: None,
 2274            code_actions_task: None,
 2275            quick_selection_highlight_task: None,
 2276            debounced_selection_highlight_task: None,
 2277            document_highlights_task: None,
 2278            linked_editing_range_task: None,
 2279            pending_rename: None,
 2280            searchable: !is_minimap,
 2281            cursor_shape: EditorSettings::get_global(cx)
 2282                .cursor_shape
 2283                .unwrap_or_default(),
 2284            current_line_highlight: None,
 2285            autoindent_mode: Some(AutoindentMode::EachLine),
 2286            collapse_matches: false,
 2287            workspace: None,
 2288            input_enabled: !is_minimap,
 2289            use_modal_editing: full_mode,
 2290            read_only: is_minimap,
 2291            use_autoclose: true,
 2292            use_auto_surround: true,
 2293            auto_replace_emoji_shortcode: false,
 2294            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2295            leader_id: None,
 2296            remote_id: None,
 2297            hover_state: HoverState::default(),
 2298            pending_mouse_down: None,
 2299            hovered_link_state: None,
 2300            edit_prediction_provider: None,
 2301            active_edit_prediction: None,
 2302            stale_edit_prediction_in_menu: None,
 2303            edit_prediction_preview: EditPredictionPreview::Inactive {
 2304                released_too_fast: false,
 2305            },
 2306            inline_diagnostics_enabled: full_mode,
 2307            diagnostics_enabled: full_mode,
 2308            word_completions_enabled: full_mode,
 2309            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2310            gutter_hovered: false,
 2311            pixel_position_of_newest_cursor: None,
 2312            last_bounds: None,
 2313            last_position_map: None,
 2314            expect_bounds_change: None,
 2315            gutter_dimensions: GutterDimensions::default(),
 2316            style: None,
 2317            show_cursor_names: false,
 2318            hovered_cursors: HashMap::default(),
 2319            next_editor_action_id: EditorActionId::default(),
 2320            editor_actions: Rc::default(),
 2321            edit_predictions_hidden_for_vim_mode: false,
 2322            show_edit_predictions_override: None,
 2323            show_completions_on_input_override: None,
 2324            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2325            edit_prediction_settings: EditPredictionSettings::Disabled,
 2326            edit_prediction_indent_conflict: false,
 2327            edit_prediction_requires_modifier_in_indent_conflict: true,
 2328            custom_context_menu: None,
 2329            show_git_blame_gutter: false,
 2330            show_git_blame_inline: false,
 2331            show_selection_menu: None,
 2332            show_git_blame_inline_delay_task: None,
 2333            git_blame_inline_enabled: full_mode
 2334                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2335            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2336            buffer_serialization: is_minimap.not().then(|| {
 2337                BufferSerialization::new(
 2338                    ProjectSettings::get_global(cx)
 2339                        .session
 2340                        .restore_unsaved_buffers,
 2341                )
 2342            }),
 2343            blame: None,
 2344            blame_subscription: None,
 2345            tasks: BTreeMap::default(),
 2346
 2347            breakpoint_store,
 2348            gutter_breakpoint_indicator: (None, None),
 2349            hovered_diff_hunk_row: None,
 2350            _subscriptions: (!is_minimap)
 2351                .then(|| {
 2352                    vec![
 2353                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2354                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2355                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2356                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2357                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2358                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2359                        cx.observe_window_activation(window, |editor, window, cx| {
 2360                            let active = window.is_window_active();
 2361                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2362                                if active {
 2363                                    blink_manager.enable(cx);
 2364                                } else {
 2365                                    blink_manager.disable(cx);
 2366                                }
 2367                            });
 2368                            if active {
 2369                                editor.show_mouse_cursor(cx);
 2370                            }
 2371                        }),
 2372                    ]
 2373                })
 2374                .unwrap_or_default(),
 2375            tasks_update_task: None,
 2376            pull_diagnostics_task: Task::ready(()),
 2377            pull_diagnostics_background_task: Task::ready(()),
 2378            colors: None,
 2379            refresh_colors_task: Task::ready(()),
 2380            inlay_hints: None,
 2381            next_color_inlay_id: 0,
 2382            post_scroll_update: Task::ready(()),
 2383            linked_edit_ranges: Default::default(),
 2384            in_project_search: false,
 2385            previous_search_ranges: None,
 2386            breadcrumb_header: None,
 2387            focused_block: None,
 2388            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2389            addons: HashMap::default(),
 2390            registered_buffers: HashMap::default(),
 2391            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2392            selection_mark_mode: false,
 2393            toggle_fold_multiple_buffers: Task::ready(()),
 2394            serialize_selections: Task::ready(()),
 2395            serialize_folds: Task::ready(()),
 2396            text_style_refinement: None,
 2397            load_diff_task: load_uncommitted_diff,
 2398            temporary_diff_override: false,
 2399            mouse_cursor_hidden: false,
 2400            minimap: None,
 2401            hide_mouse_mode: EditorSettings::get_global(cx)
 2402                .hide_mouse
 2403                .unwrap_or_default(),
 2404            change_list: ChangeList::new(),
 2405            mode,
 2406            selection_drag_state: SelectionDragState::None,
 2407            folding_newlines: Task::ready(()),
 2408            lookup_key: None,
 2409            select_next_is_case_sensitive: None,
 2410            applicable_language_settings: HashMap::default(),
 2411            accent_data: None,
 2412            fetched_tree_sitter_chunks: HashMap::default(),
 2413            use_base_text_line_numbers: false,
 2414        };
 2415
 2416        if is_minimap {
 2417            return editor;
 2418        }
 2419
 2420        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2421        editor.accent_data = editor.fetch_accent_data(cx);
 2422
 2423        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2424            editor
 2425                ._subscriptions
 2426                .push(cx.observe(breakpoints, |_, _, cx| {
 2427                    cx.notify();
 2428                }));
 2429        }
 2430        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2431        editor._subscriptions.extend(project_subscriptions);
 2432
 2433        editor._subscriptions.push(cx.subscribe_in(
 2434            &cx.entity(),
 2435            window,
 2436            |editor, _, e: &EditorEvent, window, cx| match e {
 2437                EditorEvent::ScrollPositionChanged { local, .. } => {
 2438                    if *local {
 2439                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2440                        editor.inline_blame_popover.take();
 2441                        let new_anchor = editor.scroll_manager.anchor();
 2442                        let snapshot = editor.snapshot(window, cx);
 2443                        editor.update_restoration_data(cx, move |data| {
 2444                            data.scroll_position = (
 2445                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2446                                new_anchor.offset,
 2447                            );
 2448                        });
 2449
 2450                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2451                            cx.background_executor()
 2452                                .timer(Duration::from_millis(50))
 2453                                .await;
 2454                            editor
 2455                                .update_in(cx, |editor, window, cx| {
 2456                                    editor.register_visible_buffers(cx);
 2457                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2458                                    editor.refresh_inlay_hints(
 2459                                        InlayHintRefreshReason::NewLinesShown,
 2460                                        cx,
 2461                                    );
 2462                                    editor.colorize_brackets(false, cx);
 2463                                })
 2464                                .ok();
 2465                        });
 2466                    }
 2467                }
 2468                EditorEvent::Edited { .. } => {
 2469                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2470                        .map(|vim_mode| vim_mode.0)
 2471                        .unwrap_or(false);
 2472                    if !vim_mode {
 2473                        let display_map = editor.display_snapshot(cx);
 2474                        let selections = editor.selections.all_adjusted_display(&display_map);
 2475                        let pop_state = editor
 2476                            .change_list
 2477                            .last()
 2478                            .map(|previous| {
 2479                                previous.len() == selections.len()
 2480                                    && previous.iter().enumerate().all(|(ix, p)| {
 2481                                        p.to_display_point(&display_map).row()
 2482                                            == selections[ix].head().row()
 2483                                    })
 2484                            })
 2485                            .unwrap_or(false);
 2486                        let new_positions = selections
 2487                            .into_iter()
 2488                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2489                            .collect();
 2490                        editor
 2491                            .change_list
 2492                            .push_to_change_list(pop_state, new_positions);
 2493                    }
 2494                }
 2495                _ => (),
 2496            },
 2497        ));
 2498
 2499        if let Some(dap_store) = editor
 2500            .project
 2501            .as_ref()
 2502            .map(|project| project.read(cx).dap_store())
 2503        {
 2504            let weak_editor = cx.weak_entity();
 2505
 2506            editor
 2507                ._subscriptions
 2508                .push(
 2509                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2510                        let session_entity = cx.entity();
 2511                        weak_editor
 2512                            .update(cx, |editor, cx| {
 2513                                editor._subscriptions.push(
 2514                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2515                                );
 2516                            })
 2517                            .ok();
 2518                    }),
 2519                );
 2520
 2521            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2522                editor
 2523                    ._subscriptions
 2524                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2525            }
 2526        }
 2527
 2528        // skip adding the initial selection to selection history
 2529        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2530        editor.end_selection(window, cx);
 2531        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2532
 2533        editor.scroll_manager.show_scrollbars(window, cx);
 2534        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2535
 2536        if full_mode {
 2537            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2538            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2539
 2540            if editor.git_blame_inline_enabled {
 2541                editor.start_git_blame_inline(false, window, cx);
 2542            }
 2543
 2544            editor.go_to_active_debug_line(window, cx);
 2545
 2546            editor.minimap =
 2547                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2548            editor.colors = Some(LspColorData::new(cx));
 2549            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2550
 2551            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2552                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2553            }
 2554            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2555        }
 2556
 2557        editor
 2558    }
 2559
 2560    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2561        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2562    }
 2563
 2564    pub fn deploy_mouse_context_menu(
 2565        &mut self,
 2566        position: gpui::Point<Pixels>,
 2567        context_menu: Entity<ContextMenu>,
 2568        window: &mut Window,
 2569        cx: &mut Context<Self>,
 2570    ) {
 2571        self.mouse_context_menu = Some(MouseContextMenu::new(
 2572            self,
 2573            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2574            context_menu,
 2575            window,
 2576            cx,
 2577        ));
 2578    }
 2579
 2580    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2581        self.mouse_context_menu
 2582            .as_ref()
 2583            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2584    }
 2585
 2586    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2587        if self
 2588            .selections
 2589            .pending_anchor()
 2590            .is_some_and(|pending_selection| {
 2591                let snapshot = self.buffer().read(cx).snapshot(cx);
 2592                pending_selection.range().includes(range, &snapshot)
 2593            })
 2594        {
 2595            return true;
 2596        }
 2597
 2598        self.selections
 2599            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2600            .into_iter()
 2601            .any(|selection| {
 2602                // This is needed to cover a corner case, if we just check for an existing
 2603                // selection in the fold range, having a cursor at the start of the fold
 2604                // marks it as selected. Non-empty selections don't cause this.
 2605                let length = selection.end - selection.start;
 2606                length > 0
 2607            })
 2608    }
 2609
 2610    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2611        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2612    }
 2613
 2614    fn key_context_internal(
 2615        &self,
 2616        has_active_edit_prediction: bool,
 2617        window: &mut Window,
 2618        cx: &mut App,
 2619    ) -> KeyContext {
 2620        let mut key_context = KeyContext::new_with_defaults();
 2621        key_context.add("Editor");
 2622        let mode = match self.mode {
 2623            EditorMode::SingleLine => "single_line",
 2624            EditorMode::AutoHeight { .. } => "auto_height",
 2625            EditorMode::Minimap { .. } => "minimap",
 2626            EditorMode::Full { .. } => "full",
 2627        };
 2628
 2629        if EditorSettings::jupyter_enabled(cx) {
 2630            key_context.add("jupyter");
 2631        }
 2632
 2633        key_context.set("mode", mode);
 2634        if self.pending_rename.is_some() {
 2635            key_context.add("renaming");
 2636        }
 2637
 2638        if let Some(snippet_stack) = self.snippet_stack.last() {
 2639            key_context.add("in_snippet");
 2640
 2641            if snippet_stack.active_index > 0 {
 2642                key_context.add("has_previous_tabstop");
 2643            }
 2644
 2645            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2646                key_context.add("has_next_tabstop");
 2647            }
 2648        }
 2649
 2650        match self.context_menu.borrow().as_ref() {
 2651            Some(CodeContextMenu::Completions(menu)) => {
 2652                if menu.visible() {
 2653                    key_context.add("menu");
 2654                    key_context.add("showing_completions");
 2655                }
 2656            }
 2657            Some(CodeContextMenu::CodeActions(menu)) => {
 2658                if menu.visible() {
 2659                    key_context.add("menu");
 2660                    key_context.add("showing_code_actions")
 2661                }
 2662            }
 2663            None => {}
 2664        }
 2665
 2666        if self.signature_help_state.has_multiple_signatures() {
 2667            key_context.add("showing_signature_help");
 2668        }
 2669
 2670        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2671        if !self.focus_handle(cx).contains_focused(window, cx)
 2672            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2673        {
 2674            for addon in self.addons.values() {
 2675                addon.extend_key_context(&mut key_context, cx)
 2676            }
 2677        }
 2678
 2679        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2680            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2681                Some(
 2682                    file.full_path(cx)
 2683                        .extension()?
 2684                        .to_string_lossy()
 2685                        .into_owned(),
 2686                )
 2687            }) {
 2688                key_context.set("extension", extension);
 2689            }
 2690        } else {
 2691            key_context.add("multibuffer");
 2692        }
 2693
 2694        if has_active_edit_prediction {
 2695            if self.edit_prediction_in_conflict() {
 2696                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2697            } else {
 2698                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2699                key_context.add("copilot_suggestion");
 2700            }
 2701        }
 2702
 2703        if self.selection_mark_mode {
 2704            key_context.add("selection_mode");
 2705        }
 2706
 2707        let disjoint = self.selections.disjoint_anchors();
 2708        let snapshot = self.snapshot(window, cx);
 2709        let snapshot = snapshot.buffer_snapshot();
 2710        if self.mode == EditorMode::SingleLine
 2711            && let [selection] = disjoint
 2712            && selection.start == selection.end
 2713            && selection.end.to_offset(snapshot) == snapshot.len()
 2714        {
 2715            key_context.add("end_of_input");
 2716        }
 2717
 2718        if self.has_any_expanded_diff_hunks(cx) {
 2719            key_context.add("diffs_expanded");
 2720        }
 2721
 2722        key_context
 2723    }
 2724
 2725    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2726        self.last_bounds.as_ref()
 2727    }
 2728
 2729    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2730        if self.mouse_cursor_hidden {
 2731            self.mouse_cursor_hidden = false;
 2732            cx.notify();
 2733        }
 2734    }
 2735
 2736    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2737        let hide_mouse_cursor = match origin {
 2738            HideMouseCursorOrigin::TypingAction => {
 2739                matches!(
 2740                    self.hide_mouse_mode,
 2741                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2742                )
 2743            }
 2744            HideMouseCursorOrigin::MovementAction => {
 2745                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2746            }
 2747        };
 2748        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2749            self.mouse_cursor_hidden = hide_mouse_cursor;
 2750            cx.notify();
 2751        }
 2752    }
 2753
 2754    pub fn edit_prediction_in_conflict(&self) -> bool {
 2755        if !self.show_edit_predictions_in_menu() {
 2756            return false;
 2757        }
 2758
 2759        let showing_completions = self
 2760            .context_menu
 2761            .borrow()
 2762            .as_ref()
 2763            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2764
 2765        showing_completions
 2766            || self.edit_prediction_requires_modifier()
 2767            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2768            // bindings to insert tab characters.
 2769            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2770    }
 2771
 2772    pub fn accept_edit_prediction_keybind(
 2773        &self,
 2774        accept_partial: bool,
 2775        window: &mut Window,
 2776        cx: &mut App,
 2777    ) -> AcceptEditPredictionBinding {
 2778        let key_context = self.key_context_internal(true, window, cx);
 2779        let in_conflict = self.edit_prediction_in_conflict();
 2780
 2781        let bindings = if accept_partial {
 2782            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2783        } else {
 2784            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2785        };
 2786
 2787        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2788        // just the first one.
 2789        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2790            !in_conflict
 2791                || binding
 2792                    .keystrokes()
 2793                    .first()
 2794                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2795        }))
 2796    }
 2797
 2798    pub fn new_file(
 2799        workspace: &mut Workspace,
 2800        _: &workspace::NewFile,
 2801        window: &mut Window,
 2802        cx: &mut Context<Workspace>,
 2803    ) {
 2804        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2805            "Failed to create buffer",
 2806            window,
 2807            cx,
 2808            |e, _, _| match e.error_code() {
 2809                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2810                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2811                e.error_tag("required").unwrap_or("the latest version")
 2812            )),
 2813                _ => None,
 2814            },
 2815        );
 2816    }
 2817
 2818    pub fn new_in_workspace(
 2819        workspace: &mut Workspace,
 2820        window: &mut Window,
 2821        cx: &mut Context<Workspace>,
 2822    ) -> Task<Result<Entity<Editor>>> {
 2823        let project = workspace.project().clone();
 2824        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2825
 2826        cx.spawn_in(window, async move |workspace, cx| {
 2827            let buffer = create.await?;
 2828            workspace.update_in(cx, |workspace, window, cx| {
 2829                let editor =
 2830                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2831                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2832                editor
 2833            })
 2834        })
 2835    }
 2836
 2837    fn new_file_vertical(
 2838        workspace: &mut Workspace,
 2839        _: &workspace::NewFileSplitVertical,
 2840        window: &mut Window,
 2841        cx: &mut Context<Workspace>,
 2842    ) {
 2843        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2844    }
 2845
 2846    fn new_file_horizontal(
 2847        workspace: &mut Workspace,
 2848        _: &workspace::NewFileSplitHorizontal,
 2849        window: &mut Window,
 2850        cx: &mut Context<Workspace>,
 2851    ) {
 2852        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2853    }
 2854
 2855    fn new_file_split(
 2856        workspace: &mut Workspace,
 2857        action: &workspace::NewFileSplit,
 2858        window: &mut Window,
 2859        cx: &mut Context<Workspace>,
 2860    ) {
 2861        Self::new_file_in_direction(workspace, action.0, window, cx)
 2862    }
 2863
 2864    fn new_file_in_direction(
 2865        workspace: &mut Workspace,
 2866        direction: SplitDirection,
 2867        window: &mut Window,
 2868        cx: &mut Context<Workspace>,
 2869    ) {
 2870        let project = workspace.project().clone();
 2871        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2872
 2873        cx.spawn_in(window, async move |workspace, cx| {
 2874            let buffer = create.await?;
 2875            workspace.update_in(cx, move |workspace, window, cx| {
 2876                workspace.split_item(
 2877                    direction,
 2878                    Box::new(
 2879                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2880                    ),
 2881                    window,
 2882                    cx,
 2883                )
 2884            })?;
 2885            anyhow::Ok(())
 2886        })
 2887        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2888            match e.error_code() {
 2889                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2890                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2891                e.error_tag("required").unwrap_or("the latest version")
 2892            )),
 2893                _ => None,
 2894            }
 2895        });
 2896    }
 2897
 2898    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2899        self.leader_id
 2900    }
 2901
 2902    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2903        &self.buffer
 2904    }
 2905
 2906    pub fn project(&self) -> Option<&Entity<Project>> {
 2907        self.project.as_ref()
 2908    }
 2909
 2910    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2911        self.workspace.as_ref()?.0.upgrade()
 2912    }
 2913
 2914    /// Returns the workspace serialization ID if this editor should be serialized.
 2915    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2916        self.workspace
 2917            .as_ref()
 2918            .filter(|_| self.should_serialize_buffer())
 2919            .and_then(|workspace| workspace.1)
 2920    }
 2921
 2922    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2923        self.buffer().read(cx).title(cx)
 2924    }
 2925
 2926    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2927        let git_blame_gutter_max_author_length = self
 2928            .render_git_blame_gutter(cx)
 2929            .then(|| {
 2930                if let Some(blame) = self.blame.as_ref() {
 2931                    let max_author_length =
 2932                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2933                    Some(max_author_length)
 2934                } else {
 2935                    None
 2936                }
 2937            })
 2938            .flatten();
 2939
 2940        EditorSnapshot {
 2941            mode: self.mode.clone(),
 2942            show_gutter: self.show_gutter,
 2943            offset_content: self.offset_content,
 2944            show_line_numbers: self.show_line_numbers,
 2945            show_git_diff_gutter: self.show_git_diff_gutter,
 2946            show_code_actions: self.show_code_actions,
 2947            show_runnables: self.show_runnables,
 2948            show_breakpoints: self.show_breakpoints,
 2949            git_blame_gutter_max_author_length,
 2950            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2951            placeholder_display_snapshot: self
 2952                .placeholder_display_map
 2953                .as_ref()
 2954                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2955            scroll_anchor: self.scroll_manager.anchor(),
 2956            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2957            is_focused: self.focus_handle.is_focused(window),
 2958            current_line_highlight: self
 2959                .current_line_highlight
 2960                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2961            gutter_hovered: self.gutter_hovered,
 2962        }
 2963    }
 2964
 2965    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2966        self.buffer.read(cx).language_at(point, cx)
 2967    }
 2968
 2969    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2970        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2971    }
 2972
 2973    pub fn active_excerpt(
 2974        &self,
 2975        cx: &App,
 2976    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2977        self.buffer
 2978            .read(cx)
 2979            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2980    }
 2981
 2982    pub fn mode(&self) -> &EditorMode {
 2983        &self.mode
 2984    }
 2985
 2986    pub fn set_mode(&mut self, mode: EditorMode) {
 2987        self.mode = mode;
 2988    }
 2989
 2990    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2991        self.collaboration_hub.as_deref()
 2992    }
 2993
 2994    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2995        self.collaboration_hub = Some(hub);
 2996    }
 2997
 2998    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2999        self.in_project_search = in_project_search;
 3000    }
 3001
 3002    pub fn set_custom_context_menu(
 3003        &mut self,
 3004        f: impl 'static
 3005        + Fn(
 3006            &mut Self,
 3007            DisplayPoint,
 3008            &mut Window,
 3009            &mut Context<Self>,
 3010        ) -> Option<Entity<ui::ContextMenu>>,
 3011    ) {
 3012        self.custom_context_menu = Some(Box::new(f))
 3013    }
 3014
 3015    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3016        self.completion_provider = provider;
 3017    }
 3018
 3019    #[cfg(any(test, feature = "test-support"))]
 3020    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3021        self.completion_provider.clone()
 3022    }
 3023
 3024    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3025        self.semantics_provider.clone()
 3026    }
 3027
 3028    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3029        self.semantics_provider = provider;
 3030    }
 3031
 3032    pub fn set_edit_prediction_provider<T>(
 3033        &mut self,
 3034        provider: Option<Entity<T>>,
 3035        window: &mut Window,
 3036        cx: &mut Context<Self>,
 3037    ) where
 3038        T: EditPredictionDelegate,
 3039    {
 3040        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3041            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3042                if this.focus_handle.is_focused(window) {
 3043                    this.update_visible_edit_prediction(window, cx);
 3044                }
 3045            }),
 3046            provider: Arc::new(provider),
 3047        });
 3048        self.update_edit_prediction_settings(cx);
 3049        self.refresh_edit_prediction(false, false, window, cx);
 3050    }
 3051
 3052    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3053        self.placeholder_display_map
 3054            .as_ref()
 3055            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3056    }
 3057
 3058    pub fn set_placeholder_text(
 3059        &mut self,
 3060        placeholder_text: &str,
 3061        window: &mut Window,
 3062        cx: &mut Context<Self>,
 3063    ) {
 3064        let multibuffer = cx
 3065            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3066
 3067        let style = window.text_style();
 3068
 3069        self.placeholder_display_map = Some(cx.new(|cx| {
 3070            DisplayMap::new(
 3071                multibuffer,
 3072                style.font(),
 3073                style.font_size.to_pixels(window.rem_size()),
 3074                None,
 3075                FILE_HEADER_HEIGHT,
 3076                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3077                Default::default(),
 3078                DiagnosticSeverity::Off,
 3079                cx,
 3080            )
 3081        }));
 3082        cx.notify();
 3083    }
 3084
 3085    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3086        self.cursor_shape = cursor_shape;
 3087
 3088        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3089        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3090
 3091        cx.notify();
 3092    }
 3093
 3094    pub fn cursor_shape(&self) -> CursorShape {
 3095        self.cursor_shape
 3096    }
 3097
 3098    pub fn set_current_line_highlight(
 3099        &mut self,
 3100        current_line_highlight: Option<CurrentLineHighlight>,
 3101    ) {
 3102        self.current_line_highlight = current_line_highlight;
 3103    }
 3104
 3105    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3106        self.collapse_matches = collapse_matches;
 3107    }
 3108
 3109    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3110        if self.collapse_matches {
 3111            return range.start..range.start;
 3112        }
 3113        range.clone()
 3114    }
 3115
 3116    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3117        self.display_map.read(cx).clip_at_line_ends
 3118    }
 3119
 3120    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3121        if self.display_map.read(cx).clip_at_line_ends != clip {
 3122            self.display_map
 3123                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3124        }
 3125    }
 3126
 3127    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3128        self.input_enabled = input_enabled;
 3129    }
 3130
 3131    pub fn set_edit_predictions_hidden_for_vim_mode(
 3132        &mut self,
 3133        hidden: bool,
 3134        window: &mut Window,
 3135        cx: &mut Context<Self>,
 3136    ) {
 3137        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3138            self.edit_predictions_hidden_for_vim_mode = hidden;
 3139            if hidden {
 3140                self.update_visible_edit_prediction(window, cx);
 3141            } else {
 3142                self.refresh_edit_prediction(true, false, window, cx);
 3143            }
 3144        }
 3145    }
 3146
 3147    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3148        self.menu_edit_predictions_policy = value;
 3149    }
 3150
 3151    pub fn set_autoindent(&mut self, autoindent: bool) {
 3152        if autoindent {
 3153            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3154        } else {
 3155            self.autoindent_mode = None;
 3156        }
 3157    }
 3158
 3159    pub fn read_only(&self, cx: &App) -> bool {
 3160        self.read_only || self.buffer.read(cx).read_only()
 3161    }
 3162
 3163    pub fn set_read_only(&mut self, read_only: bool) {
 3164        self.read_only = read_only;
 3165    }
 3166
 3167    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3168        self.use_autoclose = autoclose;
 3169    }
 3170
 3171    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3172        self.use_auto_surround = auto_surround;
 3173    }
 3174
 3175    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3176        self.auto_replace_emoji_shortcode = auto_replace;
 3177    }
 3178
 3179    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3180        self.buffer_serialization = should_serialize.then(|| {
 3181            BufferSerialization::new(
 3182                ProjectSettings::get_global(cx)
 3183                    .session
 3184                    .restore_unsaved_buffers,
 3185            )
 3186        })
 3187    }
 3188
 3189    fn should_serialize_buffer(&self) -> bool {
 3190        self.buffer_serialization.is_some()
 3191    }
 3192
 3193    pub fn toggle_edit_predictions(
 3194        &mut self,
 3195        _: &ToggleEditPrediction,
 3196        window: &mut Window,
 3197        cx: &mut Context<Self>,
 3198    ) {
 3199        if self.show_edit_predictions_override.is_some() {
 3200            self.set_show_edit_predictions(None, window, cx);
 3201        } else {
 3202            let show_edit_predictions = !self.edit_predictions_enabled();
 3203            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3204        }
 3205    }
 3206
 3207    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3208        self.show_completions_on_input_override = show_completions_on_input;
 3209    }
 3210
 3211    pub fn set_show_edit_predictions(
 3212        &mut self,
 3213        show_edit_predictions: Option<bool>,
 3214        window: &mut Window,
 3215        cx: &mut Context<Self>,
 3216    ) {
 3217        self.show_edit_predictions_override = show_edit_predictions;
 3218        self.update_edit_prediction_settings(cx);
 3219
 3220        if let Some(false) = show_edit_predictions {
 3221            self.discard_edit_prediction(false, cx);
 3222        } else {
 3223            self.refresh_edit_prediction(false, true, window, cx);
 3224        }
 3225    }
 3226
 3227    fn edit_predictions_disabled_in_scope(
 3228        &self,
 3229        buffer: &Entity<Buffer>,
 3230        buffer_position: language::Anchor,
 3231        cx: &App,
 3232    ) -> bool {
 3233        let snapshot = buffer.read(cx).snapshot();
 3234        let settings = snapshot.settings_at(buffer_position, cx);
 3235
 3236        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3237            return false;
 3238        };
 3239
 3240        scope.override_name().is_some_and(|scope_name| {
 3241            settings
 3242                .edit_predictions_disabled_in
 3243                .iter()
 3244                .any(|s| s == scope_name)
 3245        })
 3246    }
 3247
 3248    pub fn set_use_modal_editing(&mut self, to: bool) {
 3249        self.use_modal_editing = to;
 3250    }
 3251
 3252    pub fn use_modal_editing(&self) -> bool {
 3253        self.use_modal_editing
 3254    }
 3255
 3256    fn selections_did_change(
 3257        &mut self,
 3258        local: bool,
 3259        old_cursor_position: &Anchor,
 3260        effects: SelectionEffects,
 3261        window: &mut Window,
 3262        cx: &mut Context<Self>,
 3263    ) {
 3264        window.invalidate_character_coordinates();
 3265
 3266        // Copy selections to primary selection buffer
 3267        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3268        if local {
 3269            let selections = self
 3270                .selections
 3271                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3272            let buffer_handle = self.buffer.read(cx).read(cx);
 3273
 3274            let mut text = String::new();
 3275            for (index, selection) in selections.iter().enumerate() {
 3276                let text_for_selection = buffer_handle
 3277                    .text_for_range(selection.start..selection.end)
 3278                    .collect::<String>();
 3279
 3280                text.push_str(&text_for_selection);
 3281                if index != selections.len() - 1 {
 3282                    text.push('\n');
 3283                }
 3284            }
 3285
 3286            if !text.is_empty() {
 3287                cx.write_to_primary(ClipboardItem::new_string(text));
 3288            }
 3289        }
 3290
 3291        let selection_anchors = self.selections.disjoint_anchors_arc();
 3292
 3293        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3294            self.buffer.update(cx, |buffer, cx| {
 3295                buffer.set_active_selections(
 3296                    &selection_anchors,
 3297                    self.selections.line_mode(),
 3298                    self.cursor_shape,
 3299                    cx,
 3300                )
 3301            });
 3302        }
 3303        let display_map = self
 3304            .display_map
 3305            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3306        let buffer = display_map.buffer_snapshot();
 3307        if self.selections.count() == 1 {
 3308            self.add_selections_state = None;
 3309        }
 3310        self.select_next_state = None;
 3311        self.select_prev_state = None;
 3312        self.select_syntax_node_history.try_clear();
 3313        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3314        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3315        self.take_rename(false, window, cx);
 3316
 3317        let newest_selection = self.selections.newest_anchor();
 3318        let new_cursor_position = newest_selection.head();
 3319        let selection_start = newest_selection.start;
 3320
 3321        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3322            self.push_to_nav_history(
 3323                *old_cursor_position,
 3324                Some(new_cursor_position.to_point(buffer)),
 3325                false,
 3326                effects.nav_history == Some(true),
 3327                cx,
 3328            );
 3329        }
 3330
 3331        if local {
 3332            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3333                self.register_buffer(buffer_id, cx);
 3334            }
 3335
 3336            let mut context_menu = self.context_menu.borrow_mut();
 3337            let completion_menu = match context_menu.as_ref() {
 3338                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3339                Some(CodeContextMenu::CodeActions(_)) => {
 3340                    *context_menu = None;
 3341                    None
 3342                }
 3343                None => None,
 3344            };
 3345            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3346            drop(context_menu);
 3347
 3348            if effects.completions
 3349                && let Some(completion_position) = completion_position
 3350            {
 3351                let start_offset = selection_start.to_offset(buffer);
 3352                let position_matches = start_offset == completion_position.to_offset(buffer);
 3353                let continue_showing = if position_matches {
 3354                    if self.snippet_stack.is_empty() {
 3355                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3356                            == Some(CharKind::Word)
 3357                    } else {
 3358                        // Snippet choices can be shown even when the cursor is in whitespace.
 3359                        // Dismissing the menu with actions like backspace is handled by
 3360                        // invalidation regions.
 3361                        true
 3362                    }
 3363                } else {
 3364                    false
 3365                };
 3366
 3367                if continue_showing {
 3368                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3369                } else {
 3370                    self.hide_context_menu(window, cx);
 3371                }
 3372            }
 3373
 3374            hide_hover(self, cx);
 3375
 3376            if old_cursor_position.to_display_point(&display_map).row()
 3377                != new_cursor_position.to_display_point(&display_map).row()
 3378            {
 3379                self.available_code_actions.take();
 3380            }
 3381            self.refresh_code_actions(window, cx);
 3382            self.refresh_document_highlights(cx);
 3383            refresh_linked_ranges(self, window, cx);
 3384
 3385            self.refresh_selected_text_highlights(false, window, cx);
 3386            self.refresh_matching_bracket_highlights(window, cx);
 3387            self.update_visible_edit_prediction(window, cx);
 3388            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3389            self.inline_blame_popover.take();
 3390            if self.git_blame_inline_enabled {
 3391                self.start_inline_blame_timer(window, cx);
 3392            }
 3393        }
 3394
 3395        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3396        cx.emit(EditorEvent::SelectionsChanged { local });
 3397
 3398        let selections = &self.selections.disjoint_anchors_arc();
 3399        if selections.len() == 1 {
 3400            cx.emit(SearchEvent::ActiveMatchChanged)
 3401        }
 3402        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3403            let inmemory_selections = selections
 3404                .iter()
 3405                .map(|s| {
 3406                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3407                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3408                })
 3409                .collect();
 3410            self.update_restoration_data(cx, |data| {
 3411                data.selections = inmemory_selections;
 3412            });
 3413
 3414            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3415                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3416            {
 3417                let snapshot = self.buffer().read(cx).snapshot(cx);
 3418                let selections = selections.clone();
 3419                let background_executor = cx.background_executor().clone();
 3420                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3421                self.serialize_selections = cx.background_spawn(async move {
 3422                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3423                    let db_selections = selections
 3424                        .iter()
 3425                        .map(|selection| {
 3426                            (
 3427                                selection.start.to_offset(&snapshot).0,
 3428                                selection.end.to_offset(&snapshot).0,
 3429                            )
 3430                        })
 3431                        .collect();
 3432
 3433                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3434                        .await
 3435                        .with_context(|| {
 3436                            format!(
 3437                                "persisting editor selections for editor {editor_id}, \
 3438                                workspace {workspace_id:?}"
 3439                            )
 3440                        })
 3441                        .log_err();
 3442                });
 3443            }
 3444        }
 3445
 3446        cx.notify();
 3447    }
 3448
 3449    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3450        use text::ToOffset as _;
 3451        use text::ToPoint as _;
 3452
 3453        if self.mode.is_minimap()
 3454            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3455        {
 3456            return;
 3457        }
 3458
 3459        if !self.buffer().read(cx).is_singleton() {
 3460            return;
 3461        }
 3462
 3463        let display_snapshot = self
 3464            .display_map
 3465            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3466        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3467            return;
 3468        };
 3469        let inmemory_folds = display_snapshot
 3470            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3471            .map(|fold| {
 3472                fold.range.start.text_anchor.to_point(&snapshot)
 3473                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3474            })
 3475            .collect();
 3476        self.update_restoration_data(cx, |data| {
 3477            data.folds = inmemory_folds;
 3478        });
 3479
 3480        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3481            return;
 3482        };
 3483        let background_executor = cx.background_executor().clone();
 3484        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3485        let db_folds = display_snapshot
 3486            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3487            .map(|fold| {
 3488                (
 3489                    fold.range.start.text_anchor.to_offset(&snapshot),
 3490                    fold.range.end.text_anchor.to_offset(&snapshot),
 3491                )
 3492            })
 3493            .collect();
 3494        self.serialize_folds = cx.background_spawn(async move {
 3495            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3496            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3497                .await
 3498                .with_context(|| {
 3499                    format!(
 3500                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3501                    )
 3502                })
 3503                .log_err();
 3504        });
 3505    }
 3506
 3507    pub fn sync_selections(
 3508        &mut self,
 3509        other: Entity<Editor>,
 3510        cx: &mut Context<Self>,
 3511    ) -> gpui::Subscription {
 3512        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3513        if !other_selections.is_empty() {
 3514            self.selections
 3515                .change_with(&self.display_snapshot(cx), |selections| {
 3516                    selections.select_anchors(other_selections);
 3517                });
 3518        }
 3519
 3520        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3521            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3522                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3523                if other_selections.is_empty() {
 3524                    return;
 3525                }
 3526                let snapshot = this.display_snapshot(cx);
 3527                this.selections.change_with(&snapshot, |selections| {
 3528                    selections.select_anchors(other_selections);
 3529                });
 3530            }
 3531        });
 3532
 3533        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3534            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3535                let these_selections = this.selections.disjoint_anchors().to_vec();
 3536                if these_selections.is_empty() {
 3537                    return;
 3538                }
 3539                other.update(cx, |other_editor, cx| {
 3540                    let snapshot = other_editor.display_snapshot(cx);
 3541                    other_editor
 3542                        .selections
 3543                        .change_with(&snapshot, |selections| {
 3544                            selections.select_anchors(these_selections);
 3545                        })
 3546                });
 3547            }
 3548        });
 3549
 3550        Subscription::join(other_subscription, this_subscription)
 3551    }
 3552
 3553    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3554        if self.buffer().read(cx).is_singleton() {
 3555            return;
 3556        }
 3557        let snapshot = self.buffer.read(cx).snapshot(cx);
 3558        let buffer_ids: HashSet<BufferId> = self
 3559            .selections
 3560            .disjoint_anchor_ranges()
 3561            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3562            .collect();
 3563        for buffer_id in buffer_ids {
 3564            self.unfold_buffer(buffer_id, cx);
 3565        }
 3566    }
 3567
 3568    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3569    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3570    /// effects of selection change occur at the end of the transaction.
 3571    pub fn change_selections<R>(
 3572        &mut self,
 3573        effects: SelectionEffects,
 3574        window: &mut Window,
 3575        cx: &mut Context<Self>,
 3576        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3577    ) -> R {
 3578        let snapshot = self.display_snapshot(cx);
 3579        if let Some(state) = &mut self.deferred_selection_effects_state {
 3580            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3581            state.effects.completions = effects.completions;
 3582            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3583            let (changed, result) = self.selections.change_with(&snapshot, change);
 3584            state.changed |= changed;
 3585            return result;
 3586        }
 3587        let mut state = DeferredSelectionEffectsState {
 3588            changed: false,
 3589            effects,
 3590            old_cursor_position: self.selections.newest_anchor().head(),
 3591            history_entry: SelectionHistoryEntry {
 3592                selections: self.selections.disjoint_anchors_arc(),
 3593                select_next_state: self.select_next_state.clone(),
 3594                select_prev_state: self.select_prev_state.clone(),
 3595                add_selections_state: self.add_selections_state.clone(),
 3596            },
 3597        };
 3598        let (changed, result) = self.selections.change_with(&snapshot, change);
 3599        state.changed = state.changed || changed;
 3600        if self.defer_selection_effects {
 3601            self.deferred_selection_effects_state = Some(state);
 3602        } else {
 3603            self.apply_selection_effects(state, window, cx);
 3604        }
 3605        result
 3606    }
 3607
 3608    /// Defers the effects of selection change, so that the effects of multiple calls to
 3609    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3610    /// to selection history and the state of popovers based on selection position aren't
 3611    /// erroneously updated.
 3612    pub fn with_selection_effects_deferred<R>(
 3613        &mut self,
 3614        window: &mut Window,
 3615        cx: &mut Context<Self>,
 3616        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3617    ) -> R {
 3618        let already_deferred = self.defer_selection_effects;
 3619        self.defer_selection_effects = true;
 3620        let result = update(self, window, cx);
 3621        if !already_deferred {
 3622            self.defer_selection_effects = false;
 3623            if let Some(state) = self.deferred_selection_effects_state.take() {
 3624                self.apply_selection_effects(state, window, cx);
 3625            }
 3626        }
 3627        result
 3628    }
 3629
 3630    fn apply_selection_effects(
 3631        &mut self,
 3632        state: DeferredSelectionEffectsState,
 3633        window: &mut Window,
 3634        cx: &mut Context<Self>,
 3635    ) {
 3636        if state.changed {
 3637            self.selection_history.push(state.history_entry);
 3638
 3639            if let Some(autoscroll) = state.effects.scroll {
 3640                self.request_autoscroll(autoscroll, cx);
 3641            }
 3642
 3643            let old_cursor_position = &state.old_cursor_position;
 3644
 3645            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3646
 3647            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3648                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3649            }
 3650        }
 3651    }
 3652
 3653    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3654    where
 3655        I: IntoIterator<Item = (Range<S>, T)>,
 3656        S: ToOffset,
 3657        T: Into<Arc<str>>,
 3658    {
 3659        if self.read_only(cx) {
 3660            return;
 3661        }
 3662
 3663        self.buffer
 3664            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3665    }
 3666
 3667    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3668    where
 3669        I: IntoIterator<Item = (Range<S>, T)>,
 3670        S: ToOffset,
 3671        T: Into<Arc<str>>,
 3672    {
 3673        if self.read_only(cx) {
 3674            return;
 3675        }
 3676
 3677        self.buffer.update(cx, |buffer, cx| {
 3678            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3679        });
 3680    }
 3681
 3682    pub fn edit_with_block_indent<I, S, T>(
 3683        &mut self,
 3684        edits: I,
 3685        original_indent_columns: Vec<Option<u32>>,
 3686        cx: &mut Context<Self>,
 3687    ) where
 3688        I: IntoIterator<Item = (Range<S>, T)>,
 3689        S: ToOffset,
 3690        T: Into<Arc<str>>,
 3691    {
 3692        if self.read_only(cx) {
 3693            return;
 3694        }
 3695
 3696        self.buffer.update(cx, |buffer, cx| {
 3697            buffer.edit(
 3698                edits,
 3699                Some(AutoindentMode::Block {
 3700                    original_indent_columns,
 3701                }),
 3702                cx,
 3703            )
 3704        });
 3705    }
 3706
 3707    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3708        self.hide_context_menu(window, cx);
 3709
 3710        match phase {
 3711            SelectPhase::Begin {
 3712                position,
 3713                add,
 3714                click_count,
 3715            } => self.begin_selection(position, add, click_count, window, cx),
 3716            SelectPhase::BeginColumnar {
 3717                position,
 3718                goal_column,
 3719                reset,
 3720                mode,
 3721            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3722            SelectPhase::Extend {
 3723                position,
 3724                click_count,
 3725            } => self.extend_selection(position, click_count, window, cx),
 3726            SelectPhase::Update {
 3727                position,
 3728                goal_column,
 3729                scroll_delta,
 3730            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3731            SelectPhase::End => self.end_selection(window, cx),
 3732        }
 3733    }
 3734
 3735    fn extend_selection(
 3736        &mut self,
 3737        position: DisplayPoint,
 3738        click_count: usize,
 3739        window: &mut Window,
 3740        cx: &mut Context<Self>,
 3741    ) {
 3742        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3743        let tail = self
 3744            .selections
 3745            .newest::<MultiBufferOffset>(&display_map)
 3746            .tail();
 3747        let click_count = click_count.max(match self.selections.select_mode() {
 3748            SelectMode::Character => 1,
 3749            SelectMode::Word(_) => 2,
 3750            SelectMode::Line(_) => 3,
 3751            SelectMode::All => 4,
 3752        });
 3753        self.begin_selection(position, false, click_count, window, cx);
 3754
 3755        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3756
 3757        let current_selection = match self.selections.select_mode() {
 3758            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3759            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3760        };
 3761
 3762        let mut pending_selection = self
 3763            .selections
 3764            .pending_anchor()
 3765            .cloned()
 3766            .expect("extend_selection not called with pending selection");
 3767
 3768        if pending_selection
 3769            .start
 3770            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3771            == Ordering::Greater
 3772        {
 3773            pending_selection.start = current_selection.start;
 3774        }
 3775        if pending_selection
 3776            .end
 3777            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3778            == Ordering::Less
 3779        {
 3780            pending_selection.end = current_selection.end;
 3781            pending_selection.reversed = true;
 3782        }
 3783
 3784        let mut pending_mode = self.selections.pending_mode().unwrap();
 3785        match &mut pending_mode {
 3786            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3787            _ => {}
 3788        }
 3789
 3790        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3791            SelectionEffects::scroll(Autoscroll::fit())
 3792        } else {
 3793            SelectionEffects::no_scroll()
 3794        };
 3795
 3796        self.change_selections(effects, window, cx, |s| {
 3797            s.set_pending(pending_selection.clone(), pending_mode);
 3798            s.set_is_extending(true);
 3799        });
 3800    }
 3801
 3802    fn begin_selection(
 3803        &mut self,
 3804        position: DisplayPoint,
 3805        add: bool,
 3806        click_count: usize,
 3807        window: &mut Window,
 3808        cx: &mut Context<Self>,
 3809    ) {
 3810        if !self.focus_handle.is_focused(window) {
 3811            self.last_focused_descendant = None;
 3812            window.focus(&self.focus_handle);
 3813        }
 3814
 3815        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3816        let buffer = display_map.buffer_snapshot();
 3817        let position = display_map.clip_point(position, Bias::Left);
 3818
 3819        let start;
 3820        let end;
 3821        let mode;
 3822        let mut auto_scroll;
 3823        match click_count {
 3824            1 => {
 3825                start = buffer.anchor_before(position.to_point(&display_map));
 3826                end = start;
 3827                mode = SelectMode::Character;
 3828                auto_scroll = true;
 3829            }
 3830            2 => {
 3831                let position = display_map
 3832                    .clip_point(position, Bias::Left)
 3833                    .to_offset(&display_map, Bias::Left);
 3834                let (range, _) = buffer.surrounding_word(position, None);
 3835                start = buffer.anchor_before(range.start);
 3836                end = buffer.anchor_before(range.end);
 3837                mode = SelectMode::Word(start..end);
 3838                auto_scroll = true;
 3839            }
 3840            3 => {
 3841                let position = display_map
 3842                    .clip_point(position, Bias::Left)
 3843                    .to_point(&display_map);
 3844                let line_start = display_map.prev_line_boundary(position).0;
 3845                let next_line_start = buffer.clip_point(
 3846                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3847                    Bias::Left,
 3848                );
 3849                start = buffer.anchor_before(line_start);
 3850                end = buffer.anchor_before(next_line_start);
 3851                mode = SelectMode::Line(start..end);
 3852                auto_scroll = true;
 3853            }
 3854            _ => {
 3855                start = buffer.anchor_before(MultiBufferOffset(0));
 3856                end = buffer.anchor_before(buffer.len());
 3857                mode = SelectMode::All;
 3858                auto_scroll = false;
 3859            }
 3860        }
 3861        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3862
 3863        let point_to_delete: Option<usize> = {
 3864            let selected_points: Vec<Selection<Point>> =
 3865                self.selections.disjoint_in_range(start..end, &display_map);
 3866
 3867            if !add || click_count > 1 {
 3868                None
 3869            } else if !selected_points.is_empty() {
 3870                Some(selected_points[0].id)
 3871            } else {
 3872                let clicked_point_already_selected =
 3873                    self.selections.disjoint_anchors().iter().find(|selection| {
 3874                        selection.start.to_point(buffer) == start.to_point(buffer)
 3875                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3876                    });
 3877
 3878                clicked_point_already_selected.map(|selection| selection.id)
 3879            }
 3880        };
 3881
 3882        let selections_count = self.selections.count();
 3883        let effects = if auto_scroll {
 3884            SelectionEffects::default()
 3885        } else {
 3886            SelectionEffects::no_scroll()
 3887        };
 3888
 3889        self.change_selections(effects, window, cx, |s| {
 3890            if let Some(point_to_delete) = point_to_delete {
 3891                s.delete(point_to_delete);
 3892
 3893                if selections_count == 1 {
 3894                    s.set_pending_anchor_range(start..end, mode);
 3895                }
 3896            } else {
 3897                if !add {
 3898                    s.clear_disjoint();
 3899                }
 3900
 3901                s.set_pending_anchor_range(start..end, mode);
 3902            }
 3903        });
 3904    }
 3905
 3906    fn begin_columnar_selection(
 3907        &mut self,
 3908        position: DisplayPoint,
 3909        goal_column: u32,
 3910        reset: bool,
 3911        mode: ColumnarMode,
 3912        window: &mut Window,
 3913        cx: &mut Context<Self>,
 3914    ) {
 3915        if !self.focus_handle.is_focused(window) {
 3916            self.last_focused_descendant = None;
 3917            window.focus(&self.focus_handle);
 3918        }
 3919
 3920        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3921
 3922        if reset {
 3923            let pointer_position = display_map
 3924                .buffer_snapshot()
 3925                .anchor_before(position.to_point(&display_map));
 3926
 3927            self.change_selections(
 3928                SelectionEffects::scroll(Autoscroll::newest()),
 3929                window,
 3930                cx,
 3931                |s| {
 3932                    s.clear_disjoint();
 3933                    s.set_pending_anchor_range(
 3934                        pointer_position..pointer_position,
 3935                        SelectMode::Character,
 3936                    );
 3937                },
 3938            );
 3939        };
 3940
 3941        let tail = self.selections.newest::<Point>(&display_map).tail();
 3942        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3943        self.columnar_selection_state = match mode {
 3944            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3945                selection_tail: selection_anchor,
 3946                display_point: if reset {
 3947                    if position.column() != goal_column {
 3948                        Some(DisplayPoint::new(position.row(), goal_column))
 3949                    } else {
 3950                        None
 3951                    }
 3952                } else {
 3953                    None
 3954                },
 3955            }),
 3956            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3957                selection_tail: selection_anchor,
 3958            }),
 3959        };
 3960
 3961        if !reset {
 3962            self.select_columns(position, goal_column, &display_map, window, cx);
 3963        }
 3964    }
 3965
 3966    fn update_selection(
 3967        &mut self,
 3968        position: DisplayPoint,
 3969        goal_column: u32,
 3970        scroll_delta: gpui::Point<f32>,
 3971        window: &mut Window,
 3972        cx: &mut Context<Self>,
 3973    ) {
 3974        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3975
 3976        if self.columnar_selection_state.is_some() {
 3977            self.select_columns(position, goal_column, &display_map, window, cx);
 3978        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3979            let buffer = display_map.buffer_snapshot();
 3980            let head;
 3981            let tail;
 3982            let mode = self.selections.pending_mode().unwrap();
 3983            match &mode {
 3984                SelectMode::Character => {
 3985                    head = position.to_point(&display_map);
 3986                    tail = pending.tail().to_point(buffer);
 3987                }
 3988                SelectMode::Word(original_range) => {
 3989                    let offset = display_map
 3990                        .clip_point(position, Bias::Left)
 3991                        .to_offset(&display_map, Bias::Left);
 3992                    let original_range = original_range.to_offset(buffer);
 3993
 3994                    let head_offset = if buffer.is_inside_word(offset, None)
 3995                        || original_range.contains(&offset)
 3996                    {
 3997                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3998                        if word_range.start < original_range.start {
 3999                            word_range.start
 4000                        } else {
 4001                            word_range.end
 4002                        }
 4003                    } else {
 4004                        offset
 4005                    };
 4006
 4007                    head = head_offset.to_point(buffer);
 4008                    if head_offset <= original_range.start {
 4009                        tail = original_range.end.to_point(buffer);
 4010                    } else {
 4011                        tail = original_range.start.to_point(buffer);
 4012                    }
 4013                }
 4014                SelectMode::Line(original_range) => {
 4015                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4016
 4017                    let position = display_map
 4018                        .clip_point(position, Bias::Left)
 4019                        .to_point(&display_map);
 4020                    let line_start = display_map.prev_line_boundary(position).0;
 4021                    let next_line_start = buffer.clip_point(
 4022                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4023                        Bias::Left,
 4024                    );
 4025
 4026                    if line_start < original_range.start {
 4027                        head = line_start
 4028                    } else {
 4029                        head = next_line_start
 4030                    }
 4031
 4032                    if head <= original_range.start {
 4033                        tail = original_range.end;
 4034                    } else {
 4035                        tail = original_range.start;
 4036                    }
 4037                }
 4038                SelectMode::All => {
 4039                    return;
 4040                }
 4041            };
 4042
 4043            if head < tail {
 4044                pending.start = buffer.anchor_before(head);
 4045                pending.end = buffer.anchor_before(tail);
 4046                pending.reversed = true;
 4047            } else {
 4048                pending.start = buffer.anchor_before(tail);
 4049                pending.end = buffer.anchor_before(head);
 4050                pending.reversed = false;
 4051            }
 4052
 4053            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4054                s.set_pending(pending.clone(), mode);
 4055            });
 4056        } else {
 4057            log::error!("update_selection dispatched with no pending selection");
 4058            return;
 4059        }
 4060
 4061        self.apply_scroll_delta(scroll_delta, window, cx);
 4062        cx.notify();
 4063    }
 4064
 4065    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4066        self.columnar_selection_state.take();
 4067        if let Some(pending_mode) = self.selections.pending_mode() {
 4068            let selections = self
 4069                .selections
 4070                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4071            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4072                s.select(selections);
 4073                s.clear_pending();
 4074                if s.is_extending() {
 4075                    s.set_is_extending(false);
 4076                } else {
 4077                    s.set_select_mode(pending_mode);
 4078                }
 4079            });
 4080        }
 4081    }
 4082
 4083    fn select_columns(
 4084        &mut self,
 4085        head: DisplayPoint,
 4086        goal_column: u32,
 4087        display_map: &DisplaySnapshot,
 4088        window: &mut Window,
 4089        cx: &mut Context<Self>,
 4090    ) {
 4091        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4092            return;
 4093        };
 4094
 4095        let tail = match columnar_state {
 4096            ColumnarSelectionState::FromMouse {
 4097                selection_tail,
 4098                display_point,
 4099            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4100            ColumnarSelectionState::FromSelection { selection_tail } => {
 4101                selection_tail.to_display_point(display_map)
 4102            }
 4103        };
 4104
 4105        let start_row = cmp::min(tail.row(), head.row());
 4106        let end_row = cmp::max(tail.row(), head.row());
 4107        let start_column = cmp::min(tail.column(), goal_column);
 4108        let end_column = cmp::max(tail.column(), goal_column);
 4109        let reversed = start_column < tail.column();
 4110
 4111        let selection_ranges = (start_row.0..=end_row.0)
 4112            .map(DisplayRow)
 4113            .filter_map(|row| {
 4114                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4115                    || start_column <= display_map.line_len(row))
 4116                    && !display_map.is_block_line(row)
 4117                {
 4118                    let start = display_map
 4119                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4120                        .to_point(display_map);
 4121                    let end = display_map
 4122                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4123                        .to_point(display_map);
 4124                    if reversed {
 4125                        Some(end..start)
 4126                    } else {
 4127                        Some(start..end)
 4128                    }
 4129                } else {
 4130                    None
 4131                }
 4132            })
 4133            .collect::<Vec<_>>();
 4134        if selection_ranges.is_empty() {
 4135            return;
 4136        }
 4137
 4138        let ranges = match columnar_state {
 4139            ColumnarSelectionState::FromMouse { .. } => {
 4140                let mut non_empty_ranges = selection_ranges
 4141                    .iter()
 4142                    .filter(|selection_range| selection_range.start != selection_range.end)
 4143                    .peekable();
 4144                if non_empty_ranges.peek().is_some() {
 4145                    non_empty_ranges.cloned().collect()
 4146                } else {
 4147                    selection_ranges
 4148                }
 4149            }
 4150            _ => selection_ranges,
 4151        };
 4152
 4153        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4154            s.select_ranges(ranges);
 4155        });
 4156        cx.notify();
 4157    }
 4158
 4159    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4160        self.selections
 4161            .all_adjusted(snapshot)
 4162            .iter()
 4163            .any(|selection| !selection.is_empty())
 4164    }
 4165
 4166    pub fn has_pending_nonempty_selection(&self) -> bool {
 4167        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4168            Some(Selection { start, end, .. }) => start != end,
 4169            None => false,
 4170        };
 4171
 4172        pending_nonempty_selection
 4173            || (self.columnar_selection_state.is_some()
 4174                && self.selections.disjoint_anchors().len() > 1)
 4175    }
 4176
 4177    pub fn has_pending_selection(&self) -> bool {
 4178        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4179    }
 4180
 4181    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4182        self.selection_mark_mode = false;
 4183        self.selection_drag_state = SelectionDragState::None;
 4184
 4185        if self.dismiss_menus_and_popups(true, window, cx) {
 4186            cx.notify();
 4187            return;
 4188        }
 4189        if self.clear_expanded_diff_hunks(cx) {
 4190            cx.notify();
 4191            return;
 4192        }
 4193        if self.show_git_blame_gutter {
 4194            self.show_git_blame_gutter = false;
 4195            cx.notify();
 4196            return;
 4197        }
 4198
 4199        if self.mode.is_full()
 4200            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4201        {
 4202            cx.notify();
 4203            return;
 4204        }
 4205
 4206        cx.propagate();
 4207    }
 4208
 4209    pub fn dismiss_menus_and_popups(
 4210        &mut self,
 4211        is_user_requested: bool,
 4212        window: &mut Window,
 4213        cx: &mut Context<Self>,
 4214    ) -> bool {
 4215        let mut dismissed = false;
 4216
 4217        dismissed |= self.take_rename(false, window, cx).is_some();
 4218        dismissed |= self.hide_blame_popover(true, cx);
 4219        dismissed |= hide_hover(self, cx);
 4220        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4221        dismissed |= self.hide_context_menu(window, cx).is_some();
 4222        dismissed |= self.mouse_context_menu.take().is_some();
 4223        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4224        dismissed |= self.snippet_stack.pop().is_some();
 4225
 4226        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4227            self.dismiss_diagnostics(cx);
 4228            dismissed = true;
 4229        }
 4230
 4231        dismissed
 4232    }
 4233
 4234    fn linked_editing_ranges_for(
 4235        &self,
 4236        selection: Range<text::Anchor>,
 4237        cx: &App,
 4238    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4239        if self.linked_edit_ranges.is_empty() {
 4240            return None;
 4241        }
 4242        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4243            selection.end.buffer_id.and_then(|end_buffer_id| {
 4244                if selection.start.buffer_id != Some(end_buffer_id) {
 4245                    return None;
 4246                }
 4247                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4248                let snapshot = buffer.read(cx).snapshot();
 4249                self.linked_edit_ranges
 4250                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4251                    .map(|ranges| (ranges, snapshot, buffer))
 4252            })?;
 4253        use text::ToOffset as TO;
 4254        // find offset from the start of current range to current cursor position
 4255        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4256
 4257        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4258        let start_difference = start_offset - start_byte_offset;
 4259        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4260        let end_difference = end_offset - start_byte_offset;
 4261        // Current range has associated linked ranges.
 4262        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4263        for range in linked_ranges.iter() {
 4264            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4265            let end_offset = start_offset + end_difference;
 4266            let start_offset = start_offset + start_difference;
 4267            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4268                continue;
 4269            }
 4270            if self.selections.disjoint_anchor_ranges().any(|s| {
 4271                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4272                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4273                {
 4274                    return false;
 4275                }
 4276                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4277                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4278            }) {
 4279                continue;
 4280            }
 4281            let start = buffer_snapshot.anchor_after(start_offset);
 4282            let end = buffer_snapshot.anchor_after(end_offset);
 4283            linked_edits
 4284                .entry(buffer.clone())
 4285                .or_default()
 4286                .push(start..end);
 4287        }
 4288        Some(linked_edits)
 4289    }
 4290
 4291    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4292        let text: Arc<str> = text.into();
 4293
 4294        if self.read_only(cx) {
 4295            return;
 4296        }
 4297
 4298        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4299
 4300        self.unfold_buffers_with_selections(cx);
 4301
 4302        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4303        let mut bracket_inserted = false;
 4304        let mut edits = Vec::new();
 4305        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4306        let mut new_selections = Vec::with_capacity(selections.len());
 4307        let mut new_autoclose_regions = Vec::new();
 4308        let snapshot = self.buffer.read(cx).read(cx);
 4309        let mut clear_linked_edit_ranges = false;
 4310
 4311        for (selection, autoclose_region) in
 4312            self.selections_with_autoclose_regions(selections, &snapshot)
 4313        {
 4314            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4315                // Determine if the inserted text matches the opening or closing
 4316                // bracket of any of this language's bracket pairs.
 4317                let mut bracket_pair = None;
 4318                let mut is_bracket_pair_start = false;
 4319                let mut is_bracket_pair_end = false;
 4320                if !text.is_empty() {
 4321                    let mut bracket_pair_matching_end = None;
 4322                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4323                    //  and they are removing the character that triggered IME popup.
 4324                    for (pair, enabled) in scope.brackets() {
 4325                        if !pair.close && !pair.surround {
 4326                            continue;
 4327                        }
 4328
 4329                        if enabled && pair.start.ends_with(text.as_ref()) {
 4330                            let prefix_len = pair.start.len() - text.len();
 4331                            let preceding_text_matches_prefix = prefix_len == 0
 4332                                || (selection.start.column >= (prefix_len as u32)
 4333                                    && snapshot.contains_str_at(
 4334                                        Point::new(
 4335                                            selection.start.row,
 4336                                            selection.start.column - (prefix_len as u32),
 4337                                        ),
 4338                                        &pair.start[..prefix_len],
 4339                                    ));
 4340                            if preceding_text_matches_prefix {
 4341                                bracket_pair = Some(pair.clone());
 4342                                is_bracket_pair_start = true;
 4343                                break;
 4344                            }
 4345                        }
 4346                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4347                        {
 4348                            // take first bracket pair matching end, but don't break in case a later bracket
 4349                            // pair matches start
 4350                            bracket_pair_matching_end = Some(pair.clone());
 4351                        }
 4352                    }
 4353                    if let Some(end) = bracket_pair_matching_end
 4354                        && bracket_pair.is_none()
 4355                    {
 4356                        bracket_pair = Some(end);
 4357                        is_bracket_pair_end = true;
 4358                    }
 4359                }
 4360
 4361                if let Some(bracket_pair) = bracket_pair {
 4362                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4363                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4364                    let auto_surround =
 4365                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4366                    if selection.is_empty() {
 4367                        if is_bracket_pair_start {
 4368                            // If the inserted text is a suffix of an opening bracket and the
 4369                            // selection is preceded by the rest of the opening bracket, then
 4370                            // insert the closing bracket.
 4371                            let following_text_allows_autoclose = snapshot
 4372                                .chars_at(selection.start)
 4373                                .next()
 4374                                .is_none_or(|c| scope.should_autoclose_before(c));
 4375
 4376                            let preceding_text_allows_autoclose = selection.start.column == 0
 4377                                || snapshot
 4378                                    .reversed_chars_at(selection.start)
 4379                                    .next()
 4380                                    .is_none_or(|c| {
 4381                                        bracket_pair.start != bracket_pair.end
 4382                                            || !snapshot
 4383                                                .char_classifier_at(selection.start)
 4384                                                .is_word(c)
 4385                                    });
 4386
 4387                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4388                                && bracket_pair.start.len() == 1
 4389                            {
 4390                                let target = bracket_pair.start.chars().next().unwrap();
 4391                                let current_line_count = snapshot
 4392                                    .reversed_chars_at(selection.start)
 4393                                    .take_while(|&c| c != '\n')
 4394                                    .filter(|&c| c == target)
 4395                                    .count();
 4396                                current_line_count % 2 == 1
 4397                            } else {
 4398                                false
 4399                            };
 4400
 4401                            if autoclose
 4402                                && bracket_pair.close
 4403                                && following_text_allows_autoclose
 4404                                && preceding_text_allows_autoclose
 4405                                && !is_closing_quote
 4406                            {
 4407                                let anchor = snapshot.anchor_before(selection.end);
 4408                                new_selections.push((selection.map(|_| anchor), text.len()));
 4409                                new_autoclose_regions.push((
 4410                                    anchor,
 4411                                    text.len(),
 4412                                    selection.id,
 4413                                    bracket_pair.clone(),
 4414                                ));
 4415                                edits.push((
 4416                                    selection.range(),
 4417                                    format!("{}{}", text, bracket_pair.end).into(),
 4418                                ));
 4419                                bracket_inserted = true;
 4420                                continue;
 4421                            }
 4422                        }
 4423
 4424                        if let Some(region) = autoclose_region {
 4425                            // If the selection is followed by an auto-inserted closing bracket,
 4426                            // then don't insert that closing bracket again; just move the selection
 4427                            // past the closing bracket.
 4428                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4429                                && text.as_ref() == region.pair.end.as_str()
 4430                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4431                            if should_skip {
 4432                                let anchor = snapshot.anchor_after(selection.end);
 4433                                new_selections
 4434                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4435                                continue;
 4436                            }
 4437                        }
 4438
 4439                        let always_treat_brackets_as_autoclosed = snapshot
 4440                            .language_settings_at(selection.start, cx)
 4441                            .always_treat_brackets_as_autoclosed;
 4442                        if always_treat_brackets_as_autoclosed
 4443                            && is_bracket_pair_end
 4444                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4445                        {
 4446                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4447                            // and the inserted text is a closing bracket and the selection is followed
 4448                            // by the closing bracket then move the selection past the closing bracket.
 4449                            let anchor = snapshot.anchor_after(selection.end);
 4450                            new_selections.push((selection.map(|_| anchor), text.len()));
 4451                            continue;
 4452                        }
 4453                    }
 4454                    // If an opening bracket is 1 character long and is typed while
 4455                    // text is selected, then surround that text with the bracket pair.
 4456                    else if auto_surround
 4457                        && bracket_pair.surround
 4458                        && is_bracket_pair_start
 4459                        && bracket_pair.start.chars().count() == 1
 4460                    {
 4461                        edits.push((selection.start..selection.start, text.clone()));
 4462                        edits.push((
 4463                            selection.end..selection.end,
 4464                            bracket_pair.end.as_str().into(),
 4465                        ));
 4466                        bracket_inserted = true;
 4467                        new_selections.push((
 4468                            Selection {
 4469                                id: selection.id,
 4470                                start: snapshot.anchor_after(selection.start),
 4471                                end: snapshot.anchor_before(selection.end),
 4472                                reversed: selection.reversed,
 4473                                goal: selection.goal,
 4474                            },
 4475                            0,
 4476                        ));
 4477                        continue;
 4478                    }
 4479                }
 4480            }
 4481
 4482            if self.auto_replace_emoji_shortcode
 4483                && selection.is_empty()
 4484                && text.as_ref().ends_with(':')
 4485                && let Some(possible_emoji_short_code) =
 4486                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4487                && !possible_emoji_short_code.is_empty()
 4488                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4489            {
 4490                let emoji_shortcode_start = Point::new(
 4491                    selection.start.row,
 4492                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4493                );
 4494
 4495                // Remove shortcode from buffer
 4496                edits.push((
 4497                    emoji_shortcode_start..selection.start,
 4498                    "".to_string().into(),
 4499                ));
 4500                new_selections.push((
 4501                    Selection {
 4502                        id: selection.id,
 4503                        start: snapshot.anchor_after(emoji_shortcode_start),
 4504                        end: snapshot.anchor_before(selection.start),
 4505                        reversed: selection.reversed,
 4506                        goal: selection.goal,
 4507                    },
 4508                    0,
 4509                ));
 4510
 4511                // Insert emoji
 4512                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4513                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4514                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4515
 4516                continue;
 4517            }
 4518
 4519            // If not handling any auto-close operation, then just replace the selected
 4520            // text with the given input and move the selection to the end of the
 4521            // newly inserted text.
 4522            let anchor = snapshot.anchor_after(selection.end);
 4523            if !self.linked_edit_ranges.is_empty() {
 4524                let start_anchor = snapshot.anchor_before(selection.start);
 4525
 4526                let is_word_char = text.chars().next().is_none_or(|char| {
 4527                    let classifier = snapshot
 4528                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4529                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4530                    classifier.is_word(char)
 4531                });
 4532
 4533                if is_word_char {
 4534                    if let Some(ranges) = self
 4535                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4536                    {
 4537                        for (buffer, edits) in ranges {
 4538                            linked_edits
 4539                                .entry(buffer.clone())
 4540                                .or_default()
 4541                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4542                        }
 4543                    }
 4544                } else {
 4545                    clear_linked_edit_ranges = true;
 4546                }
 4547            }
 4548
 4549            new_selections.push((selection.map(|_| anchor), 0));
 4550            edits.push((selection.start..selection.end, text.clone()));
 4551        }
 4552
 4553        drop(snapshot);
 4554
 4555        self.transact(window, cx, |this, window, cx| {
 4556            if clear_linked_edit_ranges {
 4557                this.linked_edit_ranges.clear();
 4558            }
 4559            let initial_buffer_versions =
 4560                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4561
 4562            this.buffer.update(cx, |buffer, cx| {
 4563                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4564            });
 4565            for (buffer, edits) in linked_edits {
 4566                buffer.update(cx, |buffer, cx| {
 4567                    let snapshot = buffer.snapshot();
 4568                    let edits = edits
 4569                        .into_iter()
 4570                        .map(|(range, text)| {
 4571                            use text::ToPoint as TP;
 4572                            let end_point = TP::to_point(&range.end, &snapshot);
 4573                            let start_point = TP::to_point(&range.start, &snapshot);
 4574                            (start_point..end_point, text)
 4575                        })
 4576                        .sorted_by_key(|(range, _)| range.start);
 4577                    buffer.edit(edits, None, cx);
 4578                })
 4579            }
 4580            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4581            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4582            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4583            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4584                new_anchor_selections,
 4585                &map,
 4586            )
 4587            .zip(new_selection_deltas)
 4588            .map(|(selection, delta)| Selection {
 4589                id: selection.id,
 4590                start: selection.start + delta,
 4591                end: selection.end + delta,
 4592                reversed: selection.reversed,
 4593                goal: SelectionGoal::None,
 4594            })
 4595            .collect::<Vec<_>>();
 4596
 4597            let mut i = 0;
 4598            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4599                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4600                let start = map.buffer_snapshot().anchor_before(position);
 4601                let end = map.buffer_snapshot().anchor_after(position);
 4602                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4603                    match existing_state
 4604                        .range
 4605                        .start
 4606                        .cmp(&start, map.buffer_snapshot())
 4607                    {
 4608                        Ordering::Less => i += 1,
 4609                        Ordering::Greater => break,
 4610                        Ordering::Equal => {
 4611                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4612                                Ordering::Less => i += 1,
 4613                                Ordering::Equal => break,
 4614                                Ordering::Greater => break,
 4615                            }
 4616                        }
 4617                    }
 4618                }
 4619                this.autoclose_regions.insert(
 4620                    i,
 4621                    AutocloseRegion {
 4622                        selection_id,
 4623                        range: start..end,
 4624                        pair,
 4625                    },
 4626                );
 4627            }
 4628
 4629            let had_active_edit_prediction = this.has_active_edit_prediction();
 4630            this.change_selections(
 4631                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4632                window,
 4633                cx,
 4634                |s| s.select(new_selections),
 4635            );
 4636
 4637            if !bracket_inserted
 4638                && let Some(on_type_format_task) =
 4639                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4640            {
 4641                on_type_format_task.detach_and_log_err(cx);
 4642            }
 4643
 4644            let editor_settings = EditorSettings::get_global(cx);
 4645            if bracket_inserted
 4646                && (editor_settings.auto_signature_help
 4647                    || editor_settings.show_signature_help_after_edits)
 4648            {
 4649                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4650            }
 4651
 4652            let trigger_in_words =
 4653                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4654            if this.hard_wrap.is_some() {
 4655                let latest: Range<Point> = this.selections.newest(&map).range();
 4656                if latest.is_empty()
 4657                    && this
 4658                        .buffer()
 4659                        .read(cx)
 4660                        .snapshot(cx)
 4661                        .line_len(MultiBufferRow(latest.start.row))
 4662                        == latest.start.column
 4663                {
 4664                    this.rewrap_impl(
 4665                        RewrapOptions {
 4666                            override_language_settings: true,
 4667                            preserve_existing_whitespace: true,
 4668                        },
 4669                        cx,
 4670                    )
 4671                }
 4672            }
 4673            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4674            refresh_linked_ranges(this, window, cx);
 4675            this.refresh_edit_prediction(true, false, window, cx);
 4676            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4677        });
 4678    }
 4679
 4680    fn find_possible_emoji_shortcode_at_position(
 4681        snapshot: &MultiBufferSnapshot,
 4682        position: Point,
 4683    ) -> Option<String> {
 4684        let mut chars = Vec::new();
 4685        let mut found_colon = false;
 4686        for char in snapshot.reversed_chars_at(position).take(100) {
 4687            // Found a possible emoji shortcode in the middle of the buffer
 4688            if found_colon {
 4689                if char.is_whitespace() {
 4690                    chars.reverse();
 4691                    return Some(chars.iter().collect());
 4692                }
 4693                // If the previous character is not a whitespace, we are in the middle of a word
 4694                // and we only want to complete the shortcode if the word is made up of other emojis
 4695                let mut containing_word = String::new();
 4696                for ch in snapshot
 4697                    .reversed_chars_at(position)
 4698                    .skip(chars.len() + 1)
 4699                    .take(100)
 4700                {
 4701                    if ch.is_whitespace() {
 4702                        break;
 4703                    }
 4704                    containing_word.push(ch);
 4705                }
 4706                let containing_word = containing_word.chars().rev().collect::<String>();
 4707                if util::word_consists_of_emojis(containing_word.as_str()) {
 4708                    chars.reverse();
 4709                    return Some(chars.iter().collect());
 4710                }
 4711            }
 4712
 4713            if char.is_whitespace() || !char.is_ascii() {
 4714                return None;
 4715            }
 4716            if char == ':' {
 4717                found_colon = true;
 4718            } else {
 4719                chars.push(char);
 4720            }
 4721        }
 4722        // Found a possible emoji shortcode at the beginning of the buffer
 4723        chars.reverse();
 4724        Some(chars.iter().collect())
 4725    }
 4726
 4727    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4728        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4729        self.transact(window, cx, |this, window, cx| {
 4730            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4731                let selections = this
 4732                    .selections
 4733                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4734                let multi_buffer = this.buffer.read(cx);
 4735                let buffer = multi_buffer.snapshot(cx);
 4736                selections
 4737                    .iter()
 4738                    .map(|selection| {
 4739                        let start_point = selection.start.to_point(&buffer);
 4740                        let mut existing_indent =
 4741                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4742                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4743                        let start = selection.start;
 4744                        let end = selection.end;
 4745                        let selection_is_empty = start == end;
 4746                        let language_scope = buffer.language_scope_at(start);
 4747                        let (
 4748                            comment_delimiter,
 4749                            doc_delimiter,
 4750                            insert_extra_newline,
 4751                            indent_on_newline,
 4752                            indent_on_extra_newline,
 4753                        ) = if let Some(language) = &language_scope {
 4754                            let mut insert_extra_newline =
 4755                                insert_extra_newline_brackets(&buffer, start..end, language)
 4756                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4757
 4758                            // Comment extension on newline is allowed only for cursor selections
 4759                            let comment_delimiter = maybe!({
 4760                                if !selection_is_empty {
 4761                                    return None;
 4762                                }
 4763
 4764                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4765                                    return None;
 4766                                }
 4767
 4768                                let delimiters = language.line_comment_prefixes();
 4769                                let max_len_of_delimiter =
 4770                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4771                                let (snapshot, range) =
 4772                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4773
 4774                                let num_of_whitespaces = snapshot
 4775                                    .chars_for_range(range.clone())
 4776                                    .take_while(|c| c.is_whitespace())
 4777                                    .count();
 4778                                let comment_candidate = snapshot
 4779                                    .chars_for_range(range.clone())
 4780                                    .skip(num_of_whitespaces)
 4781                                    .take(max_len_of_delimiter)
 4782                                    .collect::<String>();
 4783                                let (delimiter, trimmed_len) = delimiters
 4784                                    .iter()
 4785                                    .filter_map(|delimiter| {
 4786                                        let prefix = delimiter.trim_end();
 4787                                        if comment_candidate.starts_with(prefix) {
 4788                                            Some((delimiter, prefix.len()))
 4789                                        } else {
 4790                                            None
 4791                                        }
 4792                                    })
 4793                                    .max_by_key(|(_, len)| *len)?;
 4794
 4795                                if let Some(BlockCommentConfig {
 4796                                    start: block_start, ..
 4797                                }) = language.block_comment()
 4798                                {
 4799                                    let block_start_trimmed = block_start.trim_end();
 4800                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4801                                        let line_content = snapshot
 4802                                            .chars_for_range(range)
 4803                                            .skip(num_of_whitespaces)
 4804                                            .take(block_start_trimmed.len())
 4805                                            .collect::<String>();
 4806
 4807                                        if line_content.starts_with(block_start_trimmed) {
 4808                                            return None;
 4809                                        }
 4810                                    }
 4811                                }
 4812
 4813                                let cursor_is_placed_after_comment_marker =
 4814                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4815                                if cursor_is_placed_after_comment_marker {
 4816                                    Some(delimiter.clone())
 4817                                } else {
 4818                                    None
 4819                                }
 4820                            });
 4821
 4822                            let mut indent_on_newline = IndentSize::spaces(0);
 4823                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4824
 4825                            let doc_delimiter = maybe!({
 4826                                if !selection_is_empty {
 4827                                    return None;
 4828                                }
 4829
 4830                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4831                                    return None;
 4832                                }
 4833
 4834                                let BlockCommentConfig {
 4835                                    start: start_tag,
 4836                                    end: end_tag,
 4837                                    prefix: delimiter,
 4838                                    tab_size: len,
 4839                                } = language.documentation_comment()?;
 4840                                let is_within_block_comment = buffer
 4841                                    .language_scope_at(start_point)
 4842                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4843                                if !is_within_block_comment {
 4844                                    return None;
 4845                                }
 4846
 4847                                let (snapshot, range) =
 4848                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4849
 4850                                let num_of_whitespaces = snapshot
 4851                                    .chars_for_range(range.clone())
 4852                                    .take_while(|c| c.is_whitespace())
 4853                                    .count();
 4854
 4855                                // 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.
 4856                                let column = start_point.column;
 4857                                let cursor_is_after_start_tag = {
 4858                                    let start_tag_len = start_tag.len();
 4859                                    let start_tag_line = snapshot
 4860                                        .chars_for_range(range.clone())
 4861                                        .skip(num_of_whitespaces)
 4862                                        .take(start_tag_len)
 4863                                        .collect::<String>();
 4864                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4865                                        num_of_whitespaces + start_tag_len <= column as usize
 4866                                    } else {
 4867                                        false
 4868                                    }
 4869                                };
 4870
 4871                                let cursor_is_after_delimiter = {
 4872                                    let delimiter_trim = delimiter.trim_end();
 4873                                    let delimiter_line = snapshot
 4874                                        .chars_for_range(range.clone())
 4875                                        .skip(num_of_whitespaces)
 4876                                        .take(delimiter_trim.len())
 4877                                        .collect::<String>();
 4878                                    if delimiter_line.starts_with(delimiter_trim) {
 4879                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4880                                    } else {
 4881                                        false
 4882                                    }
 4883                                };
 4884
 4885                                let cursor_is_before_end_tag_if_exists = {
 4886                                    let mut char_position = 0u32;
 4887                                    let mut end_tag_offset = None;
 4888
 4889                                    'outer: for chunk in snapshot.text_for_range(range) {
 4890                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4891                                            let chars_before_match =
 4892                                                chunk[..byte_pos].chars().count() as u32;
 4893                                            end_tag_offset =
 4894                                                Some(char_position + chars_before_match);
 4895                                            break 'outer;
 4896                                        }
 4897                                        char_position += chunk.chars().count() as u32;
 4898                                    }
 4899
 4900                                    if let Some(end_tag_offset) = end_tag_offset {
 4901                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4902                                        if cursor_is_after_start_tag {
 4903                                            if cursor_is_before_end_tag {
 4904                                                insert_extra_newline = true;
 4905                                            }
 4906                                            let cursor_is_at_start_of_end_tag =
 4907                                                column == end_tag_offset;
 4908                                            if cursor_is_at_start_of_end_tag {
 4909                                                indent_on_extra_newline.len = *len;
 4910                                            }
 4911                                        }
 4912                                        cursor_is_before_end_tag
 4913                                    } else {
 4914                                        true
 4915                                    }
 4916                                };
 4917
 4918                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4919                                    && cursor_is_before_end_tag_if_exists
 4920                                {
 4921                                    if cursor_is_after_start_tag {
 4922                                        indent_on_newline.len = *len;
 4923                                    }
 4924                                    Some(delimiter.clone())
 4925                                } else {
 4926                                    None
 4927                                }
 4928                            });
 4929
 4930                            (
 4931                                comment_delimiter,
 4932                                doc_delimiter,
 4933                                insert_extra_newline,
 4934                                indent_on_newline,
 4935                                indent_on_extra_newline,
 4936                            )
 4937                        } else {
 4938                            (
 4939                                None,
 4940                                None,
 4941                                false,
 4942                                IndentSize::default(),
 4943                                IndentSize::default(),
 4944                            )
 4945                        };
 4946
 4947                        let prevent_auto_indent = doc_delimiter.is_some();
 4948                        let delimiter = comment_delimiter.or(doc_delimiter);
 4949
 4950                        let capacity_for_delimiter =
 4951                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4952                        let mut new_text = String::with_capacity(
 4953                            1 + capacity_for_delimiter
 4954                                + existing_indent.len as usize
 4955                                + indent_on_newline.len as usize
 4956                                + indent_on_extra_newline.len as usize,
 4957                        );
 4958                        new_text.push('\n');
 4959                        new_text.extend(existing_indent.chars());
 4960                        new_text.extend(indent_on_newline.chars());
 4961
 4962                        if let Some(delimiter) = &delimiter {
 4963                            new_text.push_str(delimiter);
 4964                        }
 4965
 4966                        if insert_extra_newline {
 4967                            new_text.push('\n');
 4968                            new_text.extend(existing_indent.chars());
 4969                            new_text.extend(indent_on_extra_newline.chars());
 4970                        }
 4971
 4972                        let anchor = buffer.anchor_after(end);
 4973                        let new_selection = selection.map(|_| anchor);
 4974                        (
 4975                            ((start..end, new_text), prevent_auto_indent),
 4976                            (insert_extra_newline, new_selection),
 4977                        )
 4978                    })
 4979                    .unzip()
 4980            };
 4981
 4982            let mut auto_indent_edits = Vec::new();
 4983            let mut edits = Vec::new();
 4984            for (edit, prevent_auto_indent) in edits_with_flags {
 4985                if prevent_auto_indent {
 4986                    edits.push(edit);
 4987                } else {
 4988                    auto_indent_edits.push(edit);
 4989                }
 4990            }
 4991            if !edits.is_empty() {
 4992                this.edit(edits, cx);
 4993            }
 4994            if !auto_indent_edits.is_empty() {
 4995                this.edit_with_autoindent(auto_indent_edits, cx);
 4996            }
 4997
 4998            let buffer = this.buffer.read(cx).snapshot(cx);
 4999            let new_selections = selection_info
 5000                .into_iter()
 5001                .map(|(extra_newline_inserted, new_selection)| {
 5002                    let mut cursor = new_selection.end.to_point(&buffer);
 5003                    if extra_newline_inserted {
 5004                        cursor.row -= 1;
 5005                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5006                    }
 5007                    new_selection.map(|_| cursor)
 5008                })
 5009                .collect();
 5010
 5011            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5012            this.refresh_edit_prediction(true, false, window, cx);
 5013        });
 5014    }
 5015
 5016    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5017        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5018
 5019        let buffer = self.buffer.read(cx);
 5020        let snapshot = buffer.snapshot(cx);
 5021
 5022        let mut edits = Vec::new();
 5023        let mut rows = Vec::new();
 5024
 5025        for (rows_inserted, selection) in self
 5026            .selections
 5027            .all_adjusted(&self.display_snapshot(cx))
 5028            .into_iter()
 5029            .enumerate()
 5030        {
 5031            let cursor = selection.head();
 5032            let row = cursor.row;
 5033
 5034            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5035
 5036            let newline = "\n".to_string();
 5037            edits.push((start_of_line..start_of_line, newline));
 5038
 5039            rows.push(row + rows_inserted as u32);
 5040        }
 5041
 5042        self.transact(window, cx, |editor, window, cx| {
 5043            editor.edit(edits, cx);
 5044
 5045            editor.change_selections(Default::default(), window, cx, |s| {
 5046                let mut index = 0;
 5047                s.move_cursors_with(|map, _, _| {
 5048                    let row = rows[index];
 5049                    index += 1;
 5050
 5051                    let point = Point::new(row, 0);
 5052                    let boundary = map.next_line_boundary(point).1;
 5053                    let clipped = map.clip_point(boundary, Bias::Left);
 5054
 5055                    (clipped, SelectionGoal::None)
 5056                });
 5057            });
 5058
 5059            let mut indent_edits = Vec::new();
 5060            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5061            for row in rows {
 5062                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5063                for (row, indent) in indents {
 5064                    if indent.len == 0 {
 5065                        continue;
 5066                    }
 5067
 5068                    let text = match indent.kind {
 5069                        IndentKind::Space => " ".repeat(indent.len as usize),
 5070                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5071                    };
 5072                    let point = Point::new(row.0, 0);
 5073                    indent_edits.push((point..point, text));
 5074                }
 5075            }
 5076            editor.edit(indent_edits, cx);
 5077        });
 5078    }
 5079
 5080    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5081        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5082
 5083        let buffer = self.buffer.read(cx);
 5084        let snapshot = buffer.snapshot(cx);
 5085
 5086        let mut edits = Vec::new();
 5087        let mut rows = Vec::new();
 5088        let mut rows_inserted = 0;
 5089
 5090        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5091            let cursor = selection.head();
 5092            let row = cursor.row;
 5093
 5094            let point = Point::new(row + 1, 0);
 5095            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5096
 5097            let newline = "\n".to_string();
 5098            edits.push((start_of_line..start_of_line, newline));
 5099
 5100            rows_inserted += 1;
 5101            rows.push(row + rows_inserted);
 5102        }
 5103
 5104        self.transact(window, cx, |editor, window, cx| {
 5105            editor.edit(edits, cx);
 5106
 5107            editor.change_selections(Default::default(), window, cx, |s| {
 5108                let mut index = 0;
 5109                s.move_cursors_with(|map, _, _| {
 5110                    let row = rows[index];
 5111                    index += 1;
 5112
 5113                    let point = Point::new(row, 0);
 5114                    let boundary = map.next_line_boundary(point).1;
 5115                    let clipped = map.clip_point(boundary, Bias::Left);
 5116
 5117                    (clipped, SelectionGoal::None)
 5118                });
 5119            });
 5120
 5121            let mut indent_edits = Vec::new();
 5122            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5123            for row in rows {
 5124                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5125                for (row, indent) in indents {
 5126                    if indent.len == 0 {
 5127                        continue;
 5128                    }
 5129
 5130                    let text = match indent.kind {
 5131                        IndentKind::Space => " ".repeat(indent.len as usize),
 5132                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5133                    };
 5134                    let point = Point::new(row.0, 0);
 5135                    indent_edits.push((point..point, text));
 5136                }
 5137            }
 5138            editor.edit(indent_edits, cx);
 5139        });
 5140    }
 5141
 5142    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5143        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5144            original_indent_columns: Vec::new(),
 5145        });
 5146        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5147    }
 5148
 5149    fn insert_with_autoindent_mode(
 5150        &mut self,
 5151        text: &str,
 5152        autoindent_mode: Option<AutoindentMode>,
 5153        window: &mut Window,
 5154        cx: &mut Context<Self>,
 5155    ) {
 5156        if self.read_only(cx) {
 5157            return;
 5158        }
 5159
 5160        let text: Arc<str> = text.into();
 5161        self.transact(window, cx, |this, window, cx| {
 5162            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5163            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5164                let anchors = {
 5165                    let snapshot = buffer.read(cx);
 5166                    old_selections
 5167                        .iter()
 5168                        .map(|s| {
 5169                            let anchor = snapshot.anchor_after(s.head());
 5170                            s.map(|_| anchor)
 5171                        })
 5172                        .collect::<Vec<_>>()
 5173                };
 5174                buffer.edit(
 5175                    old_selections
 5176                        .iter()
 5177                        .map(|s| (s.start..s.end, text.clone())),
 5178                    autoindent_mode,
 5179                    cx,
 5180                );
 5181                anchors
 5182            });
 5183
 5184            this.change_selections(Default::default(), window, cx, |s| {
 5185                s.select_anchors(selection_anchors);
 5186            });
 5187
 5188            cx.notify();
 5189        });
 5190    }
 5191
 5192    fn trigger_completion_on_input(
 5193        &mut self,
 5194        text: &str,
 5195        trigger_in_words: bool,
 5196        window: &mut Window,
 5197        cx: &mut Context<Self>,
 5198    ) {
 5199        let completions_source = self
 5200            .context_menu
 5201            .borrow()
 5202            .as_ref()
 5203            .and_then(|menu| match menu {
 5204                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5205                CodeContextMenu::CodeActions(_) => None,
 5206            });
 5207
 5208        match completions_source {
 5209            Some(CompletionsMenuSource::Words { .. }) => {
 5210                self.open_or_update_completions_menu(
 5211                    Some(CompletionsMenuSource::Words {
 5212                        ignore_threshold: false,
 5213                    }),
 5214                    None,
 5215                    trigger_in_words,
 5216                    window,
 5217                    cx,
 5218                );
 5219            }
 5220            _ => self.open_or_update_completions_menu(
 5221                None,
 5222                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5223                true,
 5224                window,
 5225                cx,
 5226            ),
 5227        }
 5228    }
 5229
 5230    /// If any empty selections is touching the start of its innermost containing autoclose
 5231    /// region, expand it to select the brackets.
 5232    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5233        let selections = self
 5234            .selections
 5235            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5236        let buffer = self.buffer.read(cx).read(cx);
 5237        let new_selections = self
 5238            .selections_with_autoclose_regions(selections, &buffer)
 5239            .map(|(mut selection, region)| {
 5240                if !selection.is_empty() {
 5241                    return selection;
 5242                }
 5243
 5244                if let Some(region) = region {
 5245                    let mut range = region.range.to_offset(&buffer);
 5246                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5247                        range.start -= region.pair.start.len();
 5248                        if buffer.contains_str_at(range.start, &region.pair.start)
 5249                            && buffer.contains_str_at(range.end, &region.pair.end)
 5250                        {
 5251                            range.end += region.pair.end.len();
 5252                            selection.start = range.start;
 5253                            selection.end = range.end;
 5254
 5255                            return selection;
 5256                        }
 5257                    }
 5258                }
 5259
 5260                let always_treat_brackets_as_autoclosed = buffer
 5261                    .language_settings_at(selection.start, cx)
 5262                    .always_treat_brackets_as_autoclosed;
 5263
 5264                if !always_treat_brackets_as_autoclosed {
 5265                    return selection;
 5266                }
 5267
 5268                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5269                    for (pair, enabled) in scope.brackets() {
 5270                        if !enabled || !pair.close {
 5271                            continue;
 5272                        }
 5273
 5274                        if buffer.contains_str_at(selection.start, &pair.end) {
 5275                            let pair_start_len = pair.start.len();
 5276                            if buffer.contains_str_at(
 5277                                selection.start.saturating_sub_usize(pair_start_len),
 5278                                &pair.start,
 5279                            ) {
 5280                                selection.start -= pair_start_len;
 5281                                selection.end += pair.end.len();
 5282
 5283                                return selection;
 5284                            }
 5285                        }
 5286                    }
 5287                }
 5288
 5289                selection
 5290            })
 5291            .collect();
 5292
 5293        drop(buffer);
 5294        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5295            selections.select(new_selections)
 5296        });
 5297    }
 5298
 5299    /// Iterate the given selections, and for each one, find the smallest surrounding
 5300    /// autoclose region. This uses the ordering of the selections and the autoclose
 5301    /// regions to avoid repeated comparisons.
 5302    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5303        &'a self,
 5304        selections: impl IntoIterator<Item = Selection<D>>,
 5305        buffer: &'a MultiBufferSnapshot,
 5306    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5307        let mut i = 0;
 5308        let mut regions = self.autoclose_regions.as_slice();
 5309        selections.into_iter().map(move |selection| {
 5310            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5311
 5312            let mut enclosing = None;
 5313            while let Some(pair_state) = regions.get(i) {
 5314                if pair_state.range.end.to_offset(buffer) < range.start {
 5315                    regions = &regions[i + 1..];
 5316                    i = 0;
 5317                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5318                    break;
 5319                } else {
 5320                    if pair_state.selection_id == selection.id {
 5321                        enclosing = Some(pair_state);
 5322                    }
 5323                    i += 1;
 5324                }
 5325            }
 5326
 5327            (selection, enclosing)
 5328        })
 5329    }
 5330
 5331    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5332    fn invalidate_autoclose_regions(
 5333        &mut self,
 5334        mut selections: &[Selection<Anchor>],
 5335        buffer: &MultiBufferSnapshot,
 5336    ) {
 5337        self.autoclose_regions.retain(|state| {
 5338            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5339                return false;
 5340            }
 5341
 5342            let mut i = 0;
 5343            while let Some(selection) = selections.get(i) {
 5344                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5345                    selections = &selections[1..];
 5346                    continue;
 5347                }
 5348                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5349                    break;
 5350                }
 5351                if selection.id == state.selection_id {
 5352                    return true;
 5353                } else {
 5354                    i += 1;
 5355                }
 5356            }
 5357            false
 5358        });
 5359    }
 5360
 5361    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5362        let offset = position.to_offset(buffer);
 5363        let (word_range, kind) =
 5364            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5365        if offset > word_range.start && kind == Some(CharKind::Word) {
 5366            Some(
 5367                buffer
 5368                    .text_for_range(word_range.start..offset)
 5369                    .collect::<String>(),
 5370            )
 5371        } else {
 5372            None
 5373        }
 5374    }
 5375
 5376    pub fn visible_excerpts(
 5377        &self,
 5378        lsp_related_only: bool,
 5379        cx: &mut Context<Editor>,
 5380    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5381        let project = self.project().cloned();
 5382        let multi_buffer = self.buffer().read(cx);
 5383        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5384        let multi_buffer_visible_start = self
 5385            .scroll_manager
 5386            .anchor()
 5387            .anchor
 5388            .to_point(&multi_buffer_snapshot);
 5389        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5390            multi_buffer_visible_start
 5391                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5392            Bias::Left,
 5393        );
 5394        multi_buffer_snapshot
 5395            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5396            .into_iter()
 5397            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5398            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5399                if !lsp_related_only {
 5400                    return Some((
 5401                        excerpt_id,
 5402                        (
 5403                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5404                            buffer.version().clone(),
 5405                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5406                        ),
 5407                    ));
 5408                }
 5409
 5410                let project = project.as_ref()?.read(cx);
 5411                let buffer_file = project::File::from_dyn(buffer.file())?;
 5412                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5413                let worktree_entry = buffer_worktree
 5414                    .read(cx)
 5415                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5416                if worktree_entry.is_ignored {
 5417                    None
 5418                } else {
 5419                    Some((
 5420                        excerpt_id,
 5421                        (
 5422                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5423                            buffer.version().clone(),
 5424                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5425                        ),
 5426                    ))
 5427                }
 5428            })
 5429            .collect()
 5430    }
 5431
 5432    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5433        TextLayoutDetails {
 5434            text_system: window.text_system().clone(),
 5435            editor_style: self.style.clone().unwrap(),
 5436            rem_size: window.rem_size(),
 5437            scroll_anchor: self.scroll_manager.anchor(),
 5438            visible_rows: self.visible_line_count(),
 5439            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5440        }
 5441    }
 5442
 5443    fn trigger_on_type_formatting(
 5444        &self,
 5445        input: String,
 5446        window: &mut Window,
 5447        cx: &mut Context<Self>,
 5448    ) -> Option<Task<Result<()>>> {
 5449        if input.len() != 1 {
 5450            return None;
 5451        }
 5452
 5453        let project = self.project()?;
 5454        let position = self.selections.newest_anchor().head();
 5455        let (buffer, buffer_position) = self
 5456            .buffer
 5457            .read(cx)
 5458            .text_anchor_for_position(position, cx)?;
 5459
 5460        let settings = language_settings::language_settings(
 5461            buffer
 5462                .read(cx)
 5463                .language_at(buffer_position)
 5464                .map(|l| l.name()),
 5465            buffer.read(cx).file(),
 5466            cx,
 5467        );
 5468        if !settings.use_on_type_format {
 5469            return None;
 5470        }
 5471
 5472        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5473        // hence we do LSP request & edit on host side only — add formats to host's history.
 5474        let push_to_lsp_host_history = true;
 5475        // If this is not the host, append its history with new edits.
 5476        let push_to_client_history = project.read(cx).is_via_collab();
 5477
 5478        let on_type_formatting = project.update(cx, |project, cx| {
 5479            project.on_type_format(
 5480                buffer.clone(),
 5481                buffer_position,
 5482                input,
 5483                push_to_lsp_host_history,
 5484                cx,
 5485            )
 5486        });
 5487        Some(cx.spawn_in(window, async move |editor, cx| {
 5488            if let Some(transaction) = on_type_formatting.await? {
 5489                if push_to_client_history {
 5490                    buffer
 5491                        .update(cx, |buffer, _| {
 5492                            buffer.push_transaction(transaction, Instant::now());
 5493                            buffer.finalize_last_transaction();
 5494                        })
 5495                        .ok();
 5496                }
 5497                editor.update(cx, |editor, cx| {
 5498                    editor.refresh_document_highlights(cx);
 5499                })?;
 5500            }
 5501            Ok(())
 5502        }))
 5503    }
 5504
 5505    pub fn show_word_completions(
 5506        &mut self,
 5507        _: &ShowWordCompletions,
 5508        window: &mut Window,
 5509        cx: &mut Context<Self>,
 5510    ) {
 5511        self.open_or_update_completions_menu(
 5512            Some(CompletionsMenuSource::Words {
 5513                ignore_threshold: true,
 5514            }),
 5515            None,
 5516            false,
 5517            window,
 5518            cx,
 5519        );
 5520    }
 5521
 5522    pub fn show_completions(
 5523        &mut self,
 5524        _: &ShowCompletions,
 5525        window: &mut Window,
 5526        cx: &mut Context<Self>,
 5527    ) {
 5528        self.open_or_update_completions_menu(None, None, false, window, cx);
 5529    }
 5530
 5531    fn open_or_update_completions_menu(
 5532        &mut self,
 5533        requested_source: Option<CompletionsMenuSource>,
 5534        trigger: Option<String>,
 5535        trigger_in_words: bool,
 5536        window: &mut Window,
 5537        cx: &mut Context<Self>,
 5538    ) {
 5539        if self.pending_rename.is_some() {
 5540            return;
 5541        }
 5542
 5543        let completions_source = self
 5544            .context_menu
 5545            .borrow()
 5546            .as_ref()
 5547            .and_then(|menu| match menu {
 5548                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5549                CodeContextMenu::CodeActions(_) => None,
 5550            });
 5551
 5552        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5553
 5554        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5555        // inserted and selected. To handle that case, the start of the selection is used so that
 5556        // the menu starts with all choices.
 5557        let position = self
 5558            .selections
 5559            .newest_anchor()
 5560            .start
 5561            .bias_right(&multibuffer_snapshot);
 5562        if position.diff_base_anchor.is_some() {
 5563            return;
 5564        }
 5565        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5566        let Some(buffer) = buffer_position
 5567            .text_anchor
 5568            .buffer_id
 5569            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5570        else {
 5571            return;
 5572        };
 5573        let buffer_snapshot = buffer.read(cx).snapshot();
 5574
 5575        let menu_is_open = matches!(
 5576            self.context_menu.borrow().as_ref(),
 5577            Some(CodeContextMenu::Completions(_))
 5578        );
 5579
 5580        let language = buffer_snapshot
 5581            .language_at(buffer_position.text_anchor)
 5582            .map(|language| language.name());
 5583
 5584        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5585        let completion_settings = language_settings.completions.clone();
 5586
 5587        let show_completions_on_input = self
 5588            .show_completions_on_input_override
 5589            .unwrap_or(language_settings.show_completions_on_input);
 5590        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5591            return;
 5592        }
 5593
 5594        let query: Option<Arc<String>> =
 5595            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5596                .map(|query| query.into());
 5597
 5598        drop(multibuffer_snapshot);
 5599
 5600        // Hide the current completions menu when query is empty. Without this, cached
 5601        // completions from before the trigger char may be reused (#32774).
 5602        if query.is_none() && menu_is_open {
 5603            self.hide_context_menu(window, cx);
 5604        }
 5605
 5606        let mut ignore_word_threshold = false;
 5607        let provider = match requested_source {
 5608            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5609            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5610                ignore_word_threshold = ignore_threshold;
 5611                None
 5612            }
 5613            Some(CompletionsMenuSource::SnippetChoices)
 5614            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5615                log::error!("bug: SnippetChoices requested_source is not handled");
 5616                None
 5617            }
 5618        };
 5619
 5620        let sort_completions = provider
 5621            .as_ref()
 5622            .is_some_and(|provider| provider.sort_completions());
 5623
 5624        let filter_completions = provider
 5625            .as_ref()
 5626            .is_none_or(|provider| provider.filter_completions());
 5627
 5628        let was_snippets_only = matches!(
 5629            completions_source,
 5630            Some(CompletionsMenuSource::SnippetsOnly)
 5631        );
 5632
 5633        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5634            if filter_completions {
 5635                menu.filter(
 5636                    query.clone().unwrap_or_default(),
 5637                    buffer_position.text_anchor,
 5638                    &buffer,
 5639                    provider.clone(),
 5640                    window,
 5641                    cx,
 5642                );
 5643            }
 5644            // When `is_incomplete` is false, no need to re-query completions when the current query
 5645            // is a suffix of the initial query.
 5646            let was_complete = !menu.is_incomplete;
 5647            if was_complete && !was_snippets_only {
 5648                // If the new query is a suffix of the old query (typing more characters) and
 5649                // the previous result was complete, the existing completions can be filtered.
 5650                //
 5651                // Note that snippet completions are always complete.
 5652                let query_matches = match (&menu.initial_query, &query) {
 5653                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5654                    (None, _) => true,
 5655                    _ => false,
 5656                };
 5657                if query_matches {
 5658                    let position_matches = if menu.initial_position == position {
 5659                        true
 5660                    } else {
 5661                        let snapshot = self.buffer.read(cx).read(cx);
 5662                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5663                    };
 5664                    if position_matches {
 5665                        return;
 5666                    }
 5667                }
 5668            }
 5669        };
 5670
 5671        let Anchor {
 5672            excerpt_id: buffer_excerpt_id,
 5673            text_anchor: buffer_position,
 5674            ..
 5675        } = buffer_position;
 5676
 5677        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5678            buffer_snapshot.surrounding_word(buffer_position, None)
 5679        {
 5680            let word_to_exclude = buffer_snapshot
 5681                .text_for_range(word_range.clone())
 5682                .collect::<String>();
 5683            (
 5684                buffer_snapshot.anchor_before(word_range.start)
 5685                    ..buffer_snapshot.anchor_after(buffer_position),
 5686                Some(word_to_exclude),
 5687            )
 5688        } else {
 5689            (buffer_position..buffer_position, None)
 5690        };
 5691
 5692        let show_completion_documentation = buffer_snapshot
 5693            .settings_at(buffer_position, cx)
 5694            .show_completion_documentation;
 5695
 5696        // The document can be large, so stay in reasonable bounds when searching for words,
 5697        // otherwise completion pop-up might be slow to appear.
 5698        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5699        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5700        let min_word_search = buffer_snapshot.clip_point(
 5701            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5702            Bias::Left,
 5703        );
 5704        let max_word_search = buffer_snapshot.clip_point(
 5705            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5706            Bias::Right,
 5707        );
 5708        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5709            ..buffer_snapshot.point_to_offset(max_word_search);
 5710
 5711        let skip_digits = query
 5712            .as_ref()
 5713            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5714
 5715        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5716            trigger.as_ref().is_none_or(|trigger| {
 5717                provider.is_completion_trigger(
 5718                    &buffer,
 5719                    position.text_anchor,
 5720                    trigger,
 5721                    trigger_in_words,
 5722                    cx,
 5723                )
 5724            })
 5725        });
 5726
 5727        let provider_responses = if let Some(provider) = &provider
 5728            && load_provider_completions
 5729        {
 5730            let trigger_character =
 5731                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5732            let completion_context = CompletionContext {
 5733                trigger_kind: match &trigger_character {
 5734                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5735                    None => CompletionTriggerKind::INVOKED,
 5736                },
 5737                trigger_character,
 5738            };
 5739
 5740            provider.completions(
 5741                buffer_excerpt_id,
 5742                &buffer,
 5743                buffer_position,
 5744                completion_context,
 5745                window,
 5746                cx,
 5747            )
 5748        } else {
 5749            Task::ready(Ok(Vec::new()))
 5750        };
 5751
 5752        let load_word_completions = if !self.word_completions_enabled {
 5753            false
 5754        } else if requested_source
 5755            == Some(CompletionsMenuSource::Words {
 5756                ignore_threshold: true,
 5757            })
 5758        {
 5759            true
 5760        } else {
 5761            load_provider_completions
 5762                && completion_settings.words != WordsCompletionMode::Disabled
 5763                && (ignore_word_threshold || {
 5764                    let words_min_length = completion_settings.words_min_length;
 5765                    // check whether word has at least `words_min_length` characters
 5766                    let query_chars = query.iter().flat_map(|q| q.chars());
 5767                    query_chars.take(words_min_length).count() == words_min_length
 5768                })
 5769        };
 5770
 5771        let mut words = if load_word_completions {
 5772            cx.background_spawn({
 5773                let buffer_snapshot = buffer_snapshot.clone();
 5774                async move {
 5775                    buffer_snapshot.words_in_range(WordsQuery {
 5776                        fuzzy_contents: None,
 5777                        range: word_search_range,
 5778                        skip_digits,
 5779                    })
 5780                }
 5781            })
 5782        } else {
 5783            Task::ready(BTreeMap::default())
 5784        };
 5785
 5786        let snippets = if let Some(provider) = &provider
 5787            && provider.show_snippets()
 5788            && let Some(project) = self.project()
 5789        {
 5790            let char_classifier = buffer_snapshot
 5791                .char_classifier_at(buffer_position)
 5792                .scope_context(Some(CharScopeContext::Completion));
 5793            project.update(cx, |project, cx| {
 5794                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5795            })
 5796        } else {
 5797            Task::ready(Ok(CompletionResponse {
 5798                completions: Vec::new(),
 5799                display_options: Default::default(),
 5800                is_incomplete: false,
 5801            }))
 5802        };
 5803
 5804        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5805
 5806        let id = post_inc(&mut self.next_completion_id);
 5807        let task = cx.spawn_in(window, async move |editor, cx| {
 5808            let Ok(()) = editor.update(cx, |this, _| {
 5809                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5810            }) else {
 5811                return;
 5812            };
 5813
 5814            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5815            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5816            let mut completions = Vec::new();
 5817            let mut is_incomplete = false;
 5818            let mut display_options: Option<CompletionDisplayOptions> = None;
 5819            if let Some(provider_responses) = provider_responses.await.log_err()
 5820                && !provider_responses.is_empty()
 5821            {
 5822                for response in provider_responses {
 5823                    completions.extend(response.completions);
 5824                    is_incomplete = is_incomplete || response.is_incomplete;
 5825                    match display_options.as_mut() {
 5826                        None => {
 5827                            display_options = Some(response.display_options);
 5828                        }
 5829                        Some(options) => options.merge(&response.display_options),
 5830                    }
 5831                }
 5832                if completion_settings.words == WordsCompletionMode::Fallback {
 5833                    words = Task::ready(BTreeMap::default());
 5834                }
 5835            }
 5836            let display_options = display_options.unwrap_or_default();
 5837
 5838            let mut words = words.await;
 5839            if let Some(word_to_exclude) = &word_to_exclude {
 5840                words.remove(word_to_exclude);
 5841            }
 5842            for lsp_completion in &completions {
 5843                words.remove(&lsp_completion.new_text);
 5844            }
 5845            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5846                replace_range: word_replace_range.clone(),
 5847                new_text: word.clone(),
 5848                label: CodeLabel::plain(word, None),
 5849                match_start: None,
 5850                snippet_deduplication_key: None,
 5851                icon_path: None,
 5852                documentation: None,
 5853                source: CompletionSource::BufferWord {
 5854                    word_range,
 5855                    resolved: false,
 5856                },
 5857                insert_text_mode: Some(InsertTextMode::AS_IS),
 5858                confirm: None,
 5859            }));
 5860
 5861            completions.extend(
 5862                snippets
 5863                    .await
 5864                    .into_iter()
 5865                    .flat_map(|response| response.completions),
 5866            );
 5867
 5868            let menu = if completions.is_empty() {
 5869                None
 5870            } else {
 5871                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5872                    let languages = editor
 5873                        .workspace
 5874                        .as_ref()
 5875                        .and_then(|(workspace, _)| workspace.upgrade())
 5876                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5877                    let menu = CompletionsMenu::new(
 5878                        id,
 5879                        requested_source.unwrap_or(if load_provider_completions {
 5880                            CompletionsMenuSource::Normal
 5881                        } else {
 5882                            CompletionsMenuSource::SnippetsOnly
 5883                        }),
 5884                        sort_completions,
 5885                        show_completion_documentation,
 5886                        position,
 5887                        query.clone(),
 5888                        is_incomplete,
 5889                        buffer.clone(),
 5890                        completions.into(),
 5891                        editor
 5892                            .context_menu()
 5893                            .borrow_mut()
 5894                            .as_ref()
 5895                            .map(|menu| menu.primary_scroll_handle()),
 5896                        display_options,
 5897                        snippet_sort_order,
 5898                        languages,
 5899                        language,
 5900                        cx,
 5901                    );
 5902
 5903                    let query = if filter_completions { query } else { None };
 5904                    let matches_task = menu.do_async_filtering(
 5905                        query.unwrap_or_default(),
 5906                        buffer_position,
 5907                        &buffer,
 5908                        cx,
 5909                    );
 5910                    (menu, matches_task)
 5911                }) else {
 5912                    return;
 5913                };
 5914
 5915                let matches = matches_task.await;
 5916
 5917                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5918                    // Newer menu already set, so exit.
 5919                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5920                        editor.context_menu.borrow().as_ref()
 5921                        && prev_menu.id > id
 5922                    {
 5923                        return;
 5924                    };
 5925
 5926                    // Only valid to take prev_menu because either the new menu is immediately set
 5927                    // below, or the menu is hidden.
 5928                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5929                        editor.context_menu.borrow_mut().take()
 5930                    {
 5931                        let position_matches =
 5932                            if prev_menu.initial_position == menu.initial_position {
 5933                                true
 5934                            } else {
 5935                                let snapshot = editor.buffer.read(cx).read(cx);
 5936                                prev_menu.initial_position.to_offset(&snapshot)
 5937                                    == menu.initial_position.to_offset(&snapshot)
 5938                            };
 5939                        if position_matches {
 5940                            // Preserve markdown cache before `set_filter_results` because it will
 5941                            // try to populate the documentation cache.
 5942                            menu.preserve_markdown_cache(prev_menu);
 5943                        }
 5944                    };
 5945
 5946                    menu.set_filter_results(matches, provider, window, cx);
 5947                }) else {
 5948                    return;
 5949                };
 5950
 5951                menu.visible().then_some(menu)
 5952            };
 5953
 5954            editor
 5955                .update_in(cx, |editor, window, cx| {
 5956                    if editor.focus_handle.is_focused(window)
 5957                        && let Some(menu) = menu
 5958                    {
 5959                        *editor.context_menu.borrow_mut() =
 5960                            Some(CodeContextMenu::Completions(menu));
 5961
 5962                        crate::hover_popover::hide_hover(editor, cx);
 5963                        if editor.show_edit_predictions_in_menu() {
 5964                            editor.update_visible_edit_prediction(window, cx);
 5965                        } else {
 5966                            editor.discard_edit_prediction(false, cx);
 5967                        }
 5968
 5969                        cx.notify();
 5970                        return;
 5971                    }
 5972
 5973                    if editor.completion_tasks.len() <= 1 {
 5974                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5975                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5976                        // If it was already hidden and we don't show edit predictions in the menu,
 5977                        // we should also show the edit prediction when available.
 5978                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5979                            editor.update_visible_edit_prediction(window, cx);
 5980                        }
 5981                    }
 5982                })
 5983                .ok();
 5984        });
 5985
 5986        self.completion_tasks.push((id, task));
 5987    }
 5988
 5989    #[cfg(feature = "test-support")]
 5990    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5991        let menu = self.context_menu.borrow();
 5992        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5993            let completions = menu.completions.borrow();
 5994            Some(completions.to_vec())
 5995        } else {
 5996            None
 5997        }
 5998    }
 5999
 6000    pub fn with_completions_menu_matching_id<R>(
 6001        &self,
 6002        id: CompletionId,
 6003        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6004    ) -> R {
 6005        let mut context_menu = self.context_menu.borrow_mut();
 6006        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6007            return f(None);
 6008        };
 6009        if completions_menu.id != id {
 6010            return f(None);
 6011        }
 6012        f(Some(completions_menu))
 6013    }
 6014
 6015    pub fn confirm_completion(
 6016        &mut self,
 6017        action: &ConfirmCompletion,
 6018        window: &mut Window,
 6019        cx: &mut Context<Self>,
 6020    ) -> Option<Task<Result<()>>> {
 6021        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6022        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6023    }
 6024
 6025    pub fn confirm_completion_insert(
 6026        &mut self,
 6027        _: &ConfirmCompletionInsert,
 6028        window: &mut Window,
 6029        cx: &mut Context<Self>,
 6030    ) -> Option<Task<Result<()>>> {
 6031        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6032        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6033    }
 6034
 6035    pub fn confirm_completion_replace(
 6036        &mut self,
 6037        _: &ConfirmCompletionReplace,
 6038        window: &mut Window,
 6039        cx: &mut Context<Self>,
 6040    ) -> Option<Task<Result<()>>> {
 6041        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6042        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6043    }
 6044
 6045    pub fn compose_completion(
 6046        &mut self,
 6047        action: &ComposeCompletion,
 6048        window: &mut Window,
 6049        cx: &mut Context<Self>,
 6050    ) -> Option<Task<Result<()>>> {
 6051        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6052        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6053    }
 6054
 6055    fn do_completion(
 6056        &mut self,
 6057        item_ix: Option<usize>,
 6058        intent: CompletionIntent,
 6059        window: &mut Window,
 6060        cx: &mut Context<Editor>,
 6061    ) -> Option<Task<Result<()>>> {
 6062        use language::ToOffset as _;
 6063
 6064        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6065        else {
 6066            return None;
 6067        };
 6068
 6069        let candidate_id = {
 6070            let entries = completions_menu.entries.borrow();
 6071            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6072            if self.show_edit_predictions_in_menu() {
 6073                self.discard_edit_prediction(true, cx);
 6074            }
 6075            mat.candidate_id
 6076        };
 6077
 6078        let completion = completions_menu
 6079            .completions
 6080            .borrow()
 6081            .get(candidate_id)?
 6082            .clone();
 6083        cx.stop_propagation();
 6084
 6085        let buffer_handle = completions_menu.buffer.clone();
 6086
 6087        let CompletionEdit {
 6088            new_text,
 6089            snippet,
 6090            replace_range,
 6091        } = process_completion_for_edit(
 6092            &completion,
 6093            intent,
 6094            &buffer_handle,
 6095            &completions_menu.initial_position.text_anchor,
 6096            cx,
 6097        );
 6098
 6099        let buffer = buffer_handle.read(cx);
 6100        let snapshot = self.buffer.read(cx).snapshot(cx);
 6101        let newest_anchor = self.selections.newest_anchor();
 6102        let replace_range_multibuffer = {
 6103            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6104            excerpt.map_range_from_buffer(replace_range.clone())
 6105        };
 6106        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6107            return None;
 6108        }
 6109
 6110        let old_text = buffer
 6111            .text_for_range(replace_range.clone())
 6112            .collect::<String>();
 6113        let lookbehind = newest_anchor
 6114            .start
 6115            .text_anchor
 6116            .to_offset(buffer)
 6117            .saturating_sub(replace_range.start.0);
 6118        let lookahead = replace_range
 6119            .end
 6120            .0
 6121            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6122        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6123        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6124
 6125        let selections = self
 6126            .selections
 6127            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6128        let mut ranges = Vec::new();
 6129        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6130
 6131        for selection in &selections {
 6132            let range = if selection.id == newest_anchor.id {
 6133                replace_range_multibuffer.clone()
 6134            } else {
 6135                let mut range = selection.range();
 6136
 6137                // if prefix is present, don't duplicate it
 6138                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6139                    range.start = range.start.saturating_sub_usize(lookbehind);
 6140
 6141                    // if suffix is also present, mimic the newest cursor and replace it
 6142                    if selection.id != newest_anchor.id
 6143                        && snapshot.contains_str_at(range.end, suffix)
 6144                    {
 6145                        range.end += lookahead;
 6146                    }
 6147                }
 6148                range
 6149            };
 6150
 6151            ranges.push(range.clone());
 6152
 6153            if !self.linked_edit_ranges.is_empty() {
 6154                let start_anchor = snapshot.anchor_before(range.start);
 6155                let end_anchor = snapshot.anchor_after(range.end);
 6156                if let Some(ranges) = self
 6157                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6158                {
 6159                    for (buffer, edits) in ranges {
 6160                        linked_edits
 6161                            .entry(buffer.clone())
 6162                            .or_default()
 6163                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6164                    }
 6165                }
 6166            }
 6167        }
 6168
 6169        let common_prefix_len = old_text
 6170            .chars()
 6171            .zip(new_text.chars())
 6172            .take_while(|(a, b)| a == b)
 6173            .map(|(a, _)| a.len_utf8())
 6174            .sum::<usize>();
 6175
 6176        cx.emit(EditorEvent::InputHandled {
 6177            utf16_range_to_replace: None,
 6178            text: new_text[common_prefix_len..].into(),
 6179        });
 6180
 6181        self.transact(window, cx, |editor, window, cx| {
 6182            if let Some(mut snippet) = snippet {
 6183                snippet.text = new_text.to_string();
 6184                editor
 6185                    .insert_snippet(&ranges, snippet, window, cx)
 6186                    .log_err();
 6187            } else {
 6188                editor.buffer.update(cx, |multi_buffer, cx| {
 6189                    let auto_indent = match completion.insert_text_mode {
 6190                        Some(InsertTextMode::AS_IS) => None,
 6191                        _ => editor.autoindent_mode.clone(),
 6192                    };
 6193                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6194                    multi_buffer.edit(edits, auto_indent, cx);
 6195                });
 6196            }
 6197            for (buffer, edits) in linked_edits {
 6198                buffer.update(cx, |buffer, cx| {
 6199                    let snapshot = buffer.snapshot();
 6200                    let edits = edits
 6201                        .into_iter()
 6202                        .map(|(range, text)| {
 6203                            use text::ToPoint as TP;
 6204                            let end_point = TP::to_point(&range.end, &snapshot);
 6205                            let start_point = TP::to_point(&range.start, &snapshot);
 6206                            (start_point..end_point, text)
 6207                        })
 6208                        .sorted_by_key(|(range, _)| range.start);
 6209                    buffer.edit(edits, None, cx);
 6210                })
 6211            }
 6212
 6213            editor.refresh_edit_prediction(true, false, window, cx);
 6214        });
 6215        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6216
 6217        let show_new_completions_on_confirm = completion
 6218            .confirm
 6219            .as_ref()
 6220            .is_some_and(|confirm| confirm(intent, window, cx));
 6221        if show_new_completions_on_confirm {
 6222            self.open_or_update_completions_menu(None, None, false, window, cx);
 6223        }
 6224
 6225        let provider = self.completion_provider.as_ref()?;
 6226
 6227        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6228        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6229            let CompletionSource::Lsp {
 6230                lsp_completion,
 6231                server_id,
 6232                ..
 6233            } = &completion.source
 6234            else {
 6235                return None;
 6236            };
 6237            let lsp_command = lsp_completion.command.as_ref()?;
 6238            let available_commands = lsp_store
 6239                .read(cx)
 6240                .lsp_server_capabilities
 6241                .get(server_id)
 6242                .and_then(|server_capabilities| {
 6243                    server_capabilities
 6244                        .execute_command_provider
 6245                        .as_ref()
 6246                        .map(|options| options.commands.as_slice())
 6247                })?;
 6248            if available_commands.contains(&lsp_command.command) {
 6249                Some(CodeAction {
 6250                    server_id: *server_id,
 6251                    range: language::Anchor::MIN..language::Anchor::MIN,
 6252                    lsp_action: LspAction::Command(lsp_command.clone()),
 6253                    resolved: false,
 6254                })
 6255            } else {
 6256                None
 6257            }
 6258        });
 6259
 6260        drop(completion);
 6261        let apply_edits = provider.apply_additional_edits_for_completion(
 6262            buffer_handle.clone(),
 6263            completions_menu.completions.clone(),
 6264            candidate_id,
 6265            true,
 6266            cx,
 6267        );
 6268
 6269        let editor_settings = EditorSettings::get_global(cx);
 6270        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6271            // After the code completion is finished, users often want to know what signatures are needed.
 6272            // so we should automatically call signature_help
 6273            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6274        }
 6275
 6276        Some(cx.spawn_in(window, async move |editor, cx| {
 6277            apply_edits.await?;
 6278
 6279            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6280                let title = command.lsp_action.title().to_owned();
 6281                let project_transaction = lsp_store
 6282                    .update(cx, |lsp_store, cx| {
 6283                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6284                    })?
 6285                    .await
 6286                    .context("applying post-completion command")?;
 6287                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6288                    Self::open_project_transaction(
 6289                        &editor,
 6290                        workspace.downgrade(),
 6291                        project_transaction,
 6292                        title,
 6293                        cx,
 6294                    )
 6295                    .await?;
 6296                }
 6297            }
 6298
 6299            Ok(())
 6300        }))
 6301    }
 6302
 6303    pub fn toggle_code_actions(
 6304        &mut self,
 6305        action: &ToggleCodeActions,
 6306        window: &mut Window,
 6307        cx: &mut Context<Self>,
 6308    ) {
 6309        let quick_launch = action.quick_launch;
 6310        let mut context_menu = self.context_menu.borrow_mut();
 6311        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6312            if code_actions.deployed_from == action.deployed_from {
 6313                // Toggle if we're selecting the same one
 6314                *context_menu = None;
 6315                cx.notify();
 6316                return;
 6317            } else {
 6318                // Otherwise, clear it and start a new one
 6319                *context_menu = None;
 6320                cx.notify();
 6321            }
 6322        }
 6323        drop(context_menu);
 6324        let snapshot = self.snapshot(window, cx);
 6325        let deployed_from = action.deployed_from.clone();
 6326        let action = action.clone();
 6327        self.completion_tasks.clear();
 6328        self.discard_edit_prediction(false, cx);
 6329
 6330        let multibuffer_point = match &action.deployed_from {
 6331            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6332                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6333            }
 6334            _ => self
 6335                .selections
 6336                .newest::<Point>(&snapshot.display_snapshot)
 6337                .head(),
 6338        };
 6339        let Some((buffer, buffer_row)) = snapshot
 6340            .buffer_snapshot()
 6341            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6342            .and_then(|(buffer_snapshot, range)| {
 6343                self.buffer()
 6344                    .read(cx)
 6345                    .buffer(buffer_snapshot.remote_id())
 6346                    .map(|buffer| (buffer, range.start.row))
 6347            })
 6348        else {
 6349            return;
 6350        };
 6351        let buffer_id = buffer.read(cx).remote_id();
 6352        let tasks = self
 6353            .tasks
 6354            .get(&(buffer_id, buffer_row))
 6355            .map(|t| Arc::new(t.to_owned()));
 6356
 6357        if !self.focus_handle.is_focused(window) {
 6358            return;
 6359        }
 6360        let project = self.project.clone();
 6361
 6362        let code_actions_task = match deployed_from {
 6363            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6364            _ => self.code_actions(buffer_row, window, cx),
 6365        };
 6366
 6367        let runnable_task = match deployed_from {
 6368            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6369            _ => {
 6370                let mut task_context_task = Task::ready(None);
 6371                if let Some(tasks) = &tasks
 6372                    && let Some(project) = project
 6373                {
 6374                    task_context_task =
 6375                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6376                }
 6377
 6378                cx.spawn_in(window, {
 6379                    let buffer = buffer.clone();
 6380                    async move |editor, cx| {
 6381                        let task_context = task_context_task.await;
 6382
 6383                        let resolved_tasks =
 6384                            tasks
 6385                                .zip(task_context.clone())
 6386                                .map(|(tasks, task_context)| ResolvedTasks {
 6387                                    templates: tasks.resolve(&task_context).collect(),
 6388                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6389                                        multibuffer_point.row,
 6390                                        tasks.column,
 6391                                    )),
 6392                                });
 6393                        let debug_scenarios = editor
 6394                            .update(cx, |editor, cx| {
 6395                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6396                            })?
 6397                            .await;
 6398                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6399                    }
 6400                })
 6401            }
 6402        };
 6403
 6404        cx.spawn_in(window, async move |editor, cx| {
 6405            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6406            let code_actions = code_actions_task.await;
 6407            let spawn_straight_away = quick_launch
 6408                && resolved_tasks
 6409                    .as_ref()
 6410                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6411                && code_actions
 6412                    .as_ref()
 6413                    .is_none_or(|actions| actions.is_empty())
 6414                && debug_scenarios.is_empty();
 6415
 6416            editor.update_in(cx, |editor, window, cx| {
 6417                crate::hover_popover::hide_hover(editor, cx);
 6418                let actions = CodeActionContents::new(
 6419                    resolved_tasks,
 6420                    code_actions,
 6421                    debug_scenarios,
 6422                    task_context.unwrap_or_default(),
 6423                );
 6424
 6425                // Don't show the menu if there are no actions available
 6426                if actions.is_empty() {
 6427                    cx.notify();
 6428                    return Task::ready(Ok(()));
 6429                }
 6430
 6431                *editor.context_menu.borrow_mut() =
 6432                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6433                        buffer,
 6434                        actions,
 6435                        selected_item: Default::default(),
 6436                        scroll_handle: UniformListScrollHandle::default(),
 6437                        deployed_from,
 6438                    }));
 6439                cx.notify();
 6440                if spawn_straight_away
 6441                    && let Some(task) = editor.confirm_code_action(
 6442                        &ConfirmCodeAction { item_ix: Some(0) },
 6443                        window,
 6444                        cx,
 6445                    )
 6446                {
 6447                    return task;
 6448                }
 6449
 6450                Task::ready(Ok(()))
 6451            })
 6452        })
 6453        .detach_and_log_err(cx);
 6454    }
 6455
 6456    fn debug_scenarios(
 6457        &mut self,
 6458        resolved_tasks: &Option<ResolvedTasks>,
 6459        buffer: &Entity<Buffer>,
 6460        cx: &mut App,
 6461    ) -> Task<Vec<task::DebugScenario>> {
 6462        maybe!({
 6463            let project = self.project()?;
 6464            let dap_store = project.read(cx).dap_store();
 6465            let mut scenarios = vec![];
 6466            let resolved_tasks = resolved_tasks.as_ref()?;
 6467            let buffer = buffer.read(cx);
 6468            let language = buffer.language()?;
 6469            let file = buffer.file();
 6470            let debug_adapter = language_settings(language.name().into(), file, cx)
 6471                .debuggers
 6472                .first()
 6473                .map(SharedString::from)
 6474                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6475
 6476            dap_store.update(cx, |dap_store, cx| {
 6477                for (_, task) in &resolved_tasks.templates {
 6478                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6479                        task.original_task().clone(),
 6480                        debug_adapter.clone().into(),
 6481                        task.display_label().to_owned().into(),
 6482                        cx,
 6483                    );
 6484                    scenarios.push(maybe_scenario);
 6485                }
 6486            });
 6487            Some(cx.background_spawn(async move {
 6488                futures::future::join_all(scenarios)
 6489                    .await
 6490                    .into_iter()
 6491                    .flatten()
 6492                    .collect::<Vec<_>>()
 6493            }))
 6494        })
 6495        .unwrap_or_else(|| Task::ready(vec![]))
 6496    }
 6497
 6498    fn code_actions(
 6499        &mut self,
 6500        buffer_row: u32,
 6501        window: &mut Window,
 6502        cx: &mut Context<Self>,
 6503    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6504        let mut task = self.code_actions_task.take();
 6505        cx.spawn_in(window, async move |editor, cx| {
 6506            while let Some(prev_task) = task {
 6507                prev_task.await.log_err();
 6508                task = editor
 6509                    .update(cx, |this, _| this.code_actions_task.take())
 6510                    .ok()?;
 6511            }
 6512
 6513            editor
 6514                .update(cx, |editor, cx| {
 6515                    editor
 6516                        .available_code_actions
 6517                        .clone()
 6518                        .and_then(|(location, code_actions)| {
 6519                            let snapshot = location.buffer.read(cx).snapshot();
 6520                            let point_range = location.range.to_point(&snapshot);
 6521                            let point_range = point_range.start.row..=point_range.end.row;
 6522                            if point_range.contains(&buffer_row) {
 6523                                Some(code_actions)
 6524                            } else {
 6525                                None
 6526                            }
 6527                        })
 6528                })
 6529                .ok()
 6530                .flatten()
 6531        })
 6532    }
 6533
 6534    pub fn confirm_code_action(
 6535        &mut self,
 6536        action: &ConfirmCodeAction,
 6537        window: &mut Window,
 6538        cx: &mut Context<Self>,
 6539    ) -> Option<Task<Result<()>>> {
 6540        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6541
 6542        let actions_menu =
 6543            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6544                menu
 6545            } else {
 6546                return None;
 6547            };
 6548
 6549        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6550        let action = actions_menu.actions.get(action_ix)?;
 6551        let title = action.label();
 6552        let buffer = actions_menu.buffer;
 6553        let workspace = self.workspace()?;
 6554
 6555        match action {
 6556            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6557                workspace.update(cx, |workspace, cx| {
 6558                    workspace.schedule_resolved_task(
 6559                        task_source_kind,
 6560                        resolved_task,
 6561                        false,
 6562                        window,
 6563                        cx,
 6564                    );
 6565
 6566                    Some(Task::ready(Ok(())))
 6567                })
 6568            }
 6569            CodeActionsItem::CodeAction {
 6570                excerpt_id,
 6571                action,
 6572                provider,
 6573            } => {
 6574                let apply_code_action =
 6575                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6576                let workspace = workspace.downgrade();
 6577                Some(cx.spawn_in(window, async move |editor, cx| {
 6578                    let project_transaction = apply_code_action.await?;
 6579                    Self::open_project_transaction(
 6580                        &editor,
 6581                        workspace,
 6582                        project_transaction,
 6583                        title,
 6584                        cx,
 6585                    )
 6586                    .await
 6587                }))
 6588            }
 6589            CodeActionsItem::DebugScenario(scenario) => {
 6590                let context = actions_menu.actions.context;
 6591
 6592                workspace.update(cx, |workspace, cx| {
 6593                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6594                    workspace.start_debug_session(
 6595                        scenario,
 6596                        context,
 6597                        Some(buffer),
 6598                        None,
 6599                        window,
 6600                        cx,
 6601                    );
 6602                });
 6603                Some(Task::ready(Ok(())))
 6604            }
 6605        }
 6606    }
 6607
 6608    pub async fn open_project_transaction(
 6609        editor: &WeakEntity<Editor>,
 6610        workspace: WeakEntity<Workspace>,
 6611        transaction: ProjectTransaction,
 6612        title: String,
 6613        cx: &mut AsyncWindowContext,
 6614    ) -> Result<()> {
 6615        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6616        cx.update(|_, cx| {
 6617            entries.sort_unstable_by_key(|(buffer, _)| {
 6618                buffer.read(cx).file().map(|f| f.path().clone())
 6619            });
 6620        })?;
 6621        if entries.is_empty() {
 6622            return Ok(());
 6623        }
 6624
 6625        // If the project transaction's edits are all contained within this editor, then
 6626        // avoid opening a new editor to display them.
 6627
 6628        if let [(buffer, transaction)] = &*entries {
 6629            let excerpt = editor.update(cx, |editor, cx| {
 6630                editor
 6631                    .buffer()
 6632                    .read(cx)
 6633                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6634            })?;
 6635            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6636                && excerpted_buffer == *buffer
 6637            {
 6638                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6639                    let excerpt_range = excerpt_range.to_offset(buffer);
 6640                    buffer
 6641                        .edited_ranges_for_transaction::<usize>(transaction)
 6642                        .all(|range| {
 6643                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6644                        })
 6645                })?;
 6646
 6647                if all_edits_within_excerpt {
 6648                    return Ok(());
 6649                }
 6650            }
 6651        }
 6652
 6653        let mut ranges_to_highlight = Vec::new();
 6654        let excerpt_buffer = cx.new(|cx| {
 6655            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6656            for (buffer_handle, transaction) in &entries {
 6657                let edited_ranges = buffer_handle
 6658                    .read(cx)
 6659                    .edited_ranges_for_transaction::<Point>(transaction)
 6660                    .collect::<Vec<_>>();
 6661                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6662                    PathKey::for_buffer(buffer_handle, cx),
 6663                    buffer_handle.clone(),
 6664                    edited_ranges,
 6665                    multibuffer_context_lines(cx),
 6666                    cx,
 6667                );
 6668
 6669                ranges_to_highlight.extend(ranges);
 6670            }
 6671            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6672            multibuffer
 6673        })?;
 6674
 6675        workspace.update_in(cx, |workspace, window, cx| {
 6676            let project = workspace.project().clone();
 6677            let editor =
 6678                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6679            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6680            editor.update(cx, |editor, cx| {
 6681                editor.highlight_background::<Self>(
 6682                    &ranges_to_highlight,
 6683                    |_, theme| theme.colors().editor_highlighted_line_background,
 6684                    cx,
 6685                );
 6686            });
 6687        })?;
 6688
 6689        Ok(())
 6690    }
 6691
 6692    pub fn clear_code_action_providers(&mut self) {
 6693        self.code_action_providers.clear();
 6694        self.available_code_actions.take();
 6695    }
 6696
 6697    pub fn add_code_action_provider(
 6698        &mut self,
 6699        provider: Rc<dyn CodeActionProvider>,
 6700        window: &mut Window,
 6701        cx: &mut Context<Self>,
 6702    ) {
 6703        if self
 6704            .code_action_providers
 6705            .iter()
 6706            .any(|existing_provider| existing_provider.id() == provider.id())
 6707        {
 6708            return;
 6709        }
 6710
 6711        self.code_action_providers.push(provider);
 6712        self.refresh_code_actions(window, cx);
 6713    }
 6714
 6715    pub fn remove_code_action_provider(
 6716        &mut self,
 6717        id: Arc<str>,
 6718        window: &mut Window,
 6719        cx: &mut Context<Self>,
 6720    ) {
 6721        self.code_action_providers
 6722            .retain(|provider| provider.id() != id);
 6723        self.refresh_code_actions(window, cx);
 6724    }
 6725
 6726    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6727        !self.code_action_providers.is_empty()
 6728            && EditorSettings::get_global(cx).toolbar.code_actions
 6729    }
 6730
 6731    pub fn has_available_code_actions(&self) -> bool {
 6732        self.available_code_actions
 6733            .as_ref()
 6734            .is_some_and(|(_, actions)| !actions.is_empty())
 6735    }
 6736
 6737    fn render_inline_code_actions(
 6738        &self,
 6739        icon_size: ui::IconSize,
 6740        display_row: DisplayRow,
 6741        is_active: bool,
 6742        cx: &mut Context<Self>,
 6743    ) -> AnyElement {
 6744        let show_tooltip = !self.context_menu_visible();
 6745        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6746            .icon_size(icon_size)
 6747            .shape(ui::IconButtonShape::Square)
 6748            .icon_color(ui::Color::Hidden)
 6749            .toggle_state(is_active)
 6750            .when(show_tooltip, |this| {
 6751                this.tooltip({
 6752                    let focus_handle = self.focus_handle.clone();
 6753                    move |_window, cx| {
 6754                        Tooltip::for_action_in(
 6755                            "Toggle Code Actions",
 6756                            &ToggleCodeActions {
 6757                                deployed_from: None,
 6758                                quick_launch: false,
 6759                            },
 6760                            &focus_handle,
 6761                            cx,
 6762                        )
 6763                    }
 6764                })
 6765            })
 6766            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6767                window.focus(&editor.focus_handle(cx));
 6768                editor.toggle_code_actions(
 6769                    &crate::actions::ToggleCodeActions {
 6770                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6771                            display_row,
 6772                        )),
 6773                        quick_launch: false,
 6774                    },
 6775                    window,
 6776                    cx,
 6777                );
 6778            }))
 6779            .into_any_element()
 6780    }
 6781
 6782    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6783        &self.context_menu
 6784    }
 6785
 6786    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6787        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6788            cx.background_executor()
 6789                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6790                .await;
 6791
 6792            let (start_buffer, start, _, end, newest_selection) = this
 6793                .update(cx, |this, cx| {
 6794                    let newest_selection = this.selections.newest_anchor().clone();
 6795                    if newest_selection.head().diff_base_anchor.is_some() {
 6796                        return None;
 6797                    }
 6798                    let display_snapshot = this.display_snapshot(cx);
 6799                    let newest_selection_adjusted =
 6800                        this.selections.newest_adjusted(&display_snapshot);
 6801                    let buffer = this.buffer.read(cx);
 6802
 6803                    let (start_buffer, start) =
 6804                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6805                    let (end_buffer, end) =
 6806                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6807
 6808                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6809                })?
 6810                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6811                .context(
 6812                    "Expected selection to lie in a single buffer when refreshing code actions",
 6813                )?;
 6814            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6815                let providers = this.code_action_providers.clone();
 6816                let tasks = this
 6817                    .code_action_providers
 6818                    .iter()
 6819                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6820                    .collect::<Vec<_>>();
 6821                (providers, tasks)
 6822            })?;
 6823
 6824            let mut actions = Vec::new();
 6825            for (provider, provider_actions) in
 6826                providers.into_iter().zip(future::join_all(tasks).await)
 6827            {
 6828                if let Some(provider_actions) = provider_actions.log_err() {
 6829                    actions.extend(provider_actions.into_iter().map(|action| {
 6830                        AvailableCodeAction {
 6831                            excerpt_id: newest_selection.start.excerpt_id,
 6832                            action,
 6833                            provider: provider.clone(),
 6834                        }
 6835                    }));
 6836                }
 6837            }
 6838
 6839            this.update(cx, |this, cx| {
 6840                this.available_code_actions = if actions.is_empty() {
 6841                    None
 6842                } else {
 6843                    Some((
 6844                        Location {
 6845                            buffer: start_buffer,
 6846                            range: start..end,
 6847                        },
 6848                        actions.into(),
 6849                    ))
 6850                };
 6851                cx.notify();
 6852            })
 6853        }));
 6854    }
 6855
 6856    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6857        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6858            self.show_git_blame_inline = false;
 6859
 6860            self.show_git_blame_inline_delay_task =
 6861                Some(cx.spawn_in(window, async move |this, cx| {
 6862                    cx.background_executor().timer(delay).await;
 6863
 6864                    this.update(cx, |this, cx| {
 6865                        this.show_git_blame_inline = true;
 6866                        cx.notify();
 6867                    })
 6868                    .log_err();
 6869                }));
 6870        }
 6871    }
 6872
 6873    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6874        let snapshot = self.snapshot(window, cx);
 6875        let cursor = self
 6876            .selections
 6877            .newest::<Point>(&snapshot.display_snapshot)
 6878            .head();
 6879        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6880        else {
 6881            return;
 6882        };
 6883
 6884        if self.blame.is_none() {
 6885            self.start_git_blame(true, window, cx);
 6886        }
 6887        let Some(blame) = self.blame.as_ref() else {
 6888            return;
 6889        };
 6890
 6891        let row_info = RowInfo {
 6892            buffer_id: Some(buffer.remote_id()),
 6893            buffer_row: Some(point.row),
 6894            ..Default::default()
 6895        };
 6896        let Some((buffer, blame_entry)) = blame
 6897            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6898            .flatten()
 6899        else {
 6900            return;
 6901        };
 6902
 6903        let anchor = self.selections.newest_anchor().head();
 6904        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 6905        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6906            self.show_blame_popover(
 6907                buffer,
 6908                &blame_entry,
 6909                position + last_bounds.origin,
 6910                true,
 6911                cx,
 6912            );
 6913        };
 6914    }
 6915
 6916    fn show_blame_popover(
 6917        &mut self,
 6918        buffer: BufferId,
 6919        blame_entry: &BlameEntry,
 6920        position: gpui::Point<Pixels>,
 6921        ignore_timeout: bool,
 6922        cx: &mut Context<Self>,
 6923    ) {
 6924        if let Some(state) = &mut self.inline_blame_popover {
 6925            state.hide_task.take();
 6926        } else {
 6927            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6928            let blame_entry = blame_entry.clone();
 6929            let show_task = cx.spawn(async move |editor, cx| {
 6930                if !ignore_timeout {
 6931                    cx.background_executor()
 6932                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6933                        .await;
 6934                }
 6935                editor
 6936                    .update(cx, |editor, cx| {
 6937                        editor.inline_blame_popover_show_task.take();
 6938                        let Some(blame) = editor.blame.as_ref() else {
 6939                            return;
 6940                        };
 6941                        let blame = blame.read(cx);
 6942                        let details = blame.details_for_entry(buffer, &blame_entry);
 6943                        let markdown = cx.new(|cx| {
 6944                            Markdown::new(
 6945                                details
 6946                                    .as_ref()
 6947                                    .map(|message| message.message.clone())
 6948                                    .unwrap_or_default(),
 6949                                None,
 6950                                None,
 6951                                cx,
 6952                            )
 6953                        });
 6954                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6955                            position,
 6956                            hide_task: None,
 6957                            popover_bounds: None,
 6958                            popover_state: InlineBlamePopoverState {
 6959                                scroll_handle: ScrollHandle::new(),
 6960                                commit_message: details,
 6961                                markdown,
 6962                            },
 6963                            keyboard_grace: ignore_timeout,
 6964                        });
 6965                        cx.notify();
 6966                    })
 6967                    .ok();
 6968            });
 6969            self.inline_blame_popover_show_task = Some(show_task);
 6970        }
 6971    }
 6972
 6973    pub fn has_mouse_context_menu(&self) -> bool {
 6974        self.mouse_context_menu.is_some()
 6975    }
 6976
 6977    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6978        self.inline_blame_popover_show_task.take();
 6979        if let Some(state) = &mut self.inline_blame_popover {
 6980            let hide_task = cx.spawn(async move |editor, cx| {
 6981                if !ignore_timeout {
 6982                    cx.background_executor()
 6983                        .timer(std::time::Duration::from_millis(100))
 6984                        .await;
 6985                }
 6986                editor
 6987                    .update(cx, |editor, cx| {
 6988                        editor.inline_blame_popover.take();
 6989                        cx.notify();
 6990                    })
 6991                    .ok();
 6992            });
 6993            state.hide_task = Some(hide_task);
 6994            true
 6995        } else {
 6996            false
 6997        }
 6998    }
 6999
 7000    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7001        if self.pending_rename.is_some() {
 7002            return None;
 7003        }
 7004
 7005        let provider = self.semantics_provider.clone()?;
 7006        let buffer = self.buffer.read(cx);
 7007        let newest_selection = self.selections.newest_anchor().clone();
 7008        let cursor_position = newest_selection.head();
 7009        let (cursor_buffer, cursor_buffer_position) =
 7010            buffer.text_anchor_for_position(cursor_position, cx)?;
 7011        let (tail_buffer, tail_buffer_position) =
 7012            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7013        if cursor_buffer != tail_buffer {
 7014            return None;
 7015        }
 7016
 7017        let snapshot = cursor_buffer.read(cx).snapshot();
 7018        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7019        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7020        if start_word_range != end_word_range {
 7021            self.document_highlights_task.take();
 7022            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 7023            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 7024            return None;
 7025        }
 7026
 7027        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7028        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7029            cx.background_executor()
 7030                .timer(Duration::from_millis(debounce))
 7031                .await;
 7032
 7033            let highlights = if let Some(highlights) = cx
 7034                .update(|cx| {
 7035                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7036                })
 7037                .ok()
 7038                .flatten()
 7039            {
 7040                highlights.await.log_err()
 7041            } else {
 7042                None
 7043            };
 7044
 7045            if let Some(highlights) = highlights {
 7046                this.update(cx, |this, cx| {
 7047                    if this.pending_rename.is_some() {
 7048                        return;
 7049                    }
 7050
 7051                    let buffer = this.buffer.read(cx);
 7052                    if buffer
 7053                        .text_anchor_for_position(cursor_position, cx)
 7054                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7055                    {
 7056                        return;
 7057                    }
 7058
 7059                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7060                    let mut write_ranges = Vec::new();
 7061                    let mut read_ranges = Vec::new();
 7062                    for highlight in highlights {
 7063                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7064                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7065                        {
 7066                            let start = highlight
 7067                                .range
 7068                                .start
 7069                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7070                            let end = highlight
 7071                                .range
 7072                                .end
 7073                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7074                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7075                                continue;
 7076                            }
 7077
 7078                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7079                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7080                                write_ranges.push(range);
 7081                            } else {
 7082                                read_ranges.push(range);
 7083                            }
 7084                        }
 7085                    }
 7086
 7087                    this.highlight_background::<DocumentHighlightRead>(
 7088                        &read_ranges,
 7089                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7090                        cx,
 7091                    );
 7092                    this.highlight_background::<DocumentHighlightWrite>(
 7093                        &write_ranges,
 7094                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7095                        cx,
 7096                    );
 7097                    cx.notify();
 7098                })
 7099                .log_err();
 7100            }
 7101        }));
 7102        None
 7103    }
 7104
 7105    fn prepare_highlight_query_from_selection(
 7106        &mut self,
 7107        window: &Window,
 7108        cx: &mut Context<Editor>,
 7109    ) -> Option<(String, Range<Anchor>)> {
 7110        if matches!(self.mode, EditorMode::SingleLine) {
 7111            return None;
 7112        }
 7113        if !EditorSettings::get_global(cx).selection_highlight {
 7114            return None;
 7115        }
 7116        if self.selections.count() != 1 || self.selections.line_mode() {
 7117            return None;
 7118        }
 7119        let snapshot = self.snapshot(window, cx);
 7120        let selection = self.selections.newest::<Point>(&snapshot);
 7121        // If the selection spans multiple rows OR it is empty
 7122        if selection.start.row != selection.end.row
 7123            || selection.start.column == selection.end.column
 7124        {
 7125            return None;
 7126        }
 7127        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7128        let query = snapshot
 7129            .buffer_snapshot()
 7130            .text_for_range(selection_anchor_range.clone())
 7131            .collect::<String>();
 7132        if query.trim().is_empty() {
 7133            return None;
 7134        }
 7135        Some((query, selection_anchor_range))
 7136    }
 7137
 7138    #[ztracing::instrument(skip_all)]
 7139    fn update_selection_occurrence_highlights(
 7140        &mut self,
 7141        query_text: String,
 7142        query_range: Range<Anchor>,
 7143        multi_buffer_range_to_query: Range<Point>,
 7144        use_debounce: bool,
 7145        window: &mut Window,
 7146        cx: &mut Context<Editor>,
 7147    ) -> Task<()> {
 7148        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7149        cx.spawn_in(window, async move |editor, cx| {
 7150            if use_debounce {
 7151                cx.background_executor()
 7152                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7153                    .await;
 7154            }
 7155            let match_task = cx.background_spawn(async move {
 7156                let buffer_ranges = multi_buffer_snapshot
 7157                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7158                    .into_iter()
 7159                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7160                let mut match_ranges = Vec::new();
 7161                let Ok(regex) = project::search::SearchQuery::text(
 7162                    query_text.clone(),
 7163                    false,
 7164                    false,
 7165                    false,
 7166                    Default::default(),
 7167                    Default::default(),
 7168                    false,
 7169                    None,
 7170                ) else {
 7171                    return Vec::default();
 7172                };
 7173                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7174                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7175                    match_ranges.extend(
 7176                        regex
 7177                            .search(
 7178                                buffer_snapshot,
 7179                                Some(search_range.start.0..search_range.end.0),
 7180                            )
 7181                            .await
 7182                            .into_iter()
 7183                            .filter_map(|match_range| {
 7184                                let match_start = buffer_snapshot
 7185                                    .anchor_after(search_range.start + match_range.start);
 7186                                let match_end = buffer_snapshot
 7187                                    .anchor_before(search_range.start + match_range.end);
 7188                                let match_anchor_range =
 7189                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7190                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7191                            }),
 7192                    );
 7193                }
 7194                match_ranges
 7195            });
 7196            let match_ranges = match_task.await;
 7197            editor
 7198                .update_in(cx, |editor, _, cx| {
 7199                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7200                    if !match_ranges.is_empty() {
 7201                        editor.highlight_background::<SelectedTextHighlight>(
 7202                            &match_ranges,
 7203                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7204                            cx,
 7205                        )
 7206                    }
 7207                })
 7208                .log_err();
 7209        })
 7210    }
 7211
 7212    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7213        struct NewlineFold;
 7214        let type_id = std::any::TypeId::of::<NewlineFold>();
 7215        if !self.mode.is_single_line() {
 7216            return;
 7217        }
 7218        let snapshot = self.snapshot(window, cx);
 7219        if snapshot.buffer_snapshot().max_point().row == 0 {
 7220            return;
 7221        }
 7222        let task = cx.background_spawn(async move {
 7223            let new_newlines = snapshot
 7224                .buffer_chars_at(MultiBufferOffset(0))
 7225                .filter_map(|(c, i)| {
 7226                    if c == '\n' {
 7227                        Some(
 7228                            snapshot.buffer_snapshot().anchor_after(i)
 7229                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7230                        )
 7231                    } else {
 7232                        None
 7233                    }
 7234                })
 7235                .collect::<Vec<_>>();
 7236            let existing_newlines = snapshot
 7237                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7238                .filter_map(|fold| {
 7239                    if fold.placeholder.type_tag == Some(type_id) {
 7240                        Some(fold.range.start..fold.range.end)
 7241                    } else {
 7242                        None
 7243                    }
 7244                })
 7245                .collect::<Vec<_>>();
 7246
 7247            (new_newlines, existing_newlines)
 7248        });
 7249        self.folding_newlines = cx.spawn(async move |this, cx| {
 7250            let (new_newlines, existing_newlines) = task.await;
 7251            if new_newlines == existing_newlines {
 7252                return;
 7253            }
 7254            let placeholder = FoldPlaceholder {
 7255                render: Arc::new(move |_, _, cx| {
 7256                    div()
 7257                        .bg(cx.theme().status().hint_background)
 7258                        .border_b_1()
 7259                        .size_full()
 7260                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7261                        .border_color(cx.theme().status().hint)
 7262                        .child("\\n")
 7263                        .into_any()
 7264                }),
 7265                constrain_width: false,
 7266                merge_adjacent: false,
 7267                type_tag: Some(type_id),
 7268            };
 7269            let creases = new_newlines
 7270                .into_iter()
 7271                .map(|range| Crease::simple(range, placeholder.clone()))
 7272                .collect();
 7273            this.update(cx, |this, cx| {
 7274                this.display_map.update(cx, |display_map, cx| {
 7275                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7276                    display_map.fold(creases, cx);
 7277                });
 7278            })
 7279            .ok();
 7280        });
 7281    }
 7282
 7283    #[ztracing::instrument(skip_all)]
 7284    fn refresh_selected_text_highlights(
 7285        &mut self,
 7286        on_buffer_edit: bool,
 7287        window: &mut Window,
 7288        cx: &mut Context<Editor>,
 7289    ) {
 7290        let Some((query_text, query_range)) =
 7291            self.prepare_highlight_query_from_selection(window, cx)
 7292        else {
 7293            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7294            self.quick_selection_highlight_task.take();
 7295            self.debounced_selection_highlight_task.take();
 7296            return;
 7297        };
 7298        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7299        if on_buffer_edit
 7300            || self
 7301                .quick_selection_highlight_task
 7302                .as_ref()
 7303                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7304        {
 7305            let multi_buffer_visible_start = self
 7306                .scroll_manager
 7307                .anchor()
 7308                .anchor
 7309                .to_point(&multi_buffer_snapshot);
 7310            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7311                multi_buffer_visible_start
 7312                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7313                Bias::Left,
 7314            );
 7315            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7316            self.quick_selection_highlight_task = Some((
 7317                query_range.clone(),
 7318                self.update_selection_occurrence_highlights(
 7319                    query_text.clone(),
 7320                    query_range.clone(),
 7321                    multi_buffer_visible_range,
 7322                    false,
 7323                    window,
 7324                    cx,
 7325                ),
 7326            ));
 7327        }
 7328        if on_buffer_edit
 7329            || self
 7330                .debounced_selection_highlight_task
 7331                .as_ref()
 7332                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7333        {
 7334            let multi_buffer_start = multi_buffer_snapshot
 7335                .anchor_before(MultiBufferOffset(0))
 7336                .to_point(&multi_buffer_snapshot);
 7337            let multi_buffer_end = multi_buffer_snapshot
 7338                .anchor_after(multi_buffer_snapshot.len())
 7339                .to_point(&multi_buffer_snapshot);
 7340            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7341            self.debounced_selection_highlight_task = Some((
 7342                query_range.clone(),
 7343                self.update_selection_occurrence_highlights(
 7344                    query_text,
 7345                    query_range,
 7346                    multi_buffer_full_range,
 7347                    true,
 7348                    window,
 7349                    cx,
 7350                ),
 7351            ));
 7352        }
 7353    }
 7354
 7355    pub fn refresh_edit_prediction(
 7356        &mut self,
 7357        debounce: bool,
 7358        user_requested: bool,
 7359        window: &mut Window,
 7360        cx: &mut Context<Self>,
 7361    ) -> Option<()> {
 7362        if DisableAiSettings::get_global(cx).disable_ai {
 7363            return None;
 7364        }
 7365
 7366        let provider = self.edit_prediction_provider()?;
 7367        let cursor = self.selections.newest_anchor().head();
 7368        let (buffer, cursor_buffer_position) =
 7369            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7370
 7371        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7372            self.discard_edit_prediction(false, cx);
 7373            return None;
 7374        }
 7375
 7376        self.update_visible_edit_prediction(window, cx);
 7377
 7378        if !user_requested
 7379            && (!self.should_show_edit_predictions()
 7380                || !self.is_focused(window)
 7381                || buffer.read(cx).is_empty())
 7382        {
 7383            self.discard_edit_prediction(false, cx);
 7384            return None;
 7385        }
 7386
 7387        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7388        Some(())
 7389    }
 7390
 7391    fn show_edit_predictions_in_menu(&self) -> bool {
 7392        match self.edit_prediction_settings {
 7393            EditPredictionSettings::Disabled => false,
 7394            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7395        }
 7396    }
 7397
 7398    pub fn edit_predictions_enabled(&self) -> bool {
 7399        match self.edit_prediction_settings {
 7400            EditPredictionSettings::Disabled => false,
 7401            EditPredictionSettings::Enabled { .. } => true,
 7402        }
 7403    }
 7404
 7405    fn edit_prediction_requires_modifier(&self) -> bool {
 7406        match self.edit_prediction_settings {
 7407            EditPredictionSettings::Disabled => false,
 7408            EditPredictionSettings::Enabled {
 7409                preview_requires_modifier,
 7410                ..
 7411            } => preview_requires_modifier,
 7412        }
 7413    }
 7414
 7415    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7416        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7417            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7418            self.discard_edit_prediction(false, cx);
 7419        } else {
 7420            let selection = self.selections.newest_anchor();
 7421            let cursor = selection.head();
 7422
 7423            if let Some((buffer, cursor_buffer_position)) =
 7424                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7425            {
 7426                self.edit_prediction_settings =
 7427                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7428            }
 7429        }
 7430    }
 7431
 7432    fn edit_prediction_settings_at_position(
 7433        &self,
 7434        buffer: &Entity<Buffer>,
 7435        buffer_position: language::Anchor,
 7436        cx: &App,
 7437    ) -> EditPredictionSettings {
 7438        if !self.mode.is_full()
 7439            || !self.show_edit_predictions_override.unwrap_or(true)
 7440            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7441        {
 7442            return EditPredictionSettings::Disabled;
 7443        }
 7444
 7445        let buffer = buffer.read(cx);
 7446
 7447        let file = buffer.file();
 7448
 7449        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7450            return EditPredictionSettings::Disabled;
 7451        };
 7452
 7453        let by_provider = matches!(
 7454            self.menu_edit_predictions_policy,
 7455            MenuEditPredictionsPolicy::ByProvider
 7456        );
 7457
 7458        let show_in_menu = by_provider
 7459            && self
 7460                .edit_prediction_provider
 7461                .as_ref()
 7462                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7463
 7464        let preview_requires_modifier =
 7465            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7466
 7467        EditPredictionSettings::Enabled {
 7468            show_in_menu,
 7469            preview_requires_modifier,
 7470        }
 7471    }
 7472
 7473    fn should_show_edit_predictions(&self) -> bool {
 7474        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7475    }
 7476
 7477    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7478        matches!(
 7479            self.edit_prediction_preview,
 7480            EditPredictionPreview::Active { .. }
 7481        )
 7482    }
 7483
 7484    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7485        let cursor = self.selections.newest_anchor().head();
 7486        if let Some((buffer, cursor_position)) =
 7487            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7488        {
 7489            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7490        } else {
 7491            false
 7492        }
 7493    }
 7494
 7495    pub fn supports_minimap(&self, cx: &App) -> bool {
 7496        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7497    }
 7498
 7499    fn edit_predictions_enabled_in_buffer(
 7500        &self,
 7501        buffer: &Entity<Buffer>,
 7502        buffer_position: language::Anchor,
 7503        cx: &App,
 7504    ) -> bool {
 7505        maybe!({
 7506            if self.read_only(cx) {
 7507                return Some(false);
 7508            }
 7509            let provider = self.edit_prediction_provider()?;
 7510            if !provider.is_enabled(buffer, buffer_position, cx) {
 7511                return Some(false);
 7512            }
 7513            let buffer = buffer.read(cx);
 7514            let Some(file) = buffer.file() else {
 7515                return Some(true);
 7516            };
 7517            let settings = all_language_settings(Some(file), cx);
 7518            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7519        })
 7520        .unwrap_or(false)
 7521    }
 7522
 7523    fn cycle_edit_prediction(
 7524        &mut self,
 7525        direction: Direction,
 7526        window: &mut Window,
 7527        cx: &mut Context<Self>,
 7528    ) -> Option<()> {
 7529        let provider = self.edit_prediction_provider()?;
 7530        let cursor = self.selections.newest_anchor().head();
 7531        let (buffer, cursor_buffer_position) =
 7532            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7533        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7534            return None;
 7535        }
 7536
 7537        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7538        self.update_visible_edit_prediction(window, cx);
 7539
 7540        Some(())
 7541    }
 7542
 7543    pub fn show_edit_prediction(
 7544        &mut self,
 7545        _: &ShowEditPrediction,
 7546        window: &mut Window,
 7547        cx: &mut Context<Self>,
 7548    ) {
 7549        if !self.has_active_edit_prediction() {
 7550            self.refresh_edit_prediction(false, true, window, cx);
 7551            return;
 7552        }
 7553
 7554        self.update_visible_edit_prediction(window, cx);
 7555    }
 7556
 7557    pub fn display_cursor_names(
 7558        &mut self,
 7559        _: &DisplayCursorNames,
 7560        window: &mut Window,
 7561        cx: &mut Context<Self>,
 7562    ) {
 7563        self.show_cursor_names(window, cx);
 7564    }
 7565
 7566    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7567        self.show_cursor_names = true;
 7568        cx.notify();
 7569        cx.spawn_in(window, async move |this, cx| {
 7570            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7571            this.update(cx, |this, cx| {
 7572                this.show_cursor_names = false;
 7573                cx.notify()
 7574            })
 7575            .ok()
 7576        })
 7577        .detach();
 7578    }
 7579
 7580    pub fn next_edit_prediction(
 7581        &mut self,
 7582        _: &NextEditPrediction,
 7583        window: &mut Window,
 7584        cx: &mut Context<Self>,
 7585    ) {
 7586        if self.has_active_edit_prediction() {
 7587            self.cycle_edit_prediction(Direction::Next, window, cx);
 7588        } else {
 7589            let is_copilot_disabled = self
 7590                .refresh_edit_prediction(false, true, window, cx)
 7591                .is_none();
 7592            if is_copilot_disabled {
 7593                cx.propagate();
 7594            }
 7595        }
 7596    }
 7597
 7598    pub fn previous_edit_prediction(
 7599        &mut self,
 7600        _: &PreviousEditPrediction,
 7601        window: &mut Window,
 7602        cx: &mut Context<Self>,
 7603    ) {
 7604        if self.has_active_edit_prediction() {
 7605            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7606        } else {
 7607            let is_copilot_disabled = self
 7608                .refresh_edit_prediction(false, true, window, cx)
 7609                .is_none();
 7610            if is_copilot_disabled {
 7611                cx.propagate();
 7612            }
 7613        }
 7614    }
 7615
 7616    pub fn accept_edit_prediction(
 7617        &mut self,
 7618        _: &AcceptEditPrediction,
 7619        window: &mut Window,
 7620        cx: &mut Context<Self>,
 7621    ) {
 7622        if self.show_edit_predictions_in_menu() {
 7623            self.hide_context_menu(window, cx);
 7624        }
 7625
 7626        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7627            return;
 7628        };
 7629
 7630        match &active_edit_prediction.completion {
 7631            EditPrediction::MoveWithin { target, .. } => {
 7632                let target = *target;
 7633
 7634                if let Some(position_map) = &self.last_position_map {
 7635                    if position_map
 7636                        .visible_row_range
 7637                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7638                        || !self.edit_prediction_requires_modifier()
 7639                    {
 7640                        self.unfold_ranges(&[target..target], true, false, cx);
 7641                        // Note that this is also done in vim's handler of the Tab action.
 7642                        self.change_selections(
 7643                            SelectionEffects::scroll(Autoscroll::newest()),
 7644                            window,
 7645                            cx,
 7646                            |selections| {
 7647                                selections.select_anchor_ranges([target..target]);
 7648                            },
 7649                        );
 7650                        self.clear_row_highlights::<EditPredictionPreview>();
 7651
 7652                        self.edit_prediction_preview
 7653                            .set_previous_scroll_position(None);
 7654                    } else {
 7655                        self.edit_prediction_preview
 7656                            .set_previous_scroll_position(Some(
 7657                                position_map.snapshot.scroll_anchor,
 7658                            ));
 7659
 7660                        self.highlight_rows::<EditPredictionPreview>(
 7661                            target..target,
 7662                            cx.theme().colors().editor_highlighted_line_background,
 7663                            RowHighlightOptions {
 7664                                autoscroll: true,
 7665                                ..Default::default()
 7666                            },
 7667                            cx,
 7668                        );
 7669                        self.request_autoscroll(Autoscroll::fit(), cx);
 7670                    }
 7671                }
 7672            }
 7673            EditPrediction::MoveOutside { snapshot, target } => {
 7674                if let Some(workspace) = self.workspace() {
 7675                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7676                        .detach_and_log_err(cx);
 7677                }
 7678            }
 7679            EditPrediction::Edit { edits, .. } => {
 7680                self.report_edit_prediction_event(
 7681                    active_edit_prediction.completion_id.clone(),
 7682                    true,
 7683                    cx,
 7684                );
 7685
 7686                if let Some(provider) = self.edit_prediction_provider() {
 7687                    provider.accept(cx);
 7688                }
 7689
 7690                // Store the transaction ID and selections before applying the edit
 7691                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7692
 7693                let snapshot = self.buffer.read(cx).snapshot(cx);
 7694                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7695
 7696                self.buffer.update(cx, |buffer, cx| {
 7697                    buffer.edit(edits.iter().cloned(), None, cx)
 7698                });
 7699
 7700                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7701                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7702                });
 7703
 7704                let selections = self.selections.disjoint_anchors_arc();
 7705                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7706                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7707                    if has_new_transaction {
 7708                        self.selection_history
 7709                            .insert_transaction(transaction_id_now, selections);
 7710                    }
 7711                }
 7712
 7713                self.update_visible_edit_prediction(window, cx);
 7714                if self.active_edit_prediction.is_none() {
 7715                    self.refresh_edit_prediction(true, true, window, cx);
 7716                }
 7717
 7718                cx.notify();
 7719            }
 7720        }
 7721
 7722        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7723    }
 7724
 7725    pub fn accept_partial_edit_prediction(
 7726        &mut self,
 7727        _: &AcceptPartialEditPrediction,
 7728        window: &mut Window,
 7729        cx: &mut Context<Self>,
 7730    ) {
 7731        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7732            return;
 7733        };
 7734        if self.selections.count() != 1 {
 7735            return;
 7736        }
 7737
 7738        match &active_edit_prediction.completion {
 7739            EditPrediction::MoveWithin { target, .. } => {
 7740                let target = *target;
 7741                self.change_selections(
 7742                    SelectionEffects::scroll(Autoscroll::newest()),
 7743                    window,
 7744                    cx,
 7745                    |selections| {
 7746                        selections.select_anchor_ranges([target..target]);
 7747                    },
 7748                );
 7749            }
 7750            EditPrediction::MoveOutside { snapshot, target } => {
 7751                if let Some(workspace) = self.workspace() {
 7752                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7753                        .detach_and_log_err(cx);
 7754                }
 7755            }
 7756            EditPrediction::Edit { edits, .. } => {
 7757                self.report_edit_prediction_event(
 7758                    active_edit_prediction.completion_id.clone(),
 7759                    true,
 7760                    cx,
 7761                );
 7762
 7763                // Find an insertion that starts at the cursor position.
 7764                let snapshot = self.buffer.read(cx).snapshot(cx);
 7765                let cursor_offset = self
 7766                    .selections
 7767                    .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7768                    .head();
 7769                let insertion = edits.iter().find_map(|(range, text)| {
 7770                    let range = range.to_offset(&snapshot);
 7771                    if range.is_empty() && range.start == cursor_offset {
 7772                        Some(text)
 7773                    } else {
 7774                        None
 7775                    }
 7776                });
 7777
 7778                if let Some(text) = insertion {
 7779                    let mut partial_completion = text
 7780                        .chars()
 7781                        .by_ref()
 7782                        .take_while(|c| c.is_alphabetic())
 7783                        .collect::<String>();
 7784                    if partial_completion.is_empty() {
 7785                        partial_completion = text
 7786                            .chars()
 7787                            .by_ref()
 7788                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7789                            .collect::<String>();
 7790                    }
 7791
 7792                    cx.emit(EditorEvent::InputHandled {
 7793                        utf16_range_to_replace: None,
 7794                        text: partial_completion.clone().into(),
 7795                    });
 7796
 7797                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7798
 7799                    self.refresh_edit_prediction(true, true, window, cx);
 7800                    cx.notify();
 7801                } else {
 7802                    self.accept_edit_prediction(&Default::default(), window, cx);
 7803                }
 7804            }
 7805        }
 7806    }
 7807
 7808    fn discard_edit_prediction(
 7809        &mut self,
 7810        should_report_edit_prediction_event: bool,
 7811        cx: &mut Context<Self>,
 7812    ) -> bool {
 7813        if should_report_edit_prediction_event {
 7814            let completion_id = self
 7815                .active_edit_prediction
 7816                .as_ref()
 7817                .and_then(|active_completion| active_completion.completion_id.clone());
 7818
 7819            self.report_edit_prediction_event(completion_id, false, cx);
 7820        }
 7821
 7822        if let Some(provider) = self.edit_prediction_provider() {
 7823            provider.discard(cx);
 7824        }
 7825
 7826        self.take_active_edit_prediction(cx)
 7827    }
 7828
 7829    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7830        let Some(provider) = self.edit_prediction_provider() else {
 7831            return;
 7832        };
 7833
 7834        let Some((_, buffer, _)) = self
 7835            .buffer
 7836            .read(cx)
 7837            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7838        else {
 7839            return;
 7840        };
 7841
 7842        let extension = buffer
 7843            .read(cx)
 7844            .file()
 7845            .and_then(|file| Some(file.path().extension()?.to_string()));
 7846
 7847        let event_type = match accepted {
 7848            true => "Edit Prediction Accepted",
 7849            false => "Edit Prediction Discarded",
 7850        };
 7851        telemetry::event!(
 7852            event_type,
 7853            provider = provider.name(),
 7854            prediction_id = id,
 7855            suggestion_accepted = accepted,
 7856            file_extension = extension,
 7857        );
 7858    }
 7859
 7860    fn open_editor_at_anchor(
 7861        snapshot: &language::BufferSnapshot,
 7862        target: language::Anchor,
 7863        workspace: &Entity<Workspace>,
 7864        window: &mut Window,
 7865        cx: &mut App,
 7866    ) -> Task<Result<()>> {
 7867        workspace.update(cx, |workspace, cx| {
 7868            let path = snapshot.file().map(|file| file.full_path(cx));
 7869            let Some(path) =
 7870                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7871            else {
 7872                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7873            };
 7874            let target = text::ToPoint::to_point(&target, snapshot);
 7875            let item = workspace.open_path(path, None, true, window, cx);
 7876            window.spawn(cx, async move |cx| {
 7877                let Some(editor) = item.await?.downcast::<Editor>() else {
 7878                    return Ok(());
 7879                };
 7880                editor
 7881                    .update_in(cx, |editor, window, cx| {
 7882                        editor.go_to_singleton_buffer_point(target, window, cx);
 7883                    })
 7884                    .ok();
 7885                anyhow::Ok(())
 7886            })
 7887        })
 7888    }
 7889
 7890    pub fn has_active_edit_prediction(&self) -> bool {
 7891        self.active_edit_prediction.is_some()
 7892    }
 7893
 7894    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7895        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7896            return false;
 7897        };
 7898
 7899        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7900        self.clear_highlights::<EditPredictionHighlight>(cx);
 7901        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7902        true
 7903    }
 7904
 7905    /// Returns true when we're displaying the edit prediction popover below the cursor
 7906    /// like we are not previewing and the LSP autocomplete menu is visible
 7907    /// or we are in `when_holding_modifier` mode.
 7908    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7909        if self.edit_prediction_preview_is_active()
 7910            || !self.show_edit_predictions_in_menu()
 7911            || !self.edit_predictions_enabled()
 7912        {
 7913            return false;
 7914        }
 7915
 7916        if self.has_visible_completions_menu() {
 7917            return true;
 7918        }
 7919
 7920        has_completion && self.edit_prediction_requires_modifier()
 7921    }
 7922
 7923    fn handle_modifiers_changed(
 7924        &mut self,
 7925        modifiers: Modifiers,
 7926        position_map: &PositionMap,
 7927        window: &mut Window,
 7928        cx: &mut Context<Self>,
 7929    ) {
 7930        // Ensure that the edit prediction preview is updated, even when not
 7931        // enabled, if there's an active edit prediction preview.
 7932        if self.show_edit_predictions_in_menu()
 7933            || matches!(
 7934                self.edit_prediction_preview,
 7935                EditPredictionPreview::Active { .. }
 7936            )
 7937        {
 7938            self.update_edit_prediction_preview(&modifiers, window, cx);
 7939        }
 7940
 7941        self.update_selection_mode(&modifiers, position_map, window, cx);
 7942
 7943        let mouse_position = window.mouse_position();
 7944        if !position_map.text_hitbox.is_hovered(window) {
 7945            return;
 7946        }
 7947
 7948        self.update_hovered_link(
 7949            position_map.point_for_position(mouse_position),
 7950            &position_map.snapshot,
 7951            modifiers,
 7952            window,
 7953            cx,
 7954        )
 7955    }
 7956
 7957    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7958        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7959            MultiCursorModifier::Alt => modifiers.secondary(),
 7960            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7961        }
 7962    }
 7963
 7964    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7965        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7966            MultiCursorModifier::Alt => modifiers.alt,
 7967            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7968        }
 7969    }
 7970
 7971    fn columnar_selection_mode(
 7972        modifiers: &Modifiers,
 7973        cx: &mut Context<Self>,
 7974    ) -> Option<ColumnarMode> {
 7975        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7976            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7977                Some(ColumnarMode::FromMouse)
 7978            } else if Self::is_alt_pressed(modifiers, cx) {
 7979                Some(ColumnarMode::FromSelection)
 7980            } else {
 7981                None
 7982            }
 7983        } else {
 7984            None
 7985        }
 7986    }
 7987
 7988    fn update_selection_mode(
 7989        &mut self,
 7990        modifiers: &Modifiers,
 7991        position_map: &PositionMap,
 7992        window: &mut Window,
 7993        cx: &mut Context<Self>,
 7994    ) {
 7995        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7996            return;
 7997        };
 7998        if self.selections.pending_anchor().is_none() {
 7999            return;
 8000        }
 8001
 8002        let mouse_position = window.mouse_position();
 8003        let point_for_position = position_map.point_for_position(mouse_position);
 8004        let position = point_for_position.previous_valid;
 8005
 8006        self.select(
 8007            SelectPhase::BeginColumnar {
 8008                position,
 8009                reset: false,
 8010                mode,
 8011                goal_column: point_for_position.exact_unclipped.column(),
 8012            },
 8013            window,
 8014            cx,
 8015        );
 8016    }
 8017
 8018    fn update_edit_prediction_preview(
 8019        &mut self,
 8020        modifiers: &Modifiers,
 8021        window: &mut Window,
 8022        cx: &mut Context<Self>,
 8023    ) {
 8024        let mut modifiers_held = false;
 8025        if let Some(accept_keystroke) = self
 8026            .accept_edit_prediction_keybind(false, window, cx)
 8027            .keystroke()
 8028        {
 8029            modifiers_held = modifiers_held
 8030                || (accept_keystroke.modifiers() == modifiers
 8031                    && accept_keystroke.modifiers().modified());
 8032        };
 8033        if let Some(accept_partial_keystroke) = self
 8034            .accept_edit_prediction_keybind(true, window, cx)
 8035            .keystroke()
 8036        {
 8037            modifiers_held = modifiers_held
 8038                || (accept_partial_keystroke.modifiers() == modifiers
 8039                    && accept_partial_keystroke.modifiers().modified());
 8040        }
 8041
 8042        if modifiers_held {
 8043            if matches!(
 8044                self.edit_prediction_preview,
 8045                EditPredictionPreview::Inactive { .. }
 8046            ) {
 8047                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 8048                    provider.provider.did_show(cx)
 8049                }
 8050
 8051                self.edit_prediction_preview = EditPredictionPreview::Active {
 8052                    previous_scroll_position: None,
 8053                    since: Instant::now(),
 8054                };
 8055
 8056                self.update_visible_edit_prediction(window, cx);
 8057                cx.notify();
 8058            }
 8059        } else if let EditPredictionPreview::Active {
 8060            previous_scroll_position,
 8061            since,
 8062        } = self.edit_prediction_preview
 8063        {
 8064            if let (Some(previous_scroll_position), Some(position_map)) =
 8065                (previous_scroll_position, self.last_position_map.as_ref())
 8066            {
 8067                self.set_scroll_position(
 8068                    previous_scroll_position
 8069                        .scroll_position(&position_map.snapshot.display_snapshot),
 8070                    window,
 8071                    cx,
 8072                );
 8073            }
 8074
 8075            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8076                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8077            };
 8078            self.clear_row_highlights::<EditPredictionPreview>();
 8079            self.update_visible_edit_prediction(window, cx);
 8080            cx.notify();
 8081        }
 8082    }
 8083
 8084    fn update_visible_edit_prediction(
 8085        &mut self,
 8086        _window: &mut Window,
 8087        cx: &mut Context<Self>,
 8088    ) -> Option<()> {
 8089        if DisableAiSettings::get_global(cx).disable_ai {
 8090            return None;
 8091        }
 8092
 8093        if self.ime_transaction.is_some() {
 8094            self.discard_edit_prediction(false, cx);
 8095            return None;
 8096        }
 8097
 8098        let selection = self.selections.newest_anchor();
 8099        let cursor = selection.head();
 8100        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8101        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8102        let excerpt_id = cursor.excerpt_id;
 8103
 8104        let show_in_menu = self.show_edit_predictions_in_menu();
 8105        let completions_menu_has_precedence = !show_in_menu
 8106            && (self.context_menu.borrow().is_some()
 8107                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8108
 8109        if completions_menu_has_precedence
 8110            || !offset_selection.is_empty()
 8111            || self
 8112                .active_edit_prediction
 8113                .as_ref()
 8114                .is_some_and(|completion| {
 8115                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8116                        return false;
 8117                    };
 8118                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8119                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8120                    !invalidation_range.contains(&offset_selection.head())
 8121                })
 8122        {
 8123            self.discard_edit_prediction(false, cx);
 8124            return None;
 8125        }
 8126
 8127        self.take_active_edit_prediction(cx);
 8128        let Some(provider) = self.edit_prediction_provider() else {
 8129            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8130            return None;
 8131        };
 8132
 8133        let (buffer, cursor_buffer_position) =
 8134            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8135
 8136        self.edit_prediction_settings =
 8137            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8138
 8139        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8140
 8141        if self.edit_prediction_indent_conflict {
 8142            let cursor_point = cursor.to_point(&multibuffer);
 8143            let mut suggested_indent = None;
 8144            multibuffer.suggested_indents_callback(
 8145                cursor_point.row..cursor_point.row + 1,
 8146                |_, indent| {
 8147                    suggested_indent = Some(indent);
 8148                    ControlFlow::Break(())
 8149                },
 8150                cx,
 8151            );
 8152
 8153            if let Some(indent) = suggested_indent
 8154                && indent.len == cursor_point.column
 8155            {
 8156                self.edit_prediction_indent_conflict = false;
 8157            }
 8158        }
 8159
 8160        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8161
 8162        let (completion_id, edits, edit_preview) = match edit_prediction {
 8163            edit_prediction_types::EditPrediction::Local {
 8164                id,
 8165                edits,
 8166                edit_preview,
 8167            } => (id, edits, edit_preview),
 8168            edit_prediction_types::EditPrediction::Jump {
 8169                id,
 8170                snapshot,
 8171                target,
 8172            } => {
 8173                self.stale_edit_prediction_in_menu = None;
 8174                self.active_edit_prediction = Some(EditPredictionState {
 8175                    inlay_ids: vec![],
 8176                    completion: EditPrediction::MoveOutside { snapshot, target },
 8177                    completion_id: id,
 8178                    invalidation_range: None,
 8179                });
 8180                cx.notify();
 8181                return Some(());
 8182            }
 8183        };
 8184
 8185        let edits = edits
 8186            .into_iter()
 8187            .flat_map(|(range, new_text)| {
 8188                Some((
 8189                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8190                    new_text,
 8191                ))
 8192            })
 8193            .collect::<Vec<_>>();
 8194        if edits.is_empty() {
 8195            return None;
 8196        }
 8197
 8198        let first_edit_start = edits.first().unwrap().0.start;
 8199        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8200        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8201
 8202        let last_edit_end = edits.last().unwrap().0.end;
 8203        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8204        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8205
 8206        let cursor_row = cursor.to_point(&multibuffer).row;
 8207
 8208        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8209
 8210        let mut inlay_ids = Vec::new();
 8211        let invalidation_row_range;
 8212        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8213            Some(cursor_row..edit_end_row)
 8214        } else if cursor_row > edit_end_row {
 8215            Some(edit_start_row..cursor_row)
 8216        } else {
 8217            None
 8218        };
 8219        let supports_jump = self
 8220            .edit_prediction_provider
 8221            .as_ref()
 8222            .map(|provider| provider.provider.supports_jump_to_edit())
 8223            .unwrap_or(true);
 8224
 8225        let is_move = supports_jump
 8226            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8227        let completion = if is_move {
 8228            invalidation_row_range =
 8229                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8230            let target = first_edit_start;
 8231            EditPrediction::MoveWithin { target, snapshot }
 8232        } else {
 8233            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8234                && !self.edit_predictions_hidden_for_vim_mode;
 8235
 8236            if show_completions_in_buffer {
 8237                if let Some(provider) = &self.edit_prediction_provider {
 8238                    provider.provider.did_show(cx);
 8239                }
 8240                if edits
 8241                    .iter()
 8242                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8243                {
 8244                    let mut inlays = Vec::new();
 8245                    for (range, new_text) in &edits {
 8246                        let inlay = Inlay::edit_prediction(
 8247                            post_inc(&mut self.next_inlay_id),
 8248                            range.start,
 8249                            new_text.as_ref(),
 8250                        );
 8251                        inlay_ids.push(inlay.id);
 8252                        inlays.push(inlay);
 8253                    }
 8254
 8255                    self.splice_inlays(&[], inlays, cx);
 8256                } else {
 8257                    let background_color = cx.theme().status().deleted_background;
 8258                    self.highlight_text::<EditPredictionHighlight>(
 8259                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8260                        HighlightStyle {
 8261                            background_color: Some(background_color),
 8262                            ..Default::default()
 8263                        },
 8264                        cx,
 8265                    );
 8266                }
 8267            }
 8268
 8269            invalidation_row_range = edit_start_row..edit_end_row;
 8270
 8271            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8272                if provider.show_tab_accept_marker() {
 8273                    EditDisplayMode::TabAccept
 8274                } else {
 8275                    EditDisplayMode::Inline
 8276                }
 8277            } else {
 8278                EditDisplayMode::DiffPopover
 8279            };
 8280
 8281            EditPrediction::Edit {
 8282                edits,
 8283                edit_preview,
 8284                display_mode,
 8285                snapshot,
 8286            }
 8287        };
 8288
 8289        let invalidation_range = multibuffer
 8290            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8291            ..multibuffer.anchor_after(Point::new(
 8292                invalidation_row_range.end,
 8293                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8294            ));
 8295
 8296        self.stale_edit_prediction_in_menu = None;
 8297        self.active_edit_prediction = Some(EditPredictionState {
 8298            inlay_ids,
 8299            completion,
 8300            completion_id,
 8301            invalidation_range: Some(invalidation_range),
 8302        });
 8303
 8304        cx.notify();
 8305
 8306        Some(())
 8307    }
 8308
 8309    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8310        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8311    }
 8312
 8313    fn clear_tasks(&mut self) {
 8314        self.tasks.clear()
 8315    }
 8316
 8317    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8318        if self.tasks.insert(key, value).is_some() {
 8319            // This case should hopefully be rare, but just in case...
 8320            log::error!(
 8321                "multiple different run targets found on a single line, only the last target will be rendered"
 8322            )
 8323        }
 8324    }
 8325
 8326    /// Get all display points of breakpoints that will be rendered within editor
 8327    ///
 8328    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8329    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8330    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8331    fn active_breakpoints(
 8332        &self,
 8333        range: Range<DisplayRow>,
 8334        window: &mut Window,
 8335        cx: &mut Context<Self>,
 8336    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8337        let mut breakpoint_display_points = HashMap::default();
 8338
 8339        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8340            return breakpoint_display_points;
 8341        };
 8342
 8343        let snapshot = self.snapshot(window, cx);
 8344
 8345        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8346        let Some(project) = self.project() else {
 8347            return breakpoint_display_points;
 8348        };
 8349
 8350        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8351            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8352
 8353        for (buffer_snapshot, range, excerpt_id) in
 8354            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8355        {
 8356            let Some(buffer) = project
 8357                .read(cx)
 8358                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8359            else {
 8360                continue;
 8361            };
 8362            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8363                &buffer,
 8364                Some(
 8365                    buffer_snapshot.anchor_before(range.start)
 8366                        ..buffer_snapshot.anchor_after(range.end),
 8367                ),
 8368                buffer_snapshot,
 8369                cx,
 8370            );
 8371            for (breakpoint, state) in breakpoints {
 8372                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8373                let position = multi_buffer_anchor
 8374                    .to_point(&multi_buffer_snapshot)
 8375                    .to_display_point(&snapshot);
 8376
 8377                breakpoint_display_points.insert(
 8378                    position.row(),
 8379                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8380                );
 8381            }
 8382        }
 8383
 8384        breakpoint_display_points
 8385    }
 8386
 8387    fn breakpoint_context_menu(
 8388        &self,
 8389        anchor: Anchor,
 8390        window: &mut Window,
 8391        cx: &mut Context<Self>,
 8392    ) -> Entity<ui::ContextMenu> {
 8393        let weak_editor = cx.weak_entity();
 8394        let focus_handle = self.focus_handle(cx);
 8395
 8396        let row = self
 8397            .buffer
 8398            .read(cx)
 8399            .snapshot(cx)
 8400            .summary_for_anchor::<Point>(&anchor)
 8401            .row;
 8402
 8403        let breakpoint = self
 8404            .breakpoint_at_row(row, window, cx)
 8405            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8406
 8407        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8408            "Edit Log Breakpoint"
 8409        } else {
 8410            "Set Log Breakpoint"
 8411        };
 8412
 8413        let condition_breakpoint_msg = if breakpoint
 8414            .as_ref()
 8415            .is_some_and(|bp| bp.1.condition.is_some())
 8416        {
 8417            "Edit Condition Breakpoint"
 8418        } else {
 8419            "Set Condition Breakpoint"
 8420        };
 8421
 8422        let hit_condition_breakpoint_msg = if breakpoint
 8423            .as_ref()
 8424            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8425        {
 8426            "Edit Hit Condition Breakpoint"
 8427        } else {
 8428            "Set Hit Condition Breakpoint"
 8429        };
 8430
 8431        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8432            "Unset Breakpoint"
 8433        } else {
 8434            "Set Breakpoint"
 8435        };
 8436
 8437        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8438
 8439        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8440            BreakpointState::Enabled => Some("Disable"),
 8441            BreakpointState::Disabled => Some("Enable"),
 8442        });
 8443
 8444        let (anchor, breakpoint) =
 8445            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8446
 8447        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8448            menu.on_blur_subscription(Subscription::new(|| {}))
 8449                .context(focus_handle)
 8450                .when(run_to_cursor, |this| {
 8451                    let weak_editor = weak_editor.clone();
 8452                    this.entry("Run to cursor", None, move |window, cx| {
 8453                        weak_editor
 8454                            .update(cx, |editor, cx| {
 8455                                editor.change_selections(
 8456                                    SelectionEffects::no_scroll(),
 8457                                    window,
 8458                                    cx,
 8459                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8460                                );
 8461                            })
 8462                            .ok();
 8463
 8464                        window.dispatch_action(Box::new(RunToCursor), cx);
 8465                    })
 8466                    .separator()
 8467                })
 8468                .when_some(toggle_state_msg, |this, msg| {
 8469                    this.entry(msg, None, {
 8470                        let weak_editor = weak_editor.clone();
 8471                        let breakpoint = breakpoint.clone();
 8472                        move |_window, cx| {
 8473                            weak_editor
 8474                                .update(cx, |this, cx| {
 8475                                    this.edit_breakpoint_at_anchor(
 8476                                        anchor,
 8477                                        breakpoint.as_ref().clone(),
 8478                                        BreakpointEditAction::InvertState,
 8479                                        cx,
 8480                                    );
 8481                                })
 8482                                .log_err();
 8483                        }
 8484                    })
 8485                })
 8486                .entry(set_breakpoint_msg, None, {
 8487                    let weak_editor = weak_editor.clone();
 8488                    let breakpoint = breakpoint.clone();
 8489                    move |_window, cx| {
 8490                        weak_editor
 8491                            .update(cx, |this, cx| {
 8492                                this.edit_breakpoint_at_anchor(
 8493                                    anchor,
 8494                                    breakpoint.as_ref().clone(),
 8495                                    BreakpointEditAction::Toggle,
 8496                                    cx,
 8497                                );
 8498                            })
 8499                            .log_err();
 8500                    }
 8501                })
 8502                .entry(log_breakpoint_msg, None, {
 8503                    let breakpoint = breakpoint.clone();
 8504                    let weak_editor = weak_editor.clone();
 8505                    move |window, cx| {
 8506                        weak_editor
 8507                            .update(cx, |this, cx| {
 8508                                this.add_edit_breakpoint_block(
 8509                                    anchor,
 8510                                    breakpoint.as_ref(),
 8511                                    BreakpointPromptEditAction::Log,
 8512                                    window,
 8513                                    cx,
 8514                                );
 8515                            })
 8516                            .log_err();
 8517                    }
 8518                })
 8519                .entry(condition_breakpoint_msg, None, {
 8520                    let breakpoint = breakpoint.clone();
 8521                    let weak_editor = weak_editor.clone();
 8522                    move |window, cx| {
 8523                        weak_editor
 8524                            .update(cx, |this, cx| {
 8525                                this.add_edit_breakpoint_block(
 8526                                    anchor,
 8527                                    breakpoint.as_ref(),
 8528                                    BreakpointPromptEditAction::Condition,
 8529                                    window,
 8530                                    cx,
 8531                                );
 8532                            })
 8533                            .log_err();
 8534                    }
 8535                })
 8536                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8537                    weak_editor
 8538                        .update(cx, |this, cx| {
 8539                            this.add_edit_breakpoint_block(
 8540                                anchor,
 8541                                breakpoint.as_ref(),
 8542                                BreakpointPromptEditAction::HitCondition,
 8543                                window,
 8544                                cx,
 8545                            );
 8546                        })
 8547                        .log_err();
 8548                })
 8549        })
 8550    }
 8551
 8552    fn render_breakpoint(
 8553        &self,
 8554        position: Anchor,
 8555        row: DisplayRow,
 8556        breakpoint: &Breakpoint,
 8557        state: Option<BreakpointSessionState>,
 8558        cx: &mut Context<Self>,
 8559    ) -> IconButton {
 8560        let is_rejected = state.is_some_and(|s| !s.verified);
 8561        // Is it a breakpoint that shows up when hovering over gutter?
 8562        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8563            (false, false),
 8564            |PhantomBreakpointIndicator {
 8565                 is_active,
 8566                 display_row,
 8567                 collides_with_existing_breakpoint,
 8568             }| {
 8569                (
 8570                    is_active && display_row == row,
 8571                    collides_with_existing_breakpoint,
 8572                )
 8573            },
 8574        );
 8575
 8576        let (color, icon) = {
 8577            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8578                (false, false) => ui::IconName::DebugBreakpoint,
 8579                (true, false) => ui::IconName::DebugLogBreakpoint,
 8580                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8581                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8582            };
 8583
 8584            let color = cx.theme().colors();
 8585
 8586            let color = if is_phantom {
 8587                if collides_with_existing {
 8588                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8589                } else {
 8590                    Color::Hint
 8591                }
 8592            } else if is_rejected {
 8593                Color::Disabled
 8594            } else {
 8595                Color::Debugger
 8596            };
 8597
 8598            (color, icon)
 8599        };
 8600
 8601        let breakpoint = Arc::from(breakpoint.clone());
 8602
 8603        let alt_as_text = gpui::Keystroke {
 8604            modifiers: Modifiers::secondary_key(),
 8605            ..Default::default()
 8606        };
 8607        let primary_action_text = if breakpoint.is_disabled() {
 8608            "Enable breakpoint"
 8609        } else if is_phantom && !collides_with_existing {
 8610            "Set breakpoint"
 8611        } else {
 8612            "Unset breakpoint"
 8613        };
 8614        let focus_handle = self.focus_handle.clone();
 8615
 8616        let meta = if is_rejected {
 8617            SharedString::from("No executable code is associated with this line.")
 8618        } else if collides_with_existing && !breakpoint.is_disabled() {
 8619            SharedString::from(format!(
 8620                "{alt_as_text}-click to disable,\nright-click for more options."
 8621            ))
 8622        } else {
 8623            SharedString::from("Right-click for more options.")
 8624        };
 8625        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8626            .icon_size(IconSize::XSmall)
 8627            .size(ui::ButtonSize::None)
 8628            .when(is_rejected, |this| {
 8629                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8630            })
 8631            .icon_color(color)
 8632            .style(ButtonStyle::Transparent)
 8633            .on_click(cx.listener({
 8634                move |editor, event: &ClickEvent, window, cx| {
 8635                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8636                        BreakpointEditAction::InvertState
 8637                    } else {
 8638                        BreakpointEditAction::Toggle
 8639                    };
 8640
 8641                    window.focus(&editor.focus_handle(cx));
 8642                    editor.edit_breakpoint_at_anchor(
 8643                        position,
 8644                        breakpoint.as_ref().clone(),
 8645                        edit_action,
 8646                        cx,
 8647                    );
 8648                }
 8649            }))
 8650            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8651                editor.set_breakpoint_context_menu(
 8652                    row,
 8653                    Some(position),
 8654                    event.position(),
 8655                    window,
 8656                    cx,
 8657                );
 8658            }))
 8659            .tooltip(move |_window, cx| {
 8660                Tooltip::with_meta_in(
 8661                    primary_action_text,
 8662                    Some(&ToggleBreakpoint),
 8663                    meta.clone(),
 8664                    &focus_handle,
 8665                    cx,
 8666                )
 8667            })
 8668    }
 8669
 8670    fn build_tasks_context(
 8671        project: &Entity<Project>,
 8672        buffer: &Entity<Buffer>,
 8673        buffer_row: u32,
 8674        tasks: &Arc<RunnableTasks>,
 8675        cx: &mut Context<Self>,
 8676    ) -> Task<Option<task::TaskContext>> {
 8677        let position = Point::new(buffer_row, tasks.column);
 8678        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8679        let location = Location {
 8680            buffer: buffer.clone(),
 8681            range: range_start..range_start,
 8682        };
 8683        // Fill in the environmental variables from the tree-sitter captures
 8684        let mut captured_task_variables = TaskVariables::default();
 8685        for (capture_name, value) in tasks.extra_variables.clone() {
 8686            captured_task_variables.insert(
 8687                task::VariableName::Custom(capture_name.into()),
 8688                value.clone(),
 8689            );
 8690        }
 8691        project.update(cx, |project, cx| {
 8692            project.task_store().update(cx, |task_store, cx| {
 8693                task_store.task_context_for_location(captured_task_variables, location, cx)
 8694            })
 8695        })
 8696    }
 8697
 8698    pub fn spawn_nearest_task(
 8699        &mut self,
 8700        action: &SpawnNearestTask,
 8701        window: &mut Window,
 8702        cx: &mut Context<Self>,
 8703    ) {
 8704        let Some((workspace, _)) = self.workspace.clone() else {
 8705            return;
 8706        };
 8707        let Some(project) = self.project.clone() else {
 8708            return;
 8709        };
 8710
 8711        // Try to find a closest, enclosing node using tree-sitter that has a task
 8712        let Some((buffer, buffer_row, tasks)) = self
 8713            .find_enclosing_node_task(cx)
 8714            // Or find the task that's closest in row-distance.
 8715            .or_else(|| self.find_closest_task(cx))
 8716        else {
 8717            return;
 8718        };
 8719
 8720        let reveal_strategy = action.reveal;
 8721        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8722        cx.spawn_in(window, async move |_, cx| {
 8723            let context = task_context.await?;
 8724            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8725
 8726            let resolved = &mut resolved_task.resolved;
 8727            resolved.reveal = reveal_strategy;
 8728
 8729            workspace
 8730                .update_in(cx, |workspace, window, cx| {
 8731                    workspace.schedule_resolved_task(
 8732                        task_source_kind,
 8733                        resolved_task,
 8734                        false,
 8735                        window,
 8736                        cx,
 8737                    );
 8738                })
 8739                .ok()
 8740        })
 8741        .detach();
 8742    }
 8743
 8744    fn find_closest_task(
 8745        &mut self,
 8746        cx: &mut Context<Self>,
 8747    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8748        let cursor_row = self
 8749            .selections
 8750            .newest_adjusted(&self.display_snapshot(cx))
 8751            .head()
 8752            .row;
 8753
 8754        let ((buffer_id, row), tasks) = self
 8755            .tasks
 8756            .iter()
 8757            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8758
 8759        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8760        let tasks = Arc::new(tasks.to_owned());
 8761        Some((buffer, *row, tasks))
 8762    }
 8763
 8764    fn find_enclosing_node_task(
 8765        &mut self,
 8766        cx: &mut Context<Self>,
 8767    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8768        let snapshot = self.buffer.read(cx).snapshot(cx);
 8769        let offset = self
 8770            .selections
 8771            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8772            .head();
 8773        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8774        let offset = excerpt.map_offset_to_buffer(offset);
 8775        let buffer_id = excerpt.buffer().remote_id();
 8776
 8777        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8778        let mut cursor = layer.node().walk();
 8779
 8780        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8781            if cursor.node().end_byte() == offset.0 {
 8782                cursor.goto_next_sibling();
 8783            }
 8784        }
 8785
 8786        // Ascend to the smallest ancestor that contains the range and has a task.
 8787        loop {
 8788            let node = cursor.node();
 8789            let node_range = node.byte_range();
 8790            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8791
 8792            // Check if this node contains our offset
 8793            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8794                // If it contains offset, check for task
 8795                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8796                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8797                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8798                }
 8799            }
 8800
 8801            if !cursor.goto_parent() {
 8802                break;
 8803            }
 8804        }
 8805        None
 8806    }
 8807
 8808    fn render_run_indicator(
 8809        &self,
 8810        _style: &EditorStyle,
 8811        is_active: bool,
 8812        row: DisplayRow,
 8813        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8814        cx: &mut Context<Self>,
 8815    ) -> IconButton {
 8816        let color = Color::Muted;
 8817        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8818
 8819        IconButton::new(
 8820            ("run_indicator", row.0 as usize),
 8821            ui::IconName::PlayOutlined,
 8822        )
 8823        .shape(ui::IconButtonShape::Square)
 8824        .icon_size(IconSize::XSmall)
 8825        .icon_color(color)
 8826        .toggle_state(is_active)
 8827        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8828            let quick_launch = match e {
 8829                ClickEvent::Keyboard(_) => true,
 8830                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8831            };
 8832
 8833            window.focus(&editor.focus_handle(cx));
 8834            editor.toggle_code_actions(
 8835                &ToggleCodeActions {
 8836                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8837                    quick_launch,
 8838                },
 8839                window,
 8840                cx,
 8841            );
 8842        }))
 8843        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8844            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8845        }))
 8846    }
 8847
 8848    pub fn context_menu_visible(&self) -> bool {
 8849        !self.edit_prediction_preview_is_active()
 8850            && self
 8851                .context_menu
 8852                .borrow()
 8853                .as_ref()
 8854                .is_some_and(|menu| menu.visible())
 8855    }
 8856
 8857    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8858        self.context_menu
 8859            .borrow()
 8860            .as_ref()
 8861            .map(|menu| menu.origin())
 8862    }
 8863
 8864    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8865        self.context_menu_options = Some(options);
 8866    }
 8867
 8868    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8869    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8870
 8871    fn render_edit_prediction_popover(
 8872        &mut self,
 8873        text_bounds: &Bounds<Pixels>,
 8874        content_origin: gpui::Point<Pixels>,
 8875        right_margin: Pixels,
 8876        editor_snapshot: &EditorSnapshot,
 8877        visible_row_range: Range<DisplayRow>,
 8878        scroll_top: ScrollOffset,
 8879        scroll_bottom: ScrollOffset,
 8880        line_layouts: &[LineWithInvisibles],
 8881        line_height: Pixels,
 8882        scroll_position: gpui::Point<ScrollOffset>,
 8883        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8884        newest_selection_head: Option<DisplayPoint>,
 8885        editor_width: Pixels,
 8886        style: &EditorStyle,
 8887        window: &mut Window,
 8888        cx: &mut App,
 8889    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8890        if self.mode().is_minimap() {
 8891            return None;
 8892        }
 8893        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8894
 8895        if self.edit_prediction_visible_in_cursor_popover(true) {
 8896            return None;
 8897        }
 8898
 8899        match &active_edit_prediction.completion {
 8900            EditPrediction::MoveWithin { target, .. } => {
 8901                let target_display_point = target.to_display_point(editor_snapshot);
 8902
 8903                if self.edit_prediction_requires_modifier() {
 8904                    if !self.edit_prediction_preview_is_active() {
 8905                        return None;
 8906                    }
 8907
 8908                    self.render_edit_prediction_modifier_jump_popover(
 8909                        text_bounds,
 8910                        content_origin,
 8911                        visible_row_range,
 8912                        line_layouts,
 8913                        line_height,
 8914                        scroll_pixel_position,
 8915                        newest_selection_head,
 8916                        target_display_point,
 8917                        window,
 8918                        cx,
 8919                    )
 8920                } else {
 8921                    self.render_edit_prediction_eager_jump_popover(
 8922                        text_bounds,
 8923                        content_origin,
 8924                        editor_snapshot,
 8925                        visible_row_range,
 8926                        scroll_top,
 8927                        scroll_bottom,
 8928                        line_height,
 8929                        scroll_pixel_position,
 8930                        target_display_point,
 8931                        editor_width,
 8932                        window,
 8933                        cx,
 8934                    )
 8935                }
 8936            }
 8937            EditPrediction::Edit {
 8938                display_mode: EditDisplayMode::Inline,
 8939                ..
 8940            } => None,
 8941            EditPrediction::Edit {
 8942                display_mode: EditDisplayMode::TabAccept,
 8943                edits,
 8944                ..
 8945            } => {
 8946                let range = &edits.first()?.0;
 8947                let target_display_point = range.end.to_display_point(editor_snapshot);
 8948
 8949                self.render_edit_prediction_end_of_line_popover(
 8950                    "Accept",
 8951                    editor_snapshot,
 8952                    visible_row_range,
 8953                    target_display_point,
 8954                    line_height,
 8955                    scroll_pixel_position,
 8956                    content_origin,
 8957                    editor_width,
 8958                    window,
 8959                    cx,
 8960                )
 8961            }
 8962            EditPrediction::Edit {
 8963                edits,
 8964                edit_preview,
 8965                display_mode: EditDisplayMode::DiffPopover,
 8966                snapshot,
 8967            } => self.render_edit_prediction_diff_popover(
 8968                text_bounds,
 8969                content_origin,
 8970                right_margin,
 8971                editor_snapshot,
 8972                visible_row_range,
 8973                line_layouts,
 8974                line_height,
 8975                scroll_position,
 8976                scroll_pixel_position,
 8977                newest_selection_head,
 8978                editor_width,
 8979                style,
 8980                edits,
 8981                edit_preview,
 8982                snapshot,
 8983                window,
 8984                cx,
 8985            ),
 8986            EditPrediction::MoveOutside { snapshot, .. } => {
 8987                let mut element = self
 8988                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 8989                    .into_any();
 8990
 8991                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8992                let origin_x = text_bounds.size.width - size.width - px(30.);
 8993                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 8994                element.prepaint_at(origin, window, cx);
 8995
 8996                Some((element, origin))
 8997            }
 8998        }
 8999    }
 9000
 9001    fn render_edit_prediction_modifier_jump_popover(
 9002        &mut self,
 9003        text_bounds: &Bounds<Pixels>,
 9004        content_origin: gpui::Point<Pixels>,
 9005        visible_row_range: Range<DisplayRow>,
 9006        line_layouts: &[LineWithInvisibles],
 9007        line_height: Pixels,
 9008        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9009        newest_selection_head: Option<DisplayPoint>,
 9010        target_display_point: DisplayPoint,
 9011        window: &mut Window,
 9012        cx: &mut App,
 9013    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9014        let scrolled_content_origin =
 9015            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9016
 9017        const SCROLL_PADDING_Y: Pixels = px(12.);
 9018
 9019        if target_display_point.row() < visible_row_range.start {
 9020            return self.render_edit_prediction_scroll_popover(
 9021                |_| SCROLL_PADDING_Y,
 9022                IconName::ArrowUp,
 9023                visible_row_range,
 9024                line_layouts,
 9025                newest_selection_head,
 9026                scrolled_content_origin,
 9027                window,
 9028                cx,
 9029            );
 9030        } else if target_display_point.row() >= visible_row_range.end {
 9031            return self.render_edit_prediction_scroll_popover(
 9032                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9033                IconName::ArrowDown,
 9034                visible_row_range,
 9035                line_layouts,
 9036                newest_selection_head,
 9037                scrolled_content_origin,
 9038                window,
 9039                cx,
 9040            );
 9041        }
 9042
 9043        const POLE_WIDTH: Pixels = px(2.);
 9044
 9045        let line_layout =
 9046            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9047        let target_column = target_display_point.column() as usize;
 9048
 9049        let target_x = line_layout.x_for_index(target_column);
 9050        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9051            - scroll_pixel_position.y;
 9052
 9053        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9054
 9055        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9056        border_color.l += 0.001;
 9057
 9058        let mut element = v_flex()
 9059            .items_end()
 9060            .when(flag_on_right, |el| el.items_start())
 9061            .child(if flag_on_right {
 9062                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9063                    .rounded_bl(px(0.))
 9064                    .rounded_tl(px(0.))
 9065                    .border_l_2()
 9066                    .border_color(border_color)
 9067            } else {
 9068                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9069                    .rounded_br(px(0.))
 9070                    .rounded_tr(px(0.))
 9071                    .border_r_2()
 9072                    .border_color(border_color)
 9073            })
 9074            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9075            .into_any();
 9076
 9077        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9078
 9079        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9080            - point(
 9081                if flag_on_right {
 9082                    POLE_WIDTH
 9083                } else {
 9084                    size.width - POLE_WIDTH
 9085                },
 9086                size.height - line_height,
 9087            );
 9088
 9089        origin.x = origin.x.max(content_origin.x);
 9090
 9091        element.prepaint_at(origin, window, cx);
 9092
 9093        Some((element, origin))
 9094    }
 9095
 9096    fn render_edit_prediction_scroll_popover(
 9097        &mut self,
 9098        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9099        scroll_icon: IconName,
 9100        visible_row_range: Range<DisplayRow>,
 9101        line_layouts: &[LineWithInvisibles],
 9102        newest_selection_head: Option<DisplayPoint>,
 9103        scrolled_content_origin: gpui::Point<Pixels>,
 9104        window: &mut Window,
 9105        cx: &mut App,
 9106    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9107        let mut element = self
 9108            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9109            .into_any();
 9110
 9111        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9112
 9113        let cursor = newest_selection_head?;
 9114        let cursor_row_layout =
 9115            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9116        let cursor_column = cursor.column() as usize;
 9117
 9118        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9119
 9120        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9121
 9122        element.prepaint_at(origin, window, cx);
 9123        Some((element, origin))
 9124    }
 9125
 9126    fn render_edit_prediction_eager_jump_popover(
 9127        &mut self,
 9128        text_bounds: &Bounds<Pixels>,
 9129        content_origin: gpui::Point<Pixels>,
 9130        editor_snapshot: &EditorSnapshot,
 9131        visible_row_range: Range<DisplayRow>,
 9132        scroll_top: ScrollOffset,
 9133        scroll_bottom: ScrollOffset,
 9134        line_height: Pixels,
 9135        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9136        target_display_point: DisplayPoint,
 9137        editor_width: Pixels,
 9138        window: &mut Window,
 9139        cx: &mut App,
 9140    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9141        if target_display_point.row().as_f64() < scroll_top {
 9142            let mut element = self
 9143                .render_edit_prediction_line_popover(
 9144                    "Jump to Edit",
 9145                    Some(IconName::ArrowUp),
 9146                    window,
 9147                    cx,
 9148                )
 9149                .into_any();
 9150
 9151            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9152            let offset = point(
 9153                (text_bounds.size.width - size.width) / 2.,
 9154                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9155            );
 9156
 9157            let origin = text_bounds.origin + offset;
 9158            element.prepaint_at(origin, window, cx);
 9159            Some((element, origin))
 9160        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9161            let mut element = self
 9162                .render_edit_prediction_line_popover(
 9163                    "Jump to Edit",
 9164                    Some(IconName::ArrowDown),
 9165                    window,
 9166                    cx,
 9167                )
 9168                .into_any();
 9169
 9170            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9171            let offset = point(
 9172                (text_bounds.size.width - size.width) / 2.,
 9173                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9174            );
 9175
 9176            let origin = text_bounds.origin + offset;
 9177            element.prepaint_at(origin, window, cx);
 9178            Some((element, origin))
 9179        } else {
 9180            self.render_edit_prediction_end_of_line_popover(
 9181                "Jump to Edit",
 9182                editor_snapshot,
 9183                visible_row_range,
 9184                target_display_point,
 9185                line_height,
 9186                scroll_pixel_position,
 9187                content_origin,
 9188                editor_width,
 9189                window,
 9190                cx,
 9191            )
 9192        }
 9193    }
 9194
 9195    fn render_edit_prediction_end_of_line_popover(
 9196        self: &mut Editor,
 9197        label: &'static str,
 9198        editor_snapshot: &EditorSnapshot,
 9199        visible_row_range: Range<DisplayRow>,
 9200        target_display_point: DisplayPoint,
 9201        line_height: Pixels,
 9202        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9203        content_origin: gpui::Point<Pixels>,
 9204        editor_width: Pixels,
 9205        window: &mut Window,
 9206        cx: &mut App,
 9207    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9208        let target_line_end = DisplayPoint::new(
 9209            target_display_point.row(),
 9210            editor_snapshot.line_len(target_display_point.row()),
 9211        );
 9212
 9213        let mut element = self
 9214            .render_edit_prediction_line_popover(label, None, window, cx)
 9215            .into_any();
 9216
 9217        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9218
 9219        let line_origin =
 9220            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9221
 9222        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9223        let mut origin = start_point
 9224            + line_origin
 9225            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9226        origin.x = origin.x.max(content_origin.x);
 9227
 9228        let max_x = content_origin.x + editor_width - size.width;
 9229
 9230        if origin.x > max_x {
 9231            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9232
 9233            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9234                origin.y += offset;
 9235                IconName::ArrowUp
 9236            } else {
 9237                origin.y -= offset;
 9238                IconName::ArrowDown
 9239            };
 9240
 9241            element = self
 9242                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9243                .into_any();
 9244
 9245            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9246
 9247            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9248        }
 9249
 9250        element.prepaint_at(origin, window, cx);
 9251        Some((element, origin))
 9252    }
 9253
 9254    fn render_edit_prediction_diff_popover(
 9255        self: &Editor,
 9256        text_bounds: &Bounds<Pixels>,
 9257        content_origin: gpui::Point<Pixels>,
 9258        right_margin: Pixels,
 9259        editor_snapshot: &EditorSnapshot,
 9260        visible_row_range: Range<DisplayRow>,
 9261        line_layouts: &[LineWithInvisibles],
 9262        line_height: Pixels,
 9263        scroll_position: gpui::Point<ScrollOffset>,
 9264        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9265        newest_selection_head: Option<DisplayPoint>,
 9266        editor_width: Pixels,
 9267        style: &EditorStyle,
 9268        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9269        edit_preview: &Option<language::EditPreview>,
 9270        snapshot: &language::BufferSnapshot,
 9271        window: &mut Window,
 9272        cx: &mut App,
 9273    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9274        let edit_start = edits
 9275            .first()
 9276            .unwrap()
 9277            .0
 9278            .start
 9279            .to_display_point(editor_snapshot);
 9280        let edit_end = edits
 9281            .last()
 9282            .unwrap()
 9283            .0
 9284            .end
 9285            .to_display_point(editor_snapshot);
 9286
 9287        let is_visible = visible_row_range.contains(&edit_start.row())
 9288            || visible_row_range.contains(&edit_end.row());
 9289        if !is_visible {
 9290            return None;
 9291        }
 9292
 9293        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9294            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9295        } else {
 9296            // Fallback for providers without edit_preview
 9297            crate::edit_prediction_fallback_text(edits, cx)
 9298        };
 9299
 9300        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9301        let line_count = highlighted_edits.text.lines().count();
 9302
 9303        const BORDER_WIDTH: Pixels = px(1.);
 9304
 9305        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9306        let has_keybind = keybind.is_some();
 9307
 9308        let mut element = h_flex()
 9309            .items_start()
 9310            .child(
 9311                h_flex()
 9312                    .bg(cx.theme().colors().editor_background)
 9313                    .border(BORDER_WIDTH)
 9314                    .shadow_xs()
 9315                    .border_color(cx.theme().colors().border)
 9316                    .rounded_l_lg()
 9317                    .when(line_count > 1, |el| el.rounded_br_lg())
 9318                    .pr_1()
 9319                    .child(styled_text),
 9320            )
 9321            .child(
 9322                h_flex()
 9323                    .h(line_height + BORDER_WIDTH * 2.)
 9324                    .px_1p5()
 9325                    .gap_1()
 9326                    // Workaround: For some reason, there's a gap if we don't do this
 9327                    .ml(-BORDER_WIDTH)
 9328                    .shadow(vec![gpui::BoxShadow {
 9329                        color: gpui::black().opacity(0.05),
 9330                        offset: point(px(1.), px(1.)),
 9331                        blur_radius: px(2.),
 9332                        spread_radius: px(0.),
 9333                    }])
 9334                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9335                    .border(BORDER_WIDTH)
 9336                    .border_color(cx.theme().colors().border)
 9337                    .rounded_r_lg()
 9338                    .id("edit_prediction_diff_popover_keybind")
 9339                    .when(!has_keybind, |el| {
 9340                        let status_colors = cx.theme().status();
 9341
 9342                        el.bg(status_colors.error_background)
 9343                            .border_color(status_colors.error.opacity(0.6))
 9344                            .child(Icon::new(IconName::Info).color(Color::Error))
 9345                            .cursor_default()
 9346                            .hoverable_tooltip(move |_window, cx| {
 9347                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9348                            })
 9349                    })
 9350                    .children(keybind),
 9351            )
 9352            .into_any();
 9353
 9354        let longest_row =
 9355            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9356        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9357            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9358        } else {
 9359            layout_line(
 9360                longest_row,
 9361                editor_snapshot,
 9362                style,
 9363                editor_width,
 9364                |_| false,
 9365                window,
 9366                cx,
 9367            )
 9368            .width
 9369        };
 9370
 9371        let viewport_bounds =
 9372            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9373                right: -right_margin,
 9374                ..Default::default()
 9375            });
 9376
 9377        let x_after_longest = Pixels::from(
 9378            ScrollPixelOffset::from(
 9379                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9380            ) - scroll_pixel_position.x,
 9381        );
 9382
 9383        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9384
 9385        // Fully visible if it can be displayed within the window (allow overlapping other
 9386        // panes). However, this is only allowed if the popover starts within text_bounds.
 9387        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9388            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9389
 9390        let mut origin = if can_position_to_the_right {
 9391            point(
 9392                x_after_longest,
 9393                text_bounds.origin.y
 9394                    + Pixels::from(
 9395                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9396                            - scroll_pixel_position.y,
 9397                    ),
 9398            )
 9399        } else {
 9400            let cursor_row = newest_selection_head.map(|head| head.row());
 9401            let above_edit = edit_start
 9402                .row()
 9403                .0
 9404                .checked_sub(line_count as u32)
 9405                .map(DisplayRow);
 9406            let below_edit = Some(edit_end.row() + 1);
 9407            let above_cursor =
 9408                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9409            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9410
 9411            // Place the edit popover adjacent to the edit if there is a location
 9412            // available that is onscreen and does not obscure the cursor. Otherwise,
 9413            // place it adjacent to the cursor.
 9414            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9415                .into_iter()
 9416                .flatten()
 9417                .find(|&start_row| {
 9418                    let end_row = start_row + line_count as u32;
 9419                    visible_row_range.contains(&start_row)
 9420                        && visible_row_range.contains(&end_row)
 9421                        && cursor_row
 9422                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9423                })?;
 9424
 9425            content_origin
 9426                + point(
 9427                    Pixels::from(-scroll_pixel_position.x),
 9428                    Pixels::from(
 9429                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9430                    ),
 9431                )
 9432        };
 9433
 9434        origin.x -= BORDER_WIDTH;
 9435
 9436        window.defer_draw(element, origin, 1);
 9437
 9438        // Do not return an element, since it will already be drawn due to defer_draw.
 9439        None
 9440    }
 9441
 9442    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9443        px(30.)
 9444    }
 9445
 9446    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9447        if self.read_only(cx) {
 9448            cx.theme().players().read_only()
 9449        } else {
 9450            self.style.as_ref().unwrap().local_player
 9451        }
 9452    }
 9453
 9454    fn render_edit_prediction_accept_keybind(
 9455        &self,
 9456        window: &mut Window,
 9457        cx: &mut App,
 9458    ) -> Option<AnyElement> {
 9459        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9460        let accept_keystroke = accept_binding.keystroke()?;
 9461
 9462        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9463
 9464        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9465            Color::Accent
 9466        } else {
 9467            Color::Muted
 9468        };
 9469
 9470        h_flex()
 9471            .px_0p5()
 9472            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9473            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9474            .text_size(TextSize::XSmall.rems(cx))
 9475            .child(h_flex().children(ui::render_modifiers(
 9476                accept_keystroke.modifiers(),
 9477                PlatformStyle::platform(),
 9478                Some(modifiers_color),
 9479                Some(IconSize::XSmall.rems().into()),
 9480                true,
 9481            )))
 9482            .when(is_platform_style_mac, |parent| {
 9483                parent.child(accept_keystroke.key().to_string())
 9484            })
 9485            .when(!is_platform_style_mac, |parent| {
 9486                parent.child(
 9487                    Key::new(
 9488                        util::capitalize(accept_keystroke.key()),
 9489                        Some(Color::Default),
 9490                    )
 9491                    .size(Some(IconSize::XSmall.rems().into())),
 9492                )
 9493            })
 9494            .into_any()
 9495            .into()
 9496    }
 9497
 9498    fn render_edit_prediction_line_popover(
 9499        &self,
 9500        label: impl Into<SharedString>,
 9501        icon: Option<IconName>,
 9502        window: &mut Window,
 9503        cx: &mut App,
 9504    ) -> Stateful<Div> {
 9505        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9506
 9507        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9508        let has_keybind = keybind.is_some();
 9509
 9510        h_flex()
 9511            .id("ep-line-popover")
 9512            .py_0p5()
 9513            .pl_1()
 9514            .pr(padding_right)
 9515            .gap_1()
 9516            .rounded_md()
 9517            .border_1()
 9518            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9519            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9520            .shadow_xs()
 9521            .when(!has_keybind, |el| {
 9522                let status_colors = cx.theme().status();
 9523
 9524                el.bg(status_colors.error_background)
 9525                    .border_color(status_colors.error.opacity(0.6))
 9526                    .pl_2()
 9527                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9528                    .cursor_default()
 9529                    .hoverable_tooltip(move |_window, cx| {
 9530                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9531                    })
 9532            })
 9533            .children(keybind)
 9534            .child(
 9535                Label::new(label)
 9536                    .size(LabelSize::Small)
 9537                    .when(!has_keybind, |el| {
 9538                        el.color(cx.theme().status().error.into()).strikethrough()
 9539                    }),
 9540            )
 9541            .when(!has_keybind, |el| {
 9542                el.child(
 9543                    h_flex().ml_1().child(
 9544                        Icon::new(IconName::Info)
 9545                            .size(IconSize::Small)
 9546                            .color(cx.theme().status().error.into()),
 9547                    ),
 9548                )
 9549            })
 9550            .when_some(icon, |element, icon| {
 9551                element.child(
 9552                    div()
 9553                        .mt(px(1.5))
 9554                        .child(Icon::new(icon).size(IconSize::Small)),
 9555                )
 9556            })
 9557    }
 9558
 9559    fn render_edit_prediction_jump_outside_popover(
 9560        &self,
 9561        snapshot: &BufferSnapshot,
 9562        window: &mut Window,
 9563        cx: &mut App,
 9564    ) -> Stateful<Div> {
 9565        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9566        let has_keybind = keybind.is_some();
 9567
 9568        let file_name = snapshot
 9569            .file()
 9570            .map(|file| SharedString::new(file.file_name(cx)))
 9571            .unwrap_or(SharedString::new_static("untitled"));
 9572
 9573        h_flex()
 9574            .id("ep-jump-outside-popover")
 9575            .py_1()
 9576            .px_2()
 9577            .gap_1()
 9578            .rounded_md()
 9579            .border_1()
 9580            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9581            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9582            .shadow_xs()
 9583            .when(!has_keybind, |el| {
 9584                let status_colors = cx.theme().status();
 9585
 9586                el.bg(status_colors.error_background)
 9587                    .border_color(status_colors.error.opacity(0.6))
 9588                    .pl_2()
 9589                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9590                    .cursor_default()
 9591                    .hoverable_tooltip(move |_window, cx| {
 9592                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9593                    })
 9594            })
 9595            .children(keybind)
 9596            .child(
 9597                Label::new(file_name)
 9598                    .size(LabelSize::Small)
 9599                    .buffer_font(cx)
 9600                    .when(!has_keybind, |el| {
 9601                        el.color(cx.theme().status().error.into()).strikethrough()
 9602                    }),
 9603            )
 9604            .when(!has_keybind, |el| {
 9605                el.child(
 9606                    h_flex().ml_1().child(
 9607                        Icon::new(IconName::Info)
 9608                            .size(IconSize::Small)
 9609                            .color(cx.theme().status().error.into()),
 9610                    ),
 9611                )
 9612            })
 9613            .child(
 9614                div()
 9615                    .mt(px(1.5))
 9616                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9617            )
 9618    }
 9619
 9620    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9621        let accent_color = cx.theme().colors().text_accent;
 9622        let editor_bg_color = cx.theme().colors().editor_background;
 9623        editor_bg_color.blend(accent_color.opacity(0.1))
 9624    }
 9625
 9626    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9627        let accent_color = cx.theme().colors().text_accent;
 9628        let editor_bg_color = cx.theme().colors().editor_background;
 9629        editor_bg_color.blend(accent_color.opacity(0.6))
 9630    }
 9631    fn get_prediction_provider_icon_name(
 9632        provider: &Option<RegisteredEditPredictionDelegate>,
 9633    ) -> IconName {
 9634        match provider {
 9635            Some(provider) => match provider.provider.name() {
 9636                "copilot" => IconName::Copilot,
 9637                "supermaven" => IconName::Supermaven,
 9638                _ => IconName::ZedPredict,
 9639            },
 9640            None => IconName::ZedPredict,
 9641        }
 9642    }
 9643
 9644    fn render_edit_prediction_cursor_popover(
 9645        &self,
 9646        min_width: Pixels,
 9647        max_width: Pixels,
 9648        cursor_point: Point,
 9649        style: &EditorStyle,
 9650        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9651        _window: &Window,
 9652        cx: &mut Context<Editor>,
 9653    ) -> Option<AnyElement> {
 9654        let provider = self.edit_prediction_provider.as_ref()?;
 9655        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9656
 9657        let is_refreshing = provider.provider.is_refreshing(cx);
 9658
 9659        fn pending_completion_container(icon: IconName) -> Div {
 9660            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9661        }
 9662
 9663        let completion = match &self.active_edit_prediction {
 9664            Some(prediction) => {
 9665                if !self.has_visible_completions_menu() {
 9666                    const RADIUS: Pixels = px(6.);
 9667                    const BORDER_WIDTH: Pixels = px(1.);
 9668
 9669                    return Some(
 9670                        h_flex()
 9671                            .elevation_2(cx)
 9672                            .border(BORDER_WIDTH)
 9673                            .border_color(cx.theme().colors().border)
 9674                            .when(accept_keystroke.is_none(), |el| {
 9675                                el.border_color(cx.theme().status().error)
 9676                            })
 9677                            .rounded(RADIUS)
 9678                            .rounded_tl(px(0.))
 9679                            .overflow_hidden()
 9680                            .child(div().px_1p5().child(match &prediction.completion {
 9681                                EditPrediction::MoveWithin { target, snapshot } => {
 9682                                    use text::ToPoint as _;
 9683                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9684                                    {
 9685                                        Icon::new(IconName::ZedPredictDown)
 9686                                    } else {
 9687                                        Icon::new(IconName::ZedPredictUp)
 9688                                    }
 9689                                }
 9690                                EditPrediction::MoveOutside { .. } => {
 9691                                    // TODO [zeta2] custom icon for external jump?
 9692                                    Icon::new(provider_icon)
 9693                                }
 9694                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9695                            }))
 9696                            .child(
 9697                                h_flex()
 9698                                    .gap_1()
 9699                                    .py_1()
 9700                                    .px_2()
 9701                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9702                                    .border_l_1()
 9703                                    .border_color(cx.theme().colors().border)
 9704                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9705                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9706                                        el.child(
 9707                                            Label::new("Hold")
 9708                                                .size(LabelSize::Small)
 9709                                                .when(accept_keystroke.is_none(), |el| {
 9710                                                    el.strikethrough()
 9711                                                })
 9712                                                .line_height_style(LineHeightStyle::UiLabel),
 9713                                        )
 9714                                    })
 9715                                    .id("edit_prediction_cursor_popover_keybind")
 9716                                    .when(accept_keystroke.is_none(), |el| {
 9717                                        let status_colors = cx.theme().status();
 9718
 9719                                        el.bg(status_colors.error_background)
 9720                                            .border_color(status_colors.error.opacity(0.6))
 9721                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9722                                            .cursor_default()
 9723                                            .hoverable_tooltip(move |_window, cx| {
 9724                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9725                                                    .into()
 9726                                            })
 9727                                    })
 9728                                    .when_some(
 9729                                        accept_keystroke.as_ref(),
 9730                                        |el, accept_keystroke| {
 9731                                            el.child(h_flex().children(ui::render_modifiers(
 9732                                                accept_keystroke.modifiers(),
 9733                                                PlatformStyle::platform(),
 9734                                                Some(Color::Default),
 9735                                                Some(IconSize::XSmall.rems().into()),
 9736                                                false,
 9737                                            )))
 9738                                        },
 9739                                    ),
 9740                            )
 9741                            .into_any(),
 9742                    );
 9743                }
 9744
 9745                self.render_edit_prediction_cursor_popover_preview(
 9746                    prediction,
 9747                    cursor_point,
 9748                    style,
 9749                    cx,
 9750                )?
 9751            }
 9752
 9753            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9754                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9755                    stale_completion,
 9756                    cursor_point,
 9757                    style,
 9758                    cx,
 9759                )?,
 9760
 9761                None => pending_completion_container(provider_icon)
 9762                    .child(Label::new("...").size(LabelSize::Small)),
 9763            },
 9764
 9765            None => pending_completion_container(provider_icon)
 9766                .child(Label::new("...").size(LabelSize::Small)),
 9767        };
 9768
 9769        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9770            completion
 9771                .with_animation(
 9772                    "loading-completion",
 9773                    Animation::new(Duration::from_secs(2))
 9774                        .repeat()
 9775                        .with_easing(pulsating_between(0.4, 0.8)),
 9776                    |label, delta| label.opacity(delta),
 9777                )
 9778                .into_any_element()
 9779        } else {
 9780            completion.into_any_element()
 9781        };
 9782
 9783        let has_completion = self.active_edit_prediction.is_some();
 9784
 9785        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9786        Some(
 9787            h_flex()
 9788                .min_w(min_width)
 9789                .max_w(max_width)
 9790                .flex_1()
 9791                .elevation_2(cx)
 9792                .border_color(cx.theme().colors().border)
 9793                .child(
 9794                    div()
 9795                        .flex_1()
 9796                        .py_1()
 9797                        .px_2()
 9798                        .overflow_hidden()
 9799                        .child(completion),
 9800                )
 9801                .when_some(accept_keystroke, |el, accept_keystroke| {
 9802                    if !accept_keystroke.modifiers().modified() {
 9803                        return el;
 9804                    }
 9805
 9806                    el.child(
 9807                        h_flex()
 9808                            .h_full()
 9809                            .border_l_1()
 9810                            .rounded_r_lg()
 9811                            .border_color(cx.theme().colors().border)
 9812                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9813                            .gap_1()
 9814                            .py_1()
 9815                            .px_2()
 9816                            .child(
 9817                                h_flex()
 9818                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9819                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9820                                    .child(h_flex().children(ui::render_modifiers(
 9821                                        accept_keystroke.modifiers(),
 9822                                        PlatformStyle::platform(),
 9823                                        Some(if !has_completion {
 9824                                            Color::Muted
 9825                                        } else {
 9826                                            Color::Default
 9827                                        }),
 9828                                        None,
 9829                                        false,
 9830                                    ))),
 9831                            )
 9832                            .child(Label::new("Preview").into_any_element())
 9833                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9834                    )
 9835                })
 9836                .into_any(),
 9837        )
 9838    }
 9839
 9840    fn render_edit_prediction_cursor_popover_preview(
 9841        &self,
 9842        completion: &EditPredictionState,
 9843        cursor_point: Point,
 9844        style: &EditorStyle,
 9845        cx: &mut Context<Editor>,
 9846    ) -> Option<Div> {
 9847        use text::ToPoint as _;
 9848
 9849        fn render_relative_row_jump(
 9850            prefix: impl Into<String>,
 9851            current_row: u32,
 9852            target_row: u32,
 9853        ) -> Div {
 9854            let (row_diff, arrow) = if target_row < current_row {
 9855                (current_row - target_row, IconName::ArrowUp)
 9856            } else {
 9857                (target_row - current_row, IconName::ArrowDown)
 9858            };
 9859
 9860            h_flex()
 9861                .child(
 9862                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9863                        .color(Color::Muted)
 9864                        .size(LabelSize::Small),
 9865                )
 9866                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9867        }
 9868
 9869        let supports_jump = self
 9870            .edit_prediction_provider
 9871            .as_ref()
 9872            .map(|provider| provider.provider.supports_jump_to_edit())
 9873            .unwrap_or(true);
 9874
 9875        match &completion.completion {
 9876            EditPrediction::MoveWithin {
 9877                target, snapshot, ..
 9878            } => {
 9879                if !supports_jump {
 9880                    return None;
 9881                }
 9882
 9883                Some(
 9884                    h_flex()
 9885                        .px_2()
 9886                        .gap_2()
 9887                        .flex_1()
 9888                        .child(
 9889                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9890                                Icon::new(IconName::ZedPredictDown)
 9891                            } else {
 9892                                Icon::new(IconName::ZedPredictUp)
 9893                            },
 9894                        )
 9895                        .child(Label::new("Jump to Edit")),
 9896                )
 9897            }
 9898            EditPrediction::MoveOutside { snapshot, .. } => {
 9899                let file_name = snapshot
 9900                    .file()
 9901                    .map(|file| file.file_name(cx))
 9902                    .unwrap_or("untitled");
 9903                Some(
 9904                    h_flex()
 9905                        .px_2()
 9906                        .gap_2()
 9907                        .flex_1()
 9908                        .child(Icon::new(IconName::ZedPredict))
 9909                        .child(Label::new(format!("Jump to {file_name}"))),
 9910                )
 9911            }
 9912            EditPrediction::Edit {
 9913                edits,
 9914                edit_preview,
 9915                snapshot,
 9916                display_mode: _,
 9917            } => {
 9918                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9919
 9920                let (highlighted_edits, has_more_lines) =
 9921                    if let Some(edit_preview) = edit_preview.as_ref() {
 9922                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9923                            .first_line_preview()
 9924                    } else {
 9925                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9926                    };
 9927
 9928                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9929                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9930
 9931                let preview = h_flex()
 9932                    .gap_1()
 9933                    .min_w_16()
 9934                    .child(styled_text)
 9935                    .when(has_more_lines, |parent| parent.child(""));
 9936
 9937                let left = if supports_jump && first_edit_row != cursor_point.row {
 9938                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9939                        .into_any_element()
 9940                } else {
 9941                    let icon_name =
 9942                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9943                    Icon::new(icon_name).into_any_element()
 9944                };
 9945
 9946                Some(
 9947                    h_flex()
 9948                        .h_full()
 9949                        .flex_1()
 9950                        .gap_2()
 9951                        .pr_1()
 9952                        .overflow_x_hidden()
 9953                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9954                        .child(left)
 9955                        .child(preview),
 9956                )
 9957            }
 9958        }
 9959    }
 9960
 9961    pub fn render_context_menu(
 9962        &mut self,
 9963        max_height_in_lines: u32,
 9964        window: &mut Window,
 9965        cx: &mut Context<Editor>,
 9966    ) -> Option<AnyElement> {
 9967        let menu = self.context_menu.borrow();
 9968        let menu = menu.as_ref()?;
 9969        if !menu.visible() {
 9970            return None;
 9971        };
 9972        self.style
 9973            .as_ref()
 9974            .map(|style| menu.render(style, max_height_in_lines, window, cx))
 9975    }
 9976
 9977    fn render_context_menu_aside(
 9978        &mut self,
 9979        max_size: Size<Pixels>,
 9980        window: &mut Window,
 9981        cx: &mut Context<Editor>,
 9982    ) -> Option<AnyElement> {
 9983        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9984            if menu.visible() {
 9985                menu.render_aside(max_size, window, cx)
 9986            } else {
 9987                None
 9988            }
 9989        })
 9990    }
 9991
 9992    fn hide_context_menu(
 9993        &mut self,
 9994        window: &mut Window,
 9995        cx: &mut Context<Self>,
 9996    ) -> Option<CodeContextMenu> {
 9997        cx.notify();
 9998        self.completion_tasks.clear();
 9999        let context_menu = self.context_menu.borrow_mut().take();
10000        self.stale_edit_prediction_in_menu.take();
10001        self.update_visible_edit_prediction(window, cx);
10002        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10003            && let Some(completion_provider) = &self.completion_provider
10004        {
10005            completion_provider.selection_changed(None, window, cx);
10006        }
10007        context_menu
10008    }
10009
10010    fn show_snippet_choices(
10011        &mut self,
10012        choices: &Vec<String>,
10013        selection: Range<Anchor>,
10014        cx: &mut Context<Self>,
10015    ) {
10016        let Some((_, buffer, _)) = self
10017            .buffer()
10018            .read(cx)
10019            .excerpt_containing(selection.start, cx)
10020        else {
10021            return;
10022        };
10023        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10024        else {
10025            return;
10026        };
10027        if buffer != end_buffer {
10028            log::error!("expected anchor range to have matching buffer IDs");
10029            return;
10030        }
10031
10032        let id = post_inc(&mut self.next_completion_id);
10033        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10034        let mut context_menu = self.context_menu.borrow_mut();
10035        let old_menu = context_menu.take();
10036        *context_menu = Some(CodeContextMenu::Completions(
10037            CompletionsMenu::new_snippet_choices(
10038                id,
10039                true,
10040                choices,
10041                selection,
10042                buffer,
10043                old_menu.map(|menu| menu.primary_scroll_handle()),
10044                snippet_sort_order,
10045            ),
10046        ));
10047    }
10048
10049    pub fn insert_snippet(
10050        &mut self,
10051        insertion_ranges: &[Range<MultiBufferOffset>],
10052        snippet: Snippet,
10053        window: &mut Window,
10054        cx: &mut Context<Self>,
10055    ) -> Result<()> {
10056        struct Tabstop<T> {
10057            is_end_tabstop: bool,
10058            ranges: Vec<Range<T>>,
10059            choices: Option<Vec<String>>,
10060        }
10061
10062        let tabstops = self.buffer.update(cx, |buffer, cx| {
10063            let snippet_text: Arc<str> = snippet.text.clone().into();
10064            let edits = insertion_ranges
10065                .iter()
10066                .cloned()
10067                .map(|range| (range, snippet_text.clone()));
10068            let autoindent_mode = AutoindentMode::Block {
10069                original_indent_columns: Vec::new(),
10070            };
10071            buffer.edit(edits, Some(autoindent_mode), cx);
10072
10073            let snapshot = &*buffer.read(cx);
10074            let snippet = &snippet;
10075            snippet
10076                .tabstops
10077                .iter()
10078                .map(|tabstop| {
10079                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10080                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10081                    });
10082                    let mut tabstop_ranges = tabstop
10083                        .ranges
10084                        .iter()
10085                        .flat_map(|tabstop_range| {
10086                            let mut delta = 0_isize;
10087                            insertion_ranges.iter().map(move |insertion_range| {
10088                                let insertion_start = insertion_range.start + delta;
10089                                delta += snippet.text.len() as isize
10090                                    - (insertion_range.end - insertion_range.start) as isize;
10091
10092                                let start =
10093                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10094                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10095                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10096                            })
10097                        })
10098                        .collect::<Vec<_>>();
10099                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10100
10101                    Tabstop {
10102                        is_end_tabstop,
10103                        ranges: tabstop_ranges,
10104                        choices: tabstop.choices.clone(),
10105                    }
10106                })
10107                .collect::<Vec<_>>()
10108        });
10109        if let Some(tabstop) = tabstops.first() {
10110            self.change_selections(Default::default(), window, cx, |s| {
10111                // Reverse order so that the first range is the newest created selection.
10112                // Completions will use it and autoscroll will prioritize it.
10113                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10114            });
10115
10116            if let Some(choices) = &tabstop.choices
10117                && let Some(selection) = tabstop.ranges.first()
10118            {
10119                self.show_snippet_choices(choices, selection.clone(), cx)
10120            }
10121
10122            // If we're already at the last tabstop and it's at the end of the snippet,
10123            // we're done, we don't need to keep the state around.
10124            if !tabstop.is_end_tabstop {
10125                let choices = tabstops
10126                    .iter()
10127                    .map(|tabstop| tabstop.choices.clone())
10128                    .collect();
10129
10130                let ranges = tabstops
10131                    .into_iter()
10132                    .map(|tabstop| tabstop.ranges)
10133                    .collect::<Vec<_>>();
10134
10135                self.snippet_stack.push(SnippetState {
10136                    active_index: 0,
10137                    ranges,
10138                    choices,
10139                });
10140            }
10141
10142            // Check whether the just-entered snippet ends with an auto-closable bracket.
10143            if self.autoclose_regions.is_empty() {
10144                let snapshot = self.buffer.read(cx).snapshot(cx);
10145                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10146                    let selection_head = selection.head();
10147                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10148                        continue;
10149                    };
10150
10151                    let mut bracket_pair = None;
10152                    let max_lookup_length = scope
10153                        .brackets()
10154                        .map(|(pair, _)| {
10155                            pair.start
10156                                .as_str()
10157                                .chars()
10158                                .count()
10159                                .max(pair.end.as_str().chars().count())
10160                        })
10161                        .max();
10162                    if let Some(max_lookup_length) = max_lookup_length {
10163                        let next_text = snapshot
10164                            .chars_at(selection_head)
10165                            .take(max_lookup_length)
10166                            .collect::<String>();
10167                        let prev_text = snapshot
10168                            .reversed_chars_at(selection_head)
10169                            .take(max_lookup_length)
10170                            .collect::<String>();
10171
10172                        for (pair, enabled) in scope.brackets() {
10173                            if enabled
10174                                && pair.close
10175                                && prev_text.starts_with(pair.start.as_str())
10176                                && next_text.starts_with(pair.end.as_str())
10177                            {
10178                                bracket_pair = Some(pair.clone());
10179                                break;
10180                            }
10181                        }
10182                    }
10183
10184                    if let Some(pair) = bracket_pair {
10185                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10186                        let autoclose_enabled =
10187                            self.use_autoclose && snapshot_settings.use_autoclose;
10188                        if autoclose_enabled {
10189                            let start = snapshot.anchor_after(selection_head);
10190                            let end = snapshot.anchor_after(selection_head);
10191                            self.autoclose_regions.push(AutocloseRegion {
10192                                selection_id: selection.id,
10193                                range: start..end,
10194                                pair,
10195                            });
10196                        }
10197                    }
10198                }
10199            }
10200        }
10201        Ok(())
10202    }
10203
10204    pub fn move_to_next_snippet_tabstop(
10205        &mut self,
10206        window: &mut Window,
10207        cx: &mut Context<Self>,
10208    ) -> bool {
10209        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10210    }
10211
10212    pub fn move_to_prev_snippet_tabstop(
10213        &mut self,
10214        window: &mut Window,
10215        cx: &mut Context<Self>,
10216    ) -> bool {
10217        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10218    }
10219
10220    pub fn move_to_snippet_tabstop(
10221        &mut self,
10222        bias: Bias,
10223        window: &mut Window,
10224        cx: &mut Context<Self>,
10225    ) -> bool {
10226        if let Some(mut snippet) = self.snippet_stack.pop() {
10227            match bias {
10228                Bias::Left => {
10229                    if snippet.active_index > 0 {
10230                        snippet.active_index -= 1;
10231                    } else {
10232                        self.snippet_stack.push(snippet);
10233                        return false;
10234                    }
10235                }
10236                Bias::Right => {
10237                    if snippet.active_index + 1 < snippet.ranges.len() {
10238                        snippet.active_index += 1;
10239                    } else {
10240                        self.snippet_stack.push(snippet);
10241                        return false;
10242                    }
10243                }
10244            }
10245            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10246                self.change_selections(Default::default(), window, cx, |s| {
10247                    // Reverse order so that the first range is the newest created selection.
10248                    // Completions will use it and autoscroll will prioritize it.
10249                    s.select_ranges(current_ranges.iter().rev().cloned())
10250                });
10251
10252                if let Some(choices) = &snippet.choices[snippet.active_index]
10253                    && let Some(selection) = current_ranges.first()
10254                {
10255                    self.show_snippet_choices(choices, selection.clone(), cx);
10256                }
10257
10258                // If snippet state is not at the last tabstop, push it back on the stack
10259                if snippet.active_index + 1 < snippet.ranges.len() {
10260                    self.snippet_stack.push(snippet);
10261                }
10262                return true;
10263            }
10264        }
10265
10266        false
10267    }
10268
10269    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10270        self.transact(window, cx, |this, window, cx| {
10271            this.select_all(&SelectAll, window, cx);
10272            this.insert("", window, cx);
10273        });
10274    }
10275
10276    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10277        if self.read_only(cx) {
10278            return;
10279        }
10280        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10281        self.transact(window, cx, |this, window, cx| {
10282            this.select_autoclose_pair(window, cx);
10283
10284            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10285
10286            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10287            if !this.linked_edit_ranges.is_empty() {
10288                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10289                let snapshot = this.buffer.read(cx).snapshot(cx);
10290
10291                for selection in selections.iter() {
10292                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10293                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10294                    if selection_start.buffer_id != selection_end.buffer_id {
10295                        continue;
10296                    }
10297                    if let Some(ranges) =
10298                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10299                    {
10300                        for (buffer, entries) in ranges {
10301                            linked_ranges.entry(buffer).or_default().extend(entries);
10302                        }
10303                    }
10304                }
10305            }
10306
10307            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10308            for selection in &mut selections {
10309                if selection.is_empty() {
10310                    let old_head = selection.head();
10311                    let mut new_head =
10312                        movement::left(&display_map, old_head.to_display_point(&display_map))
10313                            .to_point(&display_map);
10314                    if let Some((buffer, line_buffer_range)) = display_map
10315                        .buffer_snapshot()
10316                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10317                    {
10318                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10319                        let indent_len = match indent_size.kind {
10320                            IndentKind::Space => {
10321                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10322                            }
10323                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10324                        };
10325                        if old_head.column <= indent_size.len && old_head.column > 0 {
10326                            let indent_len = indent_len.get();
10327                            new_head = cmp::min(
10328                                new_head,
10329                                MultiBufferPoint::new(
10330                                    old_head.row,
10331                                    ((old_head.column - 1) / indent_len) * indent_len,
10332                                ),
10333                            );
10334                        }
10335                    }
10336
10337                    selection.set_head(new_head, SelectionGoal::None);
10338                }
10339            }
10340
10341            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10342            this.insert("", window, cx);
10343            let empty_str: Arc<str> = Arc::from("");
10344            for (buffer, edits) in linked_ranges {
10345                let snapshot = buffer.read(cx).snapshot();
10346                use text::ToPoint as TP;
10347
10348                let edits = edits
10349                    .into_iter()
10350                    .map(|range| {
10351                        let end_point = TP::to_point(&range.end, &snapshot);
10352                        let mut start_point = TP::to_point(&range.start, &snapshot);
10353
10354                        if end_point == start_point {
10355                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10356                                .saturating_sub(1);
10357                            start_point =
10358                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10359                        };
10360
10361                        (start_point..end_point, empty_str.clone())
10362                    })
10363                    .sorted_by_key(|(range, _)| range.start)
10364                    .collect::<Vec<_>>();
10365                buffer.update(cx, |this, cx| {
10366                    this.edit(edits, None, cx);
10367                })
10368            }
10369            this.refresh_edit_prediction(true, false, window, cx);
10370            refresh_linked_ranges(this, window, cx);
10371        });
10372    }
10373
10374    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10375        if self.read_only(cx) {
10376            return;
10377        }
10378        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10379        self.transact(window, cx, |this, window, cx| {
10380            this.change_selections(Default::default(), window, cx, |s| {
10381                s.move_with(|map, selection| {
10382                    if selection.is_empty() {
10383                        let cursor = movement::right(map, selection.head());
10384                        selection.end = cursor;
10385                        selection.reversed = true;
10386                        selection.goal = SelectionGoal::None;
10387                    }
10388                })
10389            });
10390            this.insert("", window, cx);
10391            this.refresh_edit_prediction(true, false, window, cx);
10392        });
10393    }
10394
10395    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10396        if self.mode.is_single_line() {
10397            cx.propagate();
10398            return;
10399        }
10400
10401        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10402        if self.move_to_prev_snippet_tabstop(window, cx) {
10403            return;
10404        }
10405        self.outdent(&Outdent, window, cx);
10406    }
10407
10408    pub fn next_snippet_tabstop(
10409        &mut self,
10410        _: &NextSnippetTabstop,
10411        window: &mut Window,
10412        cx: &mut Context<Self>,
10413    ) {
10414        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10415            cx.propagate();
10416            return;
10417        }
10418
10419        if self.move_to_next_snippet_tabstop(window, cx) {
10420            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10421            return;
10422        }
10423        cx.propagate();
10424    }
10425
10426    pub fn previous_snippet_tabstop(
10427        &mut self,
10428        _: &PreviousSnippetTabstop,
10429        window: &mut Window,
10430        cx: &mut Context<Self>,
10431    ) {
10432        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10433            cx.propagate();
10434            return;
10435        }
10436
10437        if self.move_to_prev_snippet_tabstop(window, cx) {
10438            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10439            return;
10440        }
10441        cx.propagate();
10442    }
10443
10444    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10445        if self.mode.is_single_line() {
10446            cx.propagate();
10447            return;
10448        }
10449
10450        if self.move_to_next_snippet_tabstop(window, cx) {
10451            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10452            return;
10453        }
10454        if self.read_only(cx) {
10455            return;
10456        }
10457        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10458        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10459        let buffer = self.buffer.read(cx);
10460        let snapshot = buffer.snapshot(cx);
10461        let rows_iter = selections.iter().map(|s| s.head().row);
10462        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10463
10464        let has_some_cursor_in_whitespace = selections
10465            .iter()
10466            .filter(|selection| selection.is_empty())
10467            .any(|selection| {
10468                let cursor = selection.head();
10469                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10470                cursor.column < current_indent.len
10471            });
10472
10473        let mut edits = Vec::new();
10474        let mut prev_edited_row = 0;
10475        let mut row_delta = 0;
10476        for selection in &mut selections {
10477            if selection.start.row != prev_edited_row {
10478                row_delta = 0;
10479            }
10480            prev_edited_row = selection.end.row;
10481
10482            // If the selection is non-empty, then increase the indentation of the selected lines.
10483            if !selection.is_empty() {
10484                row_delta =
10485                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10486                continue;
10487            }
10488
10489            let cursor = selection.head();
10490            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10491            if let Some(suggested_indent) =
10492                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10493            {
10494                // Don't do anything if already at suggested indent
10495                // and there is any other cursor which is not
10496                if has_some_cursor_in_whitespace
10497                    && cursor.column == current_indent.len
10498                    && current_indent.len == suggested_indent.len
10499                {
10500                    continue;
10501                }
10502
10503                // Adjust line and move cursor to suggested indent
10504                // if cursor is not at suggested indent
10505                if cursor.column < suggested_indent.len
10506                    && cursor.column <= current_indent.len
10507                    && current_indent.len <= suggested_indent.len
10508                {
10509                    selection.start = Point::new(cursor.row, suggested_indent.len);
10510                    selection.end = selection.start;
10511                    if row_delta == 0 {
10512                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10513                            cursor.row,
10514                            current_indent,
10515                            suggested_indent,
10516                        ));
10517                        row_delta = suggested_indent.len - current_indent.len;
10518                    }
10519                    continue;
10520                }
10521
10522                // If current indent is more than suggested indent
10523                // only move cursor to current indent and skip indent
10524                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10525                    selection.start = Point::new(cursor.row, current_indent.len);
10526                    selection.end = selection.start;
10527                    continue;
10528                }
10529            }
10530
10531            // Otherwise, insert a hard or soft tab.
10532            let settings = buffer.language_settings_at(cursor, cx);
10533            let tab_size = if settings.hard_tabs {
10534                IndentSize::tab()
10535            } else {
10536                let tab_size = settings.tab_size.get();
10537                let indent_remainder = snapshot
10538                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10539                    .flat_map(str::chars)
10540                    .fold(row_delta % tab_size, |counter: u32, c| {
10541                        if c == '\t' {
10542                            0
10543                        } else {
10544                            (counter + 1) % tab_size
10545                        }
10546                    });
10547
10548                let chars_to_next_tab_stop = tab_size - indent_remainder;
10549                IndentSize::spaces(chars_to_next_tab_stop)
10550            };
10551            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10552            selection.end = selection.start;
10553            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10554            row_delta += tab_size.len;
10555        }
10556
10557        self.transact(window, cx, |this, window, cx| {
10558            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10559            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10560            this.refresh_edit_prediction(true, false, window, cx);
10561        });
10562    }
10563
10564    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10565        if self.read_only(cx) {
10566            return;
10567        }
10568        if self.mode.is_single_line() {
10569            cx.propagate();
10570            return;
10571        }
10572
10573        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10574        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10575        let mut prev_edited_row = 0;
10576        let mut row_delta = 0;
10577        let mut edits = Vec::new();
10578        let buffer = self.buffer.read(cx);
10579        let snapshot = buffer.snapshot(cx);
10580        for selection in &mut selections {
10581            if selection.start.row != prev_edited_row {
10582                row_delta = 0;
10583            }
10584            prev_edited_row = selection.end.row;
10585
10586            row_delta =
10587                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10588        }
10589
10590        self.transact(window, cx, |this, window, cx| {
10591            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10592            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10593        });
10594    }
10595
10596    fn indent_selection(
10597        buffer: &MultiBuffer,
10598        snapshot: &MultiBufferSnapshot,
10599        selection: &mut Selection<Point>,
10600        edits: &mut Vec<(Range<Point>, String)>,
10601        delta_for_start_row: u32,
10602        cx: &App,
10603    ) -> u32 {
10604        let settings = buffer.language_settings_at(selection.start, cx);
10605        let tab_size = settings.tab_size.get();
10606        let indent_kind = if settings.hard_tabs {
10607            IndentKind::Tab
10608        } else {
10609            IndentKind::Space
10610        };
10611        let mut start_row = selection.start.row;
10612        let mut end_row = selection.end.row + 1;
10613
10614        // If a selection ends at the beginning of a line, don't indent
10615        // that last line.
10616        if selection.end.column == 0 && selection.end.row > selection.start.row {
10617            end_row -= 1;
10618        }
10619
10620        // Avoid re-indenting a row that has already been indented by a
10621        // previous selection, but still update this selection's column
10622        // to reflect that indentation.
10623        if delta_for_start_row > 0 {
10624            start_row += 1;
10625            selection.start.column += delta_for_start_row;
10626            if selection.end.row == selection.start.row {
10627                selection.end.column += delta_for_start_row;
10628            }
10629        }
10630
10631        let mut delta_for_end_row = 0;
10632        let has_multiple_rows = start_row + 1 != end_row;
10633        for row in start_row..end_row {
10634            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10635            let indent_delta = match (current_indent.kind, indent_kind) {
10636                (IndentKind::Space, IndentKind::Space) => {
10637                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10638                    IndentSize::spaces(columns_to_next_tab_stop)
10639                }
10640                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10641                (_, IndentKind::Tab) => IndentSize::tab(),
10642            };
10643
10644            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10645                0
10646            } else {
10647                selection.start.column
10648            };
10649            let row_start = Point::new(row, start);
10650            edits.push((
10651                row_start..row_start,
10652                indent_delta.chars().collect::<String>(),
10653            ));
10654
10655            // Update this selection's endpoints to reflect the indentation.
10656            if row == selection.start.row {
10657                selection.start.column += indent_delta.len;
10658            }
10659            if row == selection.end.row {
10660                selection.end.column += indent_delta.len;
10661                delta_for_end_row = indent_delta.len;
10662            }
10663        }
10664
10665        if selection.start.row == selection.end.row {
10666            delta_for_start_row + delta_for_end_row
10667        } else {
10668            delta_for_end_row
10669        }
10670    }
10671
10672    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10673        if self.read_only(cx) {
10674            return;
10675        }
10676        if self.mode.is_single_line() {
10677            cx.propagate();
10678            return;
10679        }
10680
10681        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10682        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10683        let selections = self.selections.all::<Point>(&display_map);
10684        let mut deletion_ranges = Vec::new();
10685        let mut last_outdent = None;
10686        {
10687            let buffer = self.buffer.read(cx);
10688            let snapshot = buffer.snapshot(cx);
10689            for selection in &selections {
10690                let settings = buffer.language_settings_at(selection.start, cx);
10691                let tab_size = settings.tab_size.get();
10692                let mut rows = selection.spanned_rows(false, &display_map);
10693
10694                // Avoid re-outdenting a row that has already been outdented by a
10695                // previous selection.
10696                if let Some(last_row) = last_outdent
10697                    && last_row == rows.start
10698                {
10699                    rows.start = rows.start.next_row();
10700                }
10701                let has_multiple_rows = rows.len() > 1;
10702                for row in rows.iter_rows() {
10703                    let indent_size = snapshot.indent_size_for_line(row);
10704                    if indent_size.len > 0 {
10705                        let deletion_len = match indent_size.kind {
10706                            IndentKind::Space => {
10707                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10708                                if columns_to_prev_tab_stop == 0 {
10709                                    tab_size
10710                                } else {
10711                                    columns_to_prev_tab_stop
10712                                }
10713                            }
10714                            IndentKind::Tab => 1,
10715                        };
10716                        let start = if has_multiple_rows
10717                            || deletion_len > selection.start.column
10718                            || indent_size.len < selection.start.column
10719                        {
10720                            0
10721                        } else {
10722                            selection.start.column - deletion_len
10723                        };
10724                        deletion_ranges.push(
10725                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10726                        );
10727                        last_outdent = Some(row);
10728                    }
10729                }
10730            }
10731        }
10732
10733        self.transact(window, cx, |this, window, cx| {
10734            this.buffer.update(cx, |buffer, cx| {
10735                let empty_str: Arc<str> = Arc::default();
10736                buffer.edit(
10737                    deletion_ranges
10738                        .into_iter()
10739                        .map(|range| (range, empty_str.clone())),
10740                    None,
10741                    cx,
10742                );
10743            });
10744            let selections = this
10745                .selections
10746                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10747            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10748        });
10749    }
10750
10751    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10752        if self.read_only(cx) {
10753            return;
10754        }
10755        if self.mode.is_single_line() {
10756            cx.propagate();
10757            return;
10758        }
10759
10760        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10761        let selections = self
10762            .selections
10763            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10764            .into_iter()
10765            .map(|s| s.range());
10766
10767        self.transact(window, cx, |this, window, cx| {
10768            this.buffer.update(cx, |buffer, cx| {
10769                buffer.autoindent_ranges(selections, cx);
10770            });
10771            let selections = this
10772                .selections
10773                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10774            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10775        });
10776    }
10777
10778    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10779        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10780        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10781        let selections = self.selections.all::<Point>(&display_map);
10782
10783        let mut new_cursors = Vec::new();
10784        let mut edit_ranges = Vec::new();
10785        let mut selections = selections.iter().peekable();
10786        while let Some(selection) = selections.next() {
10787            let mut rows = selection.spanned_rows(false, &display_map);
10788
10789            // Accumulate contiguous regions of rows that we want to delete.
10790            while let Some(next_selection) = selections.peek() {
10791                let next_rows = next_selection.spanned_rows(false, &display_map);
10792                if next_rows.start <= rows.end {
10793                    rows.end = next_rows.end;
10794                    selections.next().unwrap();
10795                } else {
10796                    break;
10797                }
10798            }
10799
10800            let buffer = display_map.buffer_snapshot();
10801            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10802            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10803                // If there's a line after the range, delete the \n from the end of the row range
10804                (
10805                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10806                    rows.end,
10807                )
10808            } else {
10809                // If there isn't a line after the range, delete the \n from the line before the
10810                // start of the row range
10811                edit_start = edit_start.saturating_sub_usize(1);
10812                (buffer.len(), rows.start.previous_row())
10813            };
10814
10815            let text_layout_details = self.text_layout_details(window);
10816            let x = display_map.x_for_display_point(
10817                selection.head().to_display_point(&display_map),
10818                &text_layout_details,
10819            );
10820            let row = Point::new(target_row.0, 0)
10821                .to_display_point(&display_map)
10822                .row();
10823            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10824
10825            new_cursors.push((
10826                selection.id,
10827                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10828                SelectionGoal::None,
10829            ));
10830            edit_ranges.push(edit_start..edit_end);
10831        }
10832
10833        self.transact(window, cx, |this, window, cx| {
10834            let buffer = this.buffer.update(cx, |buffer, cx| {
10835                let empty_str: Arc<str> = Arc::default();
10836                buffer.edit(
10837                    edit_ranges
10838                        .into_iter()
10839                        .map(|range| (range, empty_str.clone())),
10840                    None,
10841                    cx,
10842                );
10843                buffer.snapshot(cx)
10844            });
10845            let new_selections = new_cursors
10846                .into_iter()
10847                .map(|(id, cursor, goal)| {
10848                    let cursor = cursor.to_point(&buffer);
10849                    Selection {
10850                        id,
10851                        start: cursor,
10852                        end: cursor,
10853                        reversed: false,
10854                        goal,
10855                    }
10856                })
10857                .collect();
10858
10859            this.change_selections(Default::default(), window, cx, |s| {
10860                s.select(new_selections);
10861            });
10862        });
10863    }
10864
10865    pub fn join_lines_impl(
10866        &mut self,
10867        insert_whitespace: bool,
10868        window: &mut Window,
10869        cx: &mut Context<Self>,
10870    ) {
10871        if self.read_only(cx) {
10872            return;
10873        }
10874        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10875        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10876            let start = MultiBufferRow(selection.start.row);
10877            // Treat single line selections as if they include the next line. Otherwise this action
10878            // would do nothing for single line selections individual cursors.
10879            let end = if selection.start.row == selection.end.row {
10880                MultiBufferRow(selection.start.row + 1)
10881            } else {
10882                MultiBufferRow(selection.end.row)
10883            };
10884
10885            if let Some(last_row_range) = row_ranges.last_mut()
10886                && start <= last_row_range.end
10887            {
10888                last_row_range.end = end;
10889                continue;
10890            }
10891            row_ranges.push(start..end);
10892        }
10893
10894        let snapshot = self.buffer.read(cx).snapshot(cx);
10895        let mut cursor_positions = Vec::new();
10896        for row_range in &row_ranges {
10897            let anchor = snapshot.anchor_before(Point::new(
10898                row_range.end.previous_row().0,
10899                snapshot.line_len(row_range.end.previous_row()),
10900            ));
10901            cursor_positions.push(anchor..anchor);
10902        }
10903
10904        self.transact(window, cx, |this, window, cx| {
10905            for row_range in row_ranges.into_iter().rev() {
10906                for row in row_range.iter_rows().rev() {
10907                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10908                    let next_line_row = row.next_row();
10909                    let indent = snapshot.indent_size_for_line(next_line_row);
10910                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10911
10912                    let replace =
10913                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10914                            " "
10915                        } else {
10916                            ""
10917                        };
10918
10919                    this.buffer.update(cx, |buffer, cx| {
10920                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10921                    });
10922                }
10923            }
10924
10925            this.change_selections(Default::default(), window, cx, |s| {
10926                s.select_anchor_ranges(cursor_positions)
10927            });
10928        });
10929    }
10930
10931    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10932        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10933        self.join_lines_impl(true, window, cx);
10934    }
10935
10936    pub fn sort_lines_case_sensitive(
10937        &mut self,
10938        _: &SortLinesCaseSensitive,
10939        window: &mut Window,
10940        cx: &mut Context<Self>,
10941    ) {
10942        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10943    }
10944
10945    pub fn sort_lines_by_length(
10946        &mut self,
10947        _: &SortLinesByLength,
10948        window: &mut Window,
10949        cx: &mut Context<Self>,
10950    ) {
10951        self.manipulate_immutable_lines(window, cx, |lines| {
10952            lines.sort_by_key(|&line| line.chars().count())
10953        })
10954    }
10955
10956    pub fn sort_lines_case_insensitive(
10957        &mut self,
10958        _: &SortLinesCaseInsensitive,
10959        window: &mut Window,
10960        cx: &mut Context<Self>,
10961    ) {
10962        self.manipulate_immutable_lines(window, cx, |lines| {
10963            lines.sort_by_key(|line| line.to_lowercase())
10964        })
10965    }
10966
10967    pub fn unique_lines_case_insensitive(
10968        &mut self,
10969        _: &UniqueLinesCaseInsensitive,
10970        window: &mut Window,
10971        cx: &mut Context<Self>,
10972    ) {
10973        self.manipulate_immutable_lines(window, cx, |lines| {
10974            let mut seen = HashSet::default();
10975            lines.retain(|line| seen.insert(line.to_lowercase()));
10976        })
10977    }
10978
10979    pub fn unique_lines_case_sensitive(
10980        &mut self,
10981        _: &UniqueLinesCaseSensitive,
10982        window: &mut Window,
10983        cx: &mut Context<Self>,
10984    ) {
10985        self.manipulate_immutable_lines(window, cx, |lines| {
10986            let mut seen = HashSet::default();
10987            lines.retain(|line| seen.insert(*line));
10988        })
10989    }
10990
10991    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10992        let snapshot = self.buffer.read(cx).snapshot(cx);
10993        for selection in self.selections.disjoint_anchors_arc().iter() {
10994            if snapshot
10995                .language_at(selection.start)
10996                .and_then(|lang| lang.config().wrap_characters.as_ref())
10997                .is_some()
10998            {
10999                return true;
11000            }
11001        }
11002        false
11003    }
11004
11005    fn wrap_selections_in_tag(
11006        &mut self,
11007        _: &WrapSelectionsInTag,
11008        window: &mut Window,
11009        cx: &mut Context<Self>,
11010    ) {
11011        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11012
11013        let snapshot = self.buffer.read(cx).snapshot(cx);
11014
11015        let mut edits = Vec::new();
11016        let mut boundaries = Vec::new();
11017
11018        for selection in self
11019            .selections
11020            .all_adjusted(&self.display_snapshot(cx))
11021            .iter()
11022        {
11023            let Some(wrap_config) = snapshot
11024                .language_at(selection.start)
11025                .and_then(|lang| lang.config().wrap_characters.clone())
11026            else {
11027                continue;
11028            };
11029
11030            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11031            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11032
11033            let start_before = snapshot.anchor_before(selection.start);
11034            let end_after = snapshot.anchor_after(selection.end);
11035
11036            edits.push((start_before..start_before, open_tag));
11037            edits.push((end_after..end_after, close_tag));
11038
11039            boundaries.push((
11040                start_before,
11041                end_after,
11042                wrap_config.start_prefix.len(),
11043                wrap_config.end_suffix.len(),
11044            ));
11045        }
11046
11047        if edits.is_empty() {
11048            return;
11049        }
11050
11051        self.transact(window, cx, |this, window, cx| {
11052            let buffer = this.buffer.update(cx, |buffer, cx| {
11053                buffer.edit(edits, None, cx);
11054                buffer.snapshot(cx)
11055            });
11056
11057            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11058            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11059                boundaries.into_iter()
11060            {
11061                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11062                let close_offset = end_after
11063                    .to_offset(&buffer)
11064                    .saturating_sub_usize(end_suffix_len);
11065                new_selections.push(open_offset..open_offset);
11066                new_selections.push(close_offset..close_offset);
11067            }
11068
11069            this.change_selections(Default::default(), window, cx, |s| {
11070                s.select_ranges(new_selections);
11071            });
11072
11073            this.request_autoscroll(Autoscroll::fit(), cx);
11074        });
11075    }
11076
11077    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11078        let Some(project) = self.project.clone() else {
11079            return;
11080        };
11081        self.reload(project, window, cx)
11082            .detach_and_notify_err(window, cx);
11083    }
11084
11085    pub fn restore_file(
11086        &mut self,
11087        _: &::git::RestoreFile,
11088        window: &mut Window,
11089        cx: &mut Context<Self>,
11090    ) {
11091        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11092        let mut buffer_ids = HashSet::default();
11093        let snapshot = self.buffer().read(cx).snapshot(cx);
11094        for selection in self
11095            .selections
11096            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11097        {
11098            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11099        }
11100
11101        let buffer = self.buffer().read(cx);
11102        let ranges = buffer_ids
11103            .into_iter()
11104            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11105            .collect::<Vec<_>>();
11106
11107        self.restore_hunks_in_ranges(ranges, window, cx);
11108    }
11109
11110    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11111        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11112        let selections = self
11113            .selections
11114            .all(&self.display_snapshot(cx))
11115            .into_iter()
11116            .map(|s| s.range())
11117            .collect();
11118        self.restore_hunks_in_ranges(selections, window, cx);
11119    }
11120
11121    pub fn restore_hunks_in_ranges(
11122        &mut self,
11123        ranges: Vec<Range<Point>>,
11124        window: &mut Window,
11125        cx: &mut Context<Editor>,
11126    ) {
11127        let mut revert_changes = HashMap::default();
11128        let chunk_by = self
11129            .snapshot(window, cx)
11130            .hunks_for_ranges(ranges)
11131            .into_iter()
11132            .chunk_by(|hunk| hunk.buffer_id);
11133        for (buffer_id, hunks) in &chunk_by {
11134            let hunks = hunks.collect::<Vec<_>>();
11135            for hunk in &hunks {
11136                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11137            }
11138            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11139        }
11140        drop(chunk_by);
11141        if !revert_changes.is_empty() {
11142            self.transact(window, cx, |editor, window, cx| {
11143                editor.restore(revert_changes, window, cx);
11144            });
11145        }
11146    }
11147
11148    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11149        if let Some(status) = self
11150            .addons
11151            .iter()
11152            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11153        {
11154            return Some(status);
11155        }
11156        self.project
11157            .as_ref()?
11158            .read(cx)
11159            .status_for_buffer_id(buffer_id, cx)
11160    }
11161
11162    pub fn open_active_item_in_terminal(
11163        &mut self,
11164        _: &OpenInTerminal,
11165        window: &mut Window,
11166        cx: &mut Context<Self>,
11167    ) {
11168        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11169            let project_path = buffer.read(cx).project_path(cx)?;
11170            let project = self.project()?.read(cx);
11171            let entry = project.entry_for_path(&project_path, cx)?;
11172            let parent = match &entry.canonical_path {
11173                Some(canonical_path) => canonical_path.to_path_buf(),
11174                None => project.absolute_path(&project_path, cx)?,
11175            }
11176            .parent()?
11177            .to_path_buf();
11178            Some(parent)
11179        }) {
11180            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11181        }
11182    }
11183
11184    fn set_breakpoint_context_menu(
11185        &mut self,
11186        display_row: DisplayRow,
11187        position: Option<Anchor>,
11188        clicked_point: gpui::Point<Pixels>,
11189        window: &mut Window,
11190        cx: &mut Context<Self>,
11191    ) {
11192        let source = self
11193            .buffer
11194            .read(cx)
11195            .snapshot(cx)
11196            .anchor_before(Point::new(display_row.0, 0u32));
11197
11198        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11199
11200        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11201            self,
11202            source,
11203            clicked_point,
11204            context_menu,
11205            window,
11206            cx,
11207        );
11208    }
11209
11210    fn add_edit_breakpoint_block(
11211        &mut self,
11212        anchor: Anchor,
11213        breakpoint: &Breakpoint,
11214        edit_action: BreakpointPromptEditAction,
11215        window: &mut Window,
11216        cx: &mut Context<Self>,
11217    ) {
11218        let weak_editor = cx.weak_entity();
11219        let bp_prompt = cx.new(|cx| {
11220            BreakpointPromptEditor::new(
11221                weak_editor,
11222                anchor,
11223                breakpoint.clone(),
11224                edit_action,
11225                window,
11226                cx,
11227            )
11228        });
11229
11230        let height = bp_prompt.update(cx, |this, cx| {
11231            this.prompt
11232                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11233        });
11234        let cloned_prompt = bp_prompt.clone();
11235        let blocks = vec![BlockProperties {
11236            style: BlockStyle::Sticky,
11237            placement: BlockPlacement::Above(anchor),
11238            height: Some(height),
11239            render: Arc::new(move |cx| {
11240                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11241                cloned_prompt.clone().into_any_element()
11242            }),
11243            priority: 0,
11244        }];
11245
11246        let focus_handle = bp_prompt.focus_handle(cx);
11247        window.focus(&focus_handle);
11248
11249        let block_ids = self.insert_blocks(blocks, None, cx);
11250        bp_prompt.update(cx, |prompt, _| {
11251            prompt.add_block_ids(block_ids);
11252        });
11253    }
11254
11255    pub(crate) fn breakpoint_at_row(
11256        &self,
11257        row: u32,
11258        window: &mut Window,
11259        cx: &mut Context<Self>,
11260    ) -> Option<(Anchor, Breakpoint)> {
11261        let snapshot = self.snapshot(window, cx);
11262        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11263
11264        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11265    }
11266
11267    pub(crate) fn breakpoint_at_anchor(
11268        &self,
11269        breakpoint_position: Anchor,
11270        snapshot: &EditorSnapshot,
11271        cx: &mut Context<Self>,
11272    ) -> Option<(Anchor, Breakpoint)> {
11273        let buffer = self
11274            .buffer
11275            .read(cx)
11276            .buffer_for_anchor(breakpoint_position, cx)?;
11277
11278        let enclosing_excerpt = breakpoint_position.excerpt_id;
11279        let buffer_snapshot = buffer.read(cx).snapshot();
11280
11281        let row = buffer_snapshot
11282            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11283            .row;
11284
11285        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11286        let anchor_end = snapshot
11287            .buffer_snapshot()
11288            .anchor_after(Point::new(row, line_len));
11289
11290        self.breakpoint_store
11291            .as_ref()?
11292            .read_with(cx, |breakpoint_store, cx| {
11293                breakpoint_store
11294                    .breakpoints(
11295                        &buffer,
11296                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11297                        &buffer_snapshot,
11298                        cx,
11299                    )
11300                    .next()
11301                    .and_then(|(bp, _)| {
11302                        let breakpoint_row = buffer_snapshot
11303                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11304                            .row;
11305
11306                        if breakpoint_row == row {
11307                            snapshot
11308                                .buffer_snapshot()
11309                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11310                                .map(|position| (position, bp.bp.clone()))
11311                        } else {
11312                            None
11313                        }
11314                    })
11315            })
11316    }
11317
11318    pub fn edit_log_breakpoint(
11319        &mut self,
11320        _: &EditLogBreakpoint,
11321        window: &mut Window,
11322        cx: &mut Context<Self>,
11323    ) {
11324        if self.breakpoint_store.is_none() {
11325            return;
11326        }
11327
11328        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11329            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11330                message: None,
11331                state: BreakpointState::Enabled,
11332                condition: None,
11333                hit_condition: None,
11334            });
11335
11336            self.add_edit_breakpoint_block(
11337                anchor,
11338                &breakpoint,
11339                BreakpointPromptEditAction::Log,
11340                window,
11341                cx,
11342            );
11343        }
11344    }
11345
11346    fn breakpoints_at_cursors(
11347        &self,
11348        window: &mut Window,
11349        cx: &mut Context<Self>,
11350    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11351        let snapshot = self.snapshot(window, cx);
11352        let cursors = self
11353            .selections
11354            .disjoint_anchors_arc()
11355            .iter()
11356            .map(|selection| {
11357                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11358
11359                let breakpoint_position = self
11360                    .breakpoint_at_row(cursor_position.row, window, cx)
11361                    .map(|bp| bp.0)
11362                    .unwrap_or_else(|| {
11363                        snapshot
11364                            .display_snapshot
11365                            .buffer_snapshot()
11366                            .anchor_after(Point::new(cursor_position.row, 0))
11367                    });
11368
11369                let breakpoint = self
11370                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11371                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11372
11373                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11374            })
11375            // 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.
11376            .collect::<HashMap<Anchor, _>>();
11377
11378        cursors.into_iter().collect()
11379    }
11380
11381    pub fn enable_breakpoint(
11382        &mut self,
11383        _: &crate::actions::EnableBreakpoint,
11384        window: &mut Window,
11385        cx: &mut Context<Self>,
11386    ) {
11387        if self.breakpoint_store.is_none() {
11388            return;
11389        }
11390
11391        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11392            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11393                continue;
11394            };
11395            self.edit_breakpoint_at_anchor(
11396                anchor,
11397                breakpoint,
11398                BreakpointEditAction::InvertState,
11399                cx,
11400            );
11401        }
11402    }
11403
11404    pub fn disable_breakpoint(
11405        &mut self,
11406        _: &crate::actions::DisableBreakpoint,
11407        window: &mut Window,
11408        cx: &mut Context<Self>,
11409    ) {
11410        if self.breakpoint_store.is_none() {
11411            return;
11412        }
11413
11414        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11415            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11416                continue;
11417            };
11418            self.edit_breakpoint_at_anchor(
11419                anchor,
11420                breakpoint,
11421                BreakpointEditAction::InvertState,
11422                cx,
11423            );
11424        }
11425    }
11426
11427    pub fn toggle_breakpoint(
11428        &mut self,
11429        _: &crate::actions::ToggleBreakpoint,
11430        window: &mut Window,
11431        cx: &mut Context<Self>,
11432    ) {
11433        if self.breakpoint_store.is_none() {
11434            return;
11435        }
11436
11437        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11438            if let Some(breakpoint) = breakpoint {
11439                self.edit_breakpoint_at_anchor(
11440                    anchor,
11441                    breakpoint,
11442                    BreakpointEditAction::Toggle,
11443                    cx,
11444                );
11445            } else {
11446                self.edit_breakpoint_at_anchor(
11447                    anchor,
11448                    Breakpoint::new_standard(),
11449                    BreakpointEditAction::Toggle,
11450                    cx,
11451                );
11452            }
11453        }
11454    }
11455
11456    pub fn edit_breakpoint_at_anchor(
11457        &mut self,
11458        breakpoint_position: Anchor,
11459        breakpoint: Breakpoint,
11460        edit_action: BreakpointEditAction,
11461        cx: &mut Context<Self>,
11462    ) {
11463        let Some(breakpoint_store) = &self.breakpoint_store else {
11464            return;
11465        };
11466
11467        let Some(buffer) = self
11468            .buffer
11469            .read(cx)
11470            .buffer_for_anchor(breakpoint_position, cx)
11471        else {
11472            return;
11473        };
11474
11475        breakpoint_store.update(cx, |breakpoint_store, cx| {
11476            breakpoint_store.toggle_breakpoint(
11477                buffer,
11478                BreakpointWithPosition {
11479                    position: breakpoint_position.text_anchor,
11480                    bp: breakpoint,
11481                },
11482                edit_action,
11483                cx,
11484            );
11485        });
11486
11487        cx.notify();
11488    }
11489
11490    #[cfg(any(test, feature = "test-support"))]
11491    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11492        self.breakpoint_store.clone()
11493    }
11494
11495    pub fn prepare_restore_change(
11496        &self,
11497        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11498        hunk: &MultiBufferDiffHunk,
11499        cx: &mut App,
11500    ) -> Option<()> {
11501        if hunk.is_created_file() {
11502            return None;
11503        }
11504        let buffer = self.buffer.read(cx);
11505        let diff = buffer.diff_for(hunk.buffer_id)?;
11506        let buffer = buffer.buffer(hunk.buffer_id)?;
11507        let buffer = buffer.read(cx);
11508        let original_text = diff
11509            .read(cx)
11510            .base_text()
11511            .as_rope()
11512            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11513        let buffer_snapshot = buffer.snapshot();
11514        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11515        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11516            probe
11517                .0
11518                .start
11519                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11520                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11521        }) {
11522            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11523            Some(())
11524        } else {
11525            None
11526        }
11527    }
11528
11529    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11530        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11531    }
11532
11533    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11534        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11535    }
11536
11537    pub fn rotate_selections_forward(
11538        &mut self,
11539        _: &RotateSelectionsForward,
11540        window: &mut Window,
11541        cx: &mut Context<Self>,
11542    ) {
11543        self.rotate_selections(window, cx, false)
11544    }
11545
11546    pub fn rotate_selections_backward(
11547        &mut self,
11548        _: &RotateSelectionsBackward,
11549        window: &mut Window,
11550        cx: &mut Context<Self>,
11551    ) {
11552        self.rotate_selections(window, cx, true)
11553    }
11554
11555    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11556        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11557        let display_snapshot = self.display_snapshot(cx);
11558        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11559
11560        if selections.len() < 2 {
11561            return;
11562        }
11563
11564        let (edits, new_selections) = {
11565            let buffer = self.buffer.read(cx).read(cx);
11566            let has_selections = selections.iter().any(|s| !s.is_empty());
11567            if has_selections {
11568                let mut selected_texts: Vec<String> = selections
11569                    .iter()
11570                    .map(|selection| {
11571                        buffer
11572                            .text_for_range(selection.start..selection.end)
11573                            .collect()
11574                    })
11575                    .collect();
11576
11577                if reverse {
11578                    selected_texts.rotate_left(1);
11579                } else {
11580                    selected_texts.rotate_right(1);
11581                }
11582
11583                let mut offset_delta: i64 = 0;
11584                let mut new_selections = Vec::new();
11585                let edits: Vec<_> = selections
11586                    .iter()
11587                    .zip(selected_texts.iter())
11588                    .map(|(selection, new_text)| {
11589                        let old_len = (selection.end.0 - selection.start.0) as i64;
11590                        let new_len = new_text.len() as i64;
11591                        let adjusted_start =
11592                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11593                        let adjusted_end =
11594                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11595
11596                        new_selections.push(Selection {
11597                            id: selection.id,
11598                            start: adjusted_start,
11599                            end: adjusted_end,
11600                            reversed: selection.reversed,
11601                            goal: selection.goal,
11602                        });
11603
11604                        offset_delta += new_len - old_len;
11605                        (selection.start..selection.end, new_text.clone())
11606                    })
11607                    .collect();
11608                (edits, new_selections)
11609            } else {
11610                let mut all_rows: Vec<u32> = selections
11611                    .iter()
11612                    .map(|selection| buffer.offset_to_point(selection.start).row)
11613                    .collect();
11614                all_rows.sort_unstable();
11615                all_rows.dedup();
11616
11617                if all_rows.len() < 2 {
11618                    return;
11619                }
11620
11621                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11622                    .iter()
11623                    .map(|&row| {
11624                        let start = Point::new(row, 0);
11625                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11626                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11627                    })
11628                    .collect();
11629
11630                let mut line_texts: Vec<String> = line_ranges
11631                    .iter()
11632                    .map(|range| buffer.text_for_range(range.clone()).collect())
11633                    .collect();
11634
11635                if reverse {
11636                    line_texts.rotate_left(1);
11637                } else {
11638                    line_texts.rotate_right(1);
11639                }
11640
11641                let edits = line_ranges
11642                    .iter()
11643                    .zip(line_texts.iter())
11644                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11645                    .collect();
11646
11647                let num_rows = all_rows.len();
11648                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11649                    .iter()
11650                    .enumerate()
11651                    .map(|(i, &row)| (row, i))
11652                    .collect();
11653
11654                // Compute new line start offsets after rotation (handles CRLF)
11655                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11656                let first_line_start = line_ranges[0].start.0;
11657                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11658                for text in line_texts.iter().take(num_rows - 1) {
11659                    let prev_start = *new_line_starts.last().unwrap();
11660                    new_line_starts.push(prev_start + text.len() + newline_len);
11661                }
11662
11663                let new_selections = selections
11664                    .iter()
11665                    .map(|selection| {
11666                        let point = buffer.offset_to_point(selection.start);
11667                        let old_index = row_to_index[&point.row];
11668                        let new_index = if reverse {
11669                            (old_index + num_rows - 1) % num_rows
11670                        } else {
11671                            (old_index + 1) % num_rows
11672                        };
11673                        let new_offset =
11674                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11675                        Selection {
11676                            id: selection.id,
11677                            start: new_offset,
11678                            end: new_offset,
11679                            reversed: selection.reversed,
11680                            goal: selection.goal,
11681                        }
11682                    })
11683                    .collect();
11684
11685                (edits, new_selections)
11686            }
11687        };
11688
11689        self.transact(window, cx, |this, window, cx| {
11690            this.buffer.update(cx, |buffer, cx| {
11691                buffer.edit(edits, None, cx);
11692            });
11693            this.change_selections(Default::default(), window, cx, |s| {
11694                s.select(new_selections);
11695            });
11696        });
11697    }
11698
11699    fn manipulate_lines<M>(
11700        &mut self,
11701        window: &mut Window,
11702        cx: &mut Context<Self>,
11703        mut manipulate: M,
11704    ) where
11705        M: FnMut(&str) -> LineManipulationResult,
11706    {
11707        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11708
11709        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11710        let buffer = self.buffer.read(cx).snapshot(cx);
11711
11712        let mut edits = Vec::new();
11713
11714        let selections = self.selections.all::<Point>(&display_map);
11715        let mut selections = selections.iter().peekable();
11716        let mut contiguous_row_selections = Vec::new();
11717        let mut new_selections = Vec::new();
11718        let mut added_lines = 0;
11719        let mut removed_lines = 0;
11720
11721        while let Some(selection) = selections.next() {
11722            let (start_row, end_row) = consume_contiguous_rows(
11723                &mut contiguous_row_selections,
11724                selection,
11725                &display_map,
11726                &mut selections,
11727            );
11728
11729            let start_point = Point::new(start_row.0, 0);
11730            let end_point = Point::new(
11731                end_row.previous_row().0,
11732                buffer.line_len(end_row.previous_row()),
11733            );
11734            let text = buffer
11735                .text_for_range(start_point..end_point)
11736                .collect::<String>();
11737
11738            let LineManipulationResult {
11739                new_text,
11740                line_count_before,
11741                line_count_after,
11742            } = manipulate(&text);
11743
11744            edits.push((start_point..end_point, new_text));
11745
11746            // Selections must change based on added and removed line count
11747            let start_row =
11748                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11749            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11750            new_selections.push(Selection {
11751                id: selection.id,
11752                start: start_row,
11753                end: end_row,
11754                goal: SelectionGoal::None,
11755                reversed: selection.reversed,
11756            });
11757
11758            if line_count_after > line_count_before {
11759                added_lines += line_count_after - line_count_before;
11760            } else if line_count_before > line_count_after {
11761                removed_lines += line_count_before - line_count_after;
11762            }
11763        }
11764
11765        self.transact(window, cx, |this, window, cx| {
11766            let buffer = this.buffer.update(cx, |buffer, cx| {
11767                buffer.edit(edits, None, cx);
11768                buffer.snapshot(cx)
11769            });
11770
11771            // Recalculate offsets on newly edited buffer
11772            let new_selections = new_selections
11773                .iter()
11774                .map(|s| {
11775                    let start_point = Point::new(s.start.0, 0);
11776                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11777                    Selection {
11778                        id: s.id,
11779                        start: buffer.point_to_offset(start_point),
11780                        end: buffer.point_to_offset(end_point),
11781                        goal: s.goal,
11782                        reversed: s.reversed,
11783                    }
11784                })
11785                .collect();
11786
11787            this.change_selections(Default::default(), window, cx, |s| {
11788                s.select(new_selections);
11789            });
11790
11791            this.request_autoscroll(Autoscroll::fit(), cx);
11792        });
11793    }
11794
11795    fn manipulate_immutable_lines<Fn>(
11796        &mut self,
11797        window: &mut Window,
11798        cx: &mut Context<Self>,
11799        mut callback: Fn,
11800    ) where
11801        Fn: FnMut(&mut Vec<&str>),
11802    {
11803        self.manipulate_lines(window, cx, |text| {
11804            let mut lines: Vec<&str> = text.split('\n').collect();
11805            let line_count_before = lines.len();
11806
11807            callback(&mut lines);
11808
11809            LineManipulationResult {
11810                new_text: lines.join("\n"),
11811                line_count_before,
11812                line_count_after: lines.len(),
11813            }
11814        });
11815    }
11816
11817    fn manipulate_mutable_lines<Fn>(
11818        &mut self,
11819        window: &mut Window,
11820        cx: &mut Context<Self>,
11821        mut callback: Fn,
11822    ) where
11823        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11824    {
11825        self.manipulate_lines(window, cx, |text| {
11826            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11827            let line_count_before = lines.len();
11828
11829            callback(&mut lines);
11830
11831            LineManipulationResult {
11832                new_text: lines.join("\n"),
11833                line_count_before,
11834                line_count_after: lines.len(),
11835            }
11836        });
11837    }
11838
11839    pub fn convert_indentation_to_spaces(
11840        &mut self,
11841        _: &ConvertIndentationToSpaces,
11842        window: &mut Window,
11843        cx: &mut Context<Self>,
11844    ) {
11845        let settings = self.buffer.read(cx).language_settings(cx);
11846        let tab_size = settings.tab_size.get() as usize;
11847
11848        self.manipulate_mutable_lines(window, cx, |lines| {
11849            // Allocates a reasonably sized scratch buffer once for the whole loop
11850            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11851            // Avoids recomputing spaces that could be inserted many times
11852            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11853                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11854                .collect();
11855
11856            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11857                let mut chars = line.as_ref().chars();
11858                let mut col = 0;
11859                let mut changed = false;
11860
11861                for ch in chars.by_ref() {
11862                    match ch {
11863                        ' ' => {
11864                            reindented_line.push(' ');
11865                            col += 1;
11866                        }
11867                        '\t' => {
11868                            // \t are converted to spaces depending on the current column
11869                            let spaces_len = tab_size - (col % tab_size);
11870                            reindented_line.extend(&space_cache[spaces_len - 1]);
11871                            col += spaces_len;
11872                            changed = true;
11873                        }
11874                        _ => {
11875                            // If we dont append before break, the character is consumed
11876                            reindented_line.push(ch);
11877                            break;
11878                        }
11879                    }
11880                }
11881
11882                if !changed {
11883                    reindented_line.clear();
11884                    continue;
11885                }
11886                // Append the rest of the line and replace old reference with new one
11887                reindented_line.extend(chars);
11888                *line = Cow::Owned(reindented_line.clone());
11889                reindented_line.clear();
11890            }
11891        });
11892    }
11893
11894    pub fn convert_indentation_to_tabs(
11895        &mut self,
11896        _: &ConvertIndentationToTabs,
11897        window: &mut Window,
11898        cx: &mut Context<Self>,
11899    ) {
11900        let settings = self.buffer.read(cx).language_settings(cx);
11901        let tab_size = settings.tab_size.get() as usize;
11902
11903        self.manipulate_mutable_lines(window, cx, |lines| {
11904            // Allocates a reasonably sized buffer once for the whole loop
11905            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11906            // Avoids recomputing spaces that could be inserted many times
11907            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11908                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11909                .collect();
11910
11911            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11912                let mut chars = line.chars();
11913                let mut spaces_count = 0;
11914                let mut first_non_indent_char = None;
11915                let mut changed = false;
11916
11917                for ch in chars.by_ref() {
11918                    match ch {
11919                        ' ' => {
11920                            // Keep track of spaces. Append \t when we reach tab_size
11921                            spaces_count += 1;
11922                            changed = true;
11923                            if spaces_count == tab_size {
11924                                reindented_line.push('\t');
11925                                spaces_count = 0;
11926                            }
11927                        }
11928                        '\t' => {
11929                            reindented_line.push('\t');
11930                            spaces_count = 0;
11931                        }
11932                        _ => {
11933                            // Dont append it yet, we might have remaining spaces
11934                            first_non_indent_char = Some(ch);
11935                            break;
11936                        }
11937                    }
11938                }
11939
11940                if !changed {
11941                    reindented_line.clear();
11942                    continue;
11943                }
11944                // Remaining spaces that didn't make a full tab stop
11945                if spaces_count > 0 {
11946                    reindented_line.extend(&space_cache[spaces_count - 1]);
11947                }
11948                // If we consume an extra character that was not indentation, add it back
11949                if let Some(extra_char) = first_non_indent_char {
11950                    reindented_line.push(extra_char);
11951                }
11952                // Append the rest of the line and replace old reference with new one
11953                reindented_line.extend(chars);
11954                *line = Cow::Owned(reindented_line.clone());
11955                reindented_line.clear();
11956            }
11957        });
11958    }
11959
11960    pub fn convert_to_upper_case(
11961        &mut self,
11962        _: &ConvertToUpperCase,
11963        window: &mut Window,
11964        cx: &mut Context<Self>,
11965    ) {
11966        self.manipulate_text(window, cx, |text| text.to_uppercase())
11967    }
11968
11969    pub fn convert_to_lower_case(
11970        &mut self,
11971        _: &ConvertToLowerCase,
11972        window: &mut Window,
11973        cx: &mut Context<Self>,
11974    ) {
11975        self.manipulate_text(window, cx, |text| text.to_lowercase())
11976    }
11977
11978    pub fn convert_to_title_case(
11979        &mut self,
11980        _: &ConvertToTitleCase,
11981        window: &mut Window,
11982        cx: &mut Context<Self>,
11983    ) {
11984        self.manipulate_text(window, cx, |text| {
11985            text.split('\n')
11986                .map(|line| line.to_case(Case::Title))
11987                .join("\n")
11988        })
11989    }
11990
11991    pub fn convert_to_snake_case(
11992        &mut self,
11993        _: &ConvertToSnakeCase,
11994        window: &mut Window,
11995        cx: &mut Context<Self>,
11996    ) {
11997        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11998    }
11999
12000    pub fn convert_to_kebab_case(
12001        &mut self,
12002        _: &ConvertToKebabCase,
12003        window: &mut Window,
12004        cx: &mut Context<Self>,
12005    ) {
12006        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
12007    }
12008
12009    pub fn convert_to_upper_camel_case(
12010        &mut self,
12011        _: &ConvertToUpperCamelCase,
12012        window: &mut Window,
12013        cx: &mut Context<Self>,
12014    ) {
12015        self.manipulate_text(window, cx, |text| {
12016            text.split('\n')
12017                .map(|line| line.to_case(Case::UpperCamel))
12018                .join("\n")
12019        })
12020    }
12021
12022    pub fn convert_to_lower_camel_case(
12023        &mut self,
12024        _: &ConvertToLowerCamelCase,
12025        window: &mut Window,
12026        cx: &mut Context<Self>,
12027    ) {
12028        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
12029    }
12030
12031    pub fn convert_to_opposite_case(
12032        &mut self,
12033        _: &ConvertToOppositeCase,
12034        window: &mut Window,
12035        cx: &mut Context<Self>,
12036    ) {
12037        self.manipulate_text(window, cx, |text| {
12038            text.chars()
12039                .fold(String::with_capacity(text.len()), |mut t, c| {
12040                    if c.is_uppercase() {
12041                        t.extend(c.to_lowercase());
12042                    } else {
12043                        t.extend(c.to_uppercase());
12044                    }
12045                    t
12046                })
12047        })
12048    }
12049
12050    pub fn convert_to_sentence_case(
12051        &mut self,
12052        _: &ConvertToSentenceCase,
12053        window: &mut Window,
12054        cx: &mut Context<Self>,
12055    ) {
12056        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12057    }
12058
12059    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12060        self.manipulate_text(window, cx, |text| {
12061            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12062            if has_upper_case_characters {
12063                text.to_lowercase()
12064            } else {
12065                text.to_uppercase()
12066            }
12067        })
12068    }
12069
12070    pub fn convert_to_rot13(
12071        &mut self,
12072        _: &ConvertToRot13,
12073        window: &mut Window,
12074        cx: &mut Context<Self>,
12075    ) {
12076        self.manipulate_text(window, cx, |text| {
12077            text.chars()
12078                .map(|c| match c {
12079                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12080                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12081                    _ => c,
12082                })
12083                .collect()
12084        })
12085    }
12086
12087    pub fn convert_to_rot47(
12088        &mut self,
12089        _: &ConvertToRot47,
12090        window: &mut Window,
12091        cx: &mut Context<Self>,
12092    ) {
12093        self.manipulate_text(window, cx, |text| {
12094            text.chars()
12095                .map(|c| {
12096                    let code_point = c as u32;
12097                    if code_point >= 33 && code_point <= 126 {
12098                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12099                    }
12100                    c
12101                })
12102                .collect()
12103        })
12104    }
12105
12106    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12107    where
12108        Fn: FnMut(&str) -> String,
12109    {
12110        let buffer = self.buffer.read(cx).snapshot(cx);
12111
12112        let mut new_selections = Vec::new();
12113        let mut edits = Vec::new();
12114        let mut selection_adjustment = 0isize;
12115
12116        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12117            let selection_is_empty = selection.is_empty();
12118
12119            let (start, end) = if selection_is_empty {
12120                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12121                (word_range.start, word_range.end)
12122            } else {
12123                (
12124                    buffer.point_to_offset(selection.start),
12125                    buffer.point_to_offset(selection.end),
12126                )
12127            };
12128
12129            let text = buffer.text_for_range(start..end).collect::<String>();
12130            let old_length = text.len() as isize;
12131            let text = callback(&text);
12132
12133            new_selections.push(Selection {
12134                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12135                end: MultiBufferOffset(
12136                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12137                ),
12138                goal: SelectionGoal::None,
12139                id: selection.id,
12140                reversed: selection.reversed,
12141            });
12142
12143            selection_adjustment += old_length - text.len() as isize;
12144
12145            edits.push((start..end, text));
12146        }
12147
12148        self.transact(window, cx, |this, window, cx| {
12149            this.buffer.update(cx, |buffer, cx| {
12150                buffer.edit(edits, None, cx);
12151            });
12152
12153            this.change_selections(Default::default(), window, cx, |s| {
12154                s.select(new_selections);
12155            });
12156
12157            this.request_autoscroll(Autoscroll::fit(), cx);
12158        });
12159    }
12160
12161    pub fn move_selection_on_drop(
12162        &mut self,
12163        selection: &Selection<Anchor>,
12164        target: DisplayPoint,
12165        is_cut: bool,
12166        window: &mut Window,
12167        cx: &mut Context<Self>,
12168    ) {
12169        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12170        let buffer = display_map.buffer_snapshot();
12171        let mut edits = Vec::new();
12172        let insert_point = display_map
12173            .clip_point(target, Bias::Left)
12174            .to_point(&display_map);
12175        let text = buffer
12176            .text_for_range(selection.start..selection.end)
12177            .collect::<String>();
12178        if is_cut {
12179            edits.push(((selection.start..selection.end), String::new()));
12180        }
12181        let insert_anchor = buffer.anchor_before(insert_point);
12182        edits.push(((insert_anchor..insert_anchor), text));
12183        let last_edit_start = insert_anchor.bias_left(buffer);
12184        let last_edit_end = insert_anchor.bias_right(buffer);
12185        self.transact(window, cx, |this, window, cx| {
12186            this.buffer.update(cx, |buffer, cx| {
12187                buffer.edit(edits, None, cx);
12188            });
12189            this.change_selections(Default::default(), window, cx, |s| {
12190                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12191            });
12192        });
12193    }
12194
12195    pub fn clear_selection_drag_state(&mut self) {
12196        self.selection_drag_state = SelectionDragState::None;
12197    }
12198
12199    pub fn duplicate(
12200        &mut self,
12201        upwards: bool,
12202        whole_lines: bool,
12203        window: &mut Window,
12204        cx: &mut Context<Self>,
12205    ) {
12206        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12207
12208        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12209        let buffer = display_map.buffer_snapshot();
12210        let selections = self.selections.all::<Point>(&display_map);
12211
12212        let mut edits = Vec::new();
12213        let mut selections_iter = selections.iter().peekable();
12214        while let Some(selection) = selections_iter.next() {
12215            let mut rows = selection.spanned_rows(false, &display_map);
12216            // duplicate line-wise
12217            if whole_lines || selection.start == selection.end {
12218                // Avoid duplicating the same lines twice.
12219                while let Some(next_selection) = selections_iter.peek() {
12220                    let next_rows = next_selection.spanned_rows(false, &display_map);
12221                    if next_rows.start < rows.end {
12222                        rows.end = next_rows.end;
12223                        selections_iter.next().unwrap();
12224                    } else {
12225                        break;
12226                    }
12227                }
12228
12229                // Copy the text from the selected row region and splice it either at the start
12230                // or end of the region.
12231                let start = Point::new(rows.start.0, 0);
12232                let end = Point::new(
12233                    rows.end.previous_row().0,
12234                    buffer.line_len(rows.end.previous_row()),
12235                );
12236
12237                let mut text = buffer.text_for_range(start..end).collect::<String>();
12238
12239                let insert_location = if upwards {
12240                    // When duplicating upward, we need to insert before the current line.
12241                    // If we're on the last line and it doesn't end with a newline,
12242                    // we need to add a newline before the duplicated content.
12243                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12244                        && buffer.max_point().column > 0
12245                        && !text.ends_with('\n');
12246
12247                    if needs_leading_newline {
12248                        text.insert(0, '\n');
12249                        end
12250                    } else {
12251                        text.push('\n');
12252                        Point::new(rows.start.0, 0)
12253                    }
12254                } else {
12255                    text.push('\n');
12256                    start
12257                };
12258                edits.push((insert_location..insert_location, text));
12259            } else {
12260                // duplicate character-wise
12261                let start = selection.start;
12262                let end = selection.end;
12263                let text = buffer.text_for_range(start..end).collect::<String>();
12264                edits.push((selection.end..selection.end, text));
12265            }
12266        }
12267
12268        self.transact(window, cx, |this, window, cx| {
12269            this.buffer.update(cx, |buffer, cx| {
12270                buffer.edit(edits, None, cx);
12271            });
12272
12273            // When duplicating upward with whole lines, move the cursor to the duplicated line
12274            if upwards && whole_lines {
12275                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12276
12277                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12278                    let mut new_ranges = Vec::new();
12279                    let selections = s.all::<Point>(&display_map);
12280                    let mut selections_iter = selections.iter().peekable();
12281
12282                    while let Some(first_selection) = selections_iter.next() {
12283                        // Group contiguous selections together to find the total row span
12284                        let mut group_selections = vec![first_selection];
12285                        let mut rows = first_selection.spanned_rows(false, &display_map);
12286
12287                        while let Some(next_selection) = selections_iter.peek() {
12288                            let next_rows = next_selection.spanned_rows(false, &display_map);
12289                            if next_rows.start < rows.end {
12290                                rows.end = next_rows.end;
12291                                group_selections.push(selections_iter.next().unwrap());
12292                            } else {
12293                                break;
12294                            }
12295                        }
12296
12297                        let row_count = rows.end.0 - rows.start.0;
12298
12299                        // Move all selections in this group up by the total number of duplicated rows
12300                        for selection in group_selections {
12301                            let new_start = Point::new(
12302                                selection.start.row.saturating_sub(row_count),
12303                                selection.start.column,
12304                            );
12305
12306                            let new_end = Point::new(
12307                                selection.end.row.saturating_sub(row_count),
12308                                selection.end.column,
12309                            );
12310
12311                            new_ranges.push(new_start..new_end);
12312                        }
12313                    }
12314
12315                    s.select_ranges(new_ranges);
12316                });
12317            }
12318
12319            this.request_autoscroll(Autoscroll::fit(), cx);
12320        });
12321    }
12322
12323    pub fn duplicate_line_up(
12324        &mut self,
12325        _: &DuplicateLineUp,
12326        window: &mut Window,
12327        cx: &mut Context<Self>,
12328    ) {
12329        self.duplicate(true, true, window, cx);
12330    }
12331
12332    pub fn duplicate_line_down(
12333        &mut self,
12334        _: &DuplicateLineDown,
12335        window: &mut Window,
12336        cx: &mut Context<Self>,
12337    ) {
12338        self.duplicate(false, true, window, cx);
12339    }
12340
12341    pub fn duplicate_selection(
12342        &mut self,
12343        _: &DuplicateSelection,
12344        window: &mut Window,
12345        cx: &mut Context<Self>,
12346    ) {
12347        self.duplicate(false, false, window, cx);
12348    }
12349
12350    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12351        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12352        if self.mode.is_single_line() {
12353            cx.propagate();
12354            return;
12355        }
12356
12357        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12358        let buffer = self.buffer.read(cx).snapshot(cx);
12359
12360        let mut edits = Vec::new();
12361        let mut unfold_ranges = Vec::new();
12362        let mut refold_creases = Vec::new();
12363
12364        let selections = self.selections.all::<Point>(&display_map);
12365        let mut selections = selections.iter().peekable();
12366        let mut contiguous_row_selections = Vec::new();
12367        let mut new_selections = Vec::new();
12368
12369        while let Some(selection) = selections.next() {
12370            // Find all the selections that span a contiguous row range
12371            let (start_row, end_row) = consume_contiguous_rows(
12372                &mut contiguous_row_selections,
12373                selection,
12374                &display_map,
12375                &mut selections,
12376            );
12377
12378            // Move the text spanned by the row range to be before the line preceding the row range
12379            if start_row.0 > 0 {
12380                let range_to_move = Point::new(
12381                    start_row.previous_row().0,
12382                    buffer.line_len(start_row.previous_row()),
12383                )
12384                    ..Point::new(
12385                        end_row.previous_row().0,
12386                        buffer.line_len(end_row.previous_row()),
12387                    );
12388                let insertion_point = display_map
12389                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12390                    .0;
12391
12392                // Don't move lines across excerpts
12393                if buffer
12394                    .excerpt_containing(insertion_point..range_to_move.end)
12395                    .is_some()
12396                {
12397                    let text = buffer
12398                        .text_for_range(range_to_move.clone())
12399                        .flat_map(|s| s.chars())
12400                        .skip(1)
12401                        .chain(['\n'])
12402                        .collect::<String>();
12403
12404                    edits.push((
12405                        buffer.anchor_after(range_to_move.start)
12406                            ..buffer.anchor_before(range_to_move.end),
12407                        String::new(),
12408                    ));
12409                    let insertion_anchor = buffer.anchor_after(insertion_point);
12410                    edits.push((insertion_anchor..insertion_anchor, text));
12411
12412                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12413
12414                    // Move selections up
12415                    new_selections.extend(contiguous_row_selections.drain(..).map(
12416                        |mut selection| {
12417                            selection.start.row -= row_delta;
12418                            selection.end.row -= row_delta;
12419                            selection
12420                        },
12421                    ));
12422
12423                    // Move folds up
12424                    unfold_ranges.push(range_to_move.clone());
12425                    for fold in display_map.folds_in_range(
12426                        buffer.anchor_before(range_to_move.start)
12427                            ..buffer.anchor_after(range_to_move.end),
12428                    ) {
12429                        let mut start = fold.range.start.to_point(&buffer);
12430                        let mut end = fold.range.end.to_point(&buffer);
12431                        start.row -= row_delta;
12432                        end.row -= row_delta;
12433                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12434                    }
12435                }
12436            }
12437
12438            // If we didn't move line(s), preserve the existing selections
12439            new_selections.append(&mut contiguous_row_selections);
12440        }
12441
12442        self.transact(window, cx, |this, window, cx| {
12443            this.unfold_ranges(&unfold_ranges, true, true, cx);
12444            this.buffer.update(cx, |buffer, cx| {
12445                for (range, text) in edits {
12446                    buffer.edit([(range, text)], None, cx);
12447                }
12448            });
12449            this.fold_creases(refold_creases, true, window, cx);
12450            this.change_selections(Default::default(), window, cx, |s| {
12451                s.select(new_selections);
12452            })
12453        });
12454    }
12455
12456    pub fn move_line_down(
12457        &mut self,
12458        _: &MoveLineDown,
12459        window: &mut Window,
12460        cx: &mut Context<Self>,
12461    ) {
12462        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12463        if self.mode.is_single_line() {
12464            cx.propagate();
12465            return;
12466        }
12467
12468        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12469        let buffer = self.buffer.read(cx).snapshot(cx);
12470
12471        let mut edits = Vec::new();
12472        let mut unfold_ranges = Vec::new();
12473        let mut refold_creases = Vec::new();
12474
12475        let selections = self.selections.all::<Point>(&display_map);
12476        let mut selections = selections.iter().peekable();
12477        let mut contiguous_row_selections = Vec::new();
12478        let mut new_selections = Vec::new();
12479
12480        while let Some(selection) = selections.next() {
12481            // Find all the selections that span a contiguous row range
12482            let (start_row, end_row) = consume_contiguous_rows(
12483                &mut contiguous_row_selections,
12484                selection,
12485                &display_map,
12486                &mut selections,
12487            );
12488
12489            // Move the text spanned by the row range to be after the last line of the row range
12490            if end_row.0 <= buffer.max_point().row {
12491                let range_to_move =
12492                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12493                let insertion_point = display_map
12494                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12495                    .0;
12496
12497                // Don't move lines across excerpt boundaries
12498                if buffer
12499                    .excerpt_containing(range_to_move.start..insertion_point)
12500                    .is_some()
12501                {
12502                    let mut text = String::from("\n");
12503                    text.extend(buffer.text_for_range(range_to_move.clone()));
12504                    text.pop(); // Drop trailing newline
12505                    edits.push((
12506                        buffer.anchor_after(range_to_move.start)
12507                            ..buffer.anchor_before(range_to_move.end),
12508                        String::new(),
12509                    ));
12510                    let insertion_anchor = buffer.anchor_after(insertion_point);
12511                    edits.push((insertion_anchor..insertion_anchor, text));
12512
12513                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12514
12515                    // Move selections down
12516                    new_selections.extend(contiguous_row_selections.drain(..).map(
12517                        |mut selection| {
12518                            selection.start.row += row_delta;
12519                            selection.end.row += row_delta;
12520                            selection
12521                        },
12522                    ));
12523
12524                    // Move folds down
12525                    unfold_ranges.push(range_to_move.clone());
12526                    for fold in display_map.folds_in_range(
12527                        buffer.anchor_before(range_to_move.start)
12528                            ..buffer.anchor_after(range_to_move.end),
12529                    ) {
12530                        let mut start = fold.range.start.to_point(&buffer);
12531                        let mut end = fold.range.end.to_point(&buffer);
12532                        start.row += row_delta;
12533                        end.row += row_delta;
12534                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12535                    }
12536                }
12537            }
12538
12539            // If we didn't move line(s), preserve the existing selections
12540            new_selections.append(&mut contiguous_row_selections);
12541        }
12542
12543        self.transact(window, cx, |this, window, cx| {
12544            this.unfold_ranges(&unfold_ranges, true, true, cx);
12545            this.buffer.update(cx, |buffer, cx| {
12546                for (range, text) in edits {
12547                    buffer.edit([(range, text)], None, cx);
12548                }
12549            });
12550            this.fold_creases(refold_creases, true, window, cx);
12551            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12552        });
12553    }
12554
12555    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12556        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12557        let text_layout_details = &self.text_layout_details(window);
12558        self.transact(window, cx, |this, window, cx| {
12559            let edits = this.change_selections(Default::default(), window, cx, |s| {
12560                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12561                s.move_with(|display_map, selection| {
12562                    if !selection.is_empty() {
12563                        return;
12564                    }
12565
12566                    let mut head = selection.head();
12567                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12568                    if head.column() == display_map.line_len(head.row()) {
12569                        transpose_offset = display_map
12570                            .buffer_snapshot()
12571                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12572                    }
12573
12574                    if transpose_offset == MultiBufferOffset(0) {
12575                        return;
12576                    }
12577
12578                    *head.column_mut() += 1;
12579                    head = display_map.clip_point(head, Bias::Right);
12580                    let goal = SelectionGoal::HorizontalPosition(
12581                        display_map
12582                            .x_for_display_point(head, text_layout_details)
12583                            .into(),
12584                    );
12585                    selection.collapse_to(head, goal);
12586
12587                    let transpose_start = display_map
12588                        .buffer_snapshot()
12589                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12590                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12591                        let transpose_end = display_map
12592                            .buffer_snapshot()
12593                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12594                        if let Some(ch) = display_map
12595                            .buffer_snapshot()
12596                            .chars_at(transpose_start)
12597                            .next()
12598                        {
12599                            edits.push((transpose_start..transpose_offset, String::new()));
12600                            edits.push((transpose_end..transpose_end, ch.to_string()));
12601                        }
12602                    }
12603                });
12604                edits
12605            });
12606            this.buffer
12607                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12608            let selections = this
12609                .selections
12610                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12611            this.change_selections(Default::default(), window, cx, |s| {
12612                s.select(selections);
12613            });
12614        });
12615    }
12616
12617    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12618        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12619        if self.mode.is_single_line() {
12620            cx.propagate();
12621            return;
12622        }
12623
12624        self.rewrap_impl(RewrapOptions::default(), cx)
12625    }
12626
12627    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12628        let buffer = self.buffer.read(cx).snapshot(cx);
12629        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12630
12631        #[derive(Clone, Debug, PartialEq)]
12632        enum CommentFormat {
12633            /// single line comment, with prefix for line
12634            Line(String),
12635            /// single line within a block comment, with prefix for line
12636            BlockLine(String),
12637            /// a single line of a block comment that includes the initial delimiter
12638            BlockCommentWithStart(BlockCommentConfig),
12639            /// a single line of a block comment that includes the ending delimiter
12640            BlockCommentWithEnd(BlockCommentConfig),
12641        }
12642
12643        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12644        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12645            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12646                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12647                .peekable();
12648
12649            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12650                row
12651            } else {
12652                return Vec::new();
12653            };
12654
12655            let language_settings = buffer.language_settings_at(selection.head(), cx);
12656            let language_scope = buffer.language_scope_at(selection.head());
12657
12658            let indent_and_prefix_for_row =
12659                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12660                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12661                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12662                        &language_scope
12663                    {
12664                        let indent_end = Point::new(row, indent.len);
12665                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12666                        let line_text_after_indent = buffer
12667                            .text_for_range(indent_end..line_end)
12668                            .collect::<String>();
12669
12670                        let is_within_comment_override = buffer
12671                            .language_scope_at(indent_end)
12672                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12673                        let comment_delimiters = if is_within_comment_override {
12674                            // we are within a comment syntax node, but we don't
12675                            // yet know what kind of comment: block, doc or line
12676                            match (
12677                                language_scope.documentation_comment(),
12678                                language_scope.block_comment(),
12679                            ) {
12680                                (Some(config), _) | (_, Some(config))
12681                                    if buffer.contains_str_at(indent_end, &config.start) =>
12682                                {
12683                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12684                                }
12685                                (Some(config), _) | (_, Some(config))
12686                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12687                                {
12688                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12689                                }
12690                                (Some(config), _) | (_, Some(config))
12691                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12692                                {
12693                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12694                                }
12695                                (_, _) => language_scope
12696                                    .line_comment_prefixes()
12697                                    .iter()
12698                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12699                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12700                            }
12701                        } else {
12702                            // we not in an overridden comment node, but we may
12703                            // be within a non-overridden line comment node
12704                            language_scope
12705                                .line_comment_prefixes()
12706                                .iter()
12707                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12708                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12709                        };
12710
12711                        let rewrap_prefix = language_scope
12712                            .rewrap_prefixes()
12713                            .iter()
12714                            .find_map(|prefix_regex| {
12715                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12716                                    if mat.start() == 0 {
12717                                        Some(mat.as_str().to_string())
12718                                    } else {
12719                                        None
12720                                    }
12721                                })
12722                            })
12723                            .flatten();
12724                        (comment_delimiters, rewrap_prefix)
12725                    } else {
12726                        (None, None)
12727                    };
12728                    (indent, comment_prefix, rewrap_prefix)
12729                };
12730
12731            let mut ranges = Vec::new();
12732            let from_empty_selection = selection.is_empty();
12733
12734            let mut current_range_start = first_row;
12735            let mut prev_row = first_row;
12736            let (
12737                mut current_range_indent,
12738                mut current_range_comment_delimiters,
12739                mut current_range_rewrap_prefix,
12740            ) = indent_and_prefix_for_row(first_row);
12741
12742            for row in non_blank_rows_iter.skip(1) {
12743                let has_paragraph_break = row > prev_row + 1;
12744
12745                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12746                    indent_and_prefix_for_row(row);
12747
12748                let has_indent_change = row_indent != current_range_indent;
12749                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12750
12751                let has_boundary_change = has_comment_change
12752                    || row_rewrap_prefix.is_some()
12753                    || (has_indent_change && current_range_comment_delimiters.is_some());
12754
12755                if has_paragraph_break || has_boundary_change {
12756                    ranges.push((
12757                        language_settings.clone(),
12758                        Point::new(current_range_start, 0)
12759                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12760                        current_range_indent,
12761                        current_range_comment_delimiters.clone(),
12762                        current_range_rewrap_prefix.clone(),
12763                        from_empty_selection,
12764                    ));
12765                    current_range_start = row;
12766                    current_range_indent = row_indent;
12767                    current_range_comment_delimiters = row_comment_delimiters;
12768                    current_range_rewrap_prefix = row_rewrap_prefix;
12769                }
12770                prev_row = row;
12771            }
12772
12773            ranges.push((
12774                language_settings.clone(),
12775                Point::new(current_range_start, 0)
12776                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12777                current_range_indent,
12778                current_range_comment_delimiters,
12779                current_range_rewrap_prefix,
12780                from_empty_selection,
12781            ));
12782
12783            ranges
12784        });
12785
12786        let mut edits = Vec::new();
12787        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12788
12789        for (
12790            language_settings,
12791            wrap_range,
12792            mut indent_size,
12793            comment_prefix,
12794            rewrap_prefix,
12795            from_empty_selection,
12796        ) in wrap_ranges
12797        {
12798            let mut start_row = wrap_range.start.row;
12799            let mut end_row = wrap_range.end.row;
12800
12801            // Skip selections that overlap with a range that has already been rewrapped.
12802            let selection_range = start_row..end_row;
12803            if rewrapped_row_ranges
12804                .iter()
12805                .any(|range| range.overlaps(&selection_range))
12806            {
12807                continue;
12808            }
12809
12810            let tab_size = language_settings.tab_size;
12811
12812            let (line_prefix, inside_comment) = match &comment_prefix {
12813                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12814                    (Some(prefix.as_str()), true)
12815                }
12816                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12817                    (Some(prefix.as_ref()), true)
12818                }
12819                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12820                    start: _,
12821                    end: _,
12822                    prefix,
12823                    tab_size,
12824                })) => {
12825                    indent_size.len += tab_size;
12826                    (Some(prefix.as_ref()), true)
12827                }
12828                None => (None, false),
12829            };
12830            let indent_prefix = indent_size.chars().collect::<String>();
12831            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12832
12833            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12834                RewrapBehavior::InComments => inside_comment,
12835                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12836                RewrapBehavior::Anywhere => true,
12837            };
12838
12839            let should_rewrap = options.override_language_settings
12840                || allow_rewrap_based_on_language
12841                || self.hard_wrap.is_some();
12842            if !should_rewrap {
12843                continue;
12844            }
12845
12846            if from_empty_selection {
12847                'expand_upwards: while start_row > 0 {
12848                    let prev_row = start_row - 1;
12849                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12850                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12851                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12852                    {
12853                        start_row = prev_row;
12854                    } else {
12855                        break 'expand_upwards;
12856                    }
12857                }
12858
12859                'expand_downwards: while end_row < buffer.max_point().row {
12860                    let next_row = end_row + 1;
12861                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12862                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12863                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12864                    {
12865                        end_row = next_row;
12866                    } else {
12867                        break 'expand_downwards;
12868                    }
12869                }
12870            }
12871
12872            let start = Point::new(start_row, 0);
12873            let start_offset = ToOffset::to_offset(&start, &buffer);
12874            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12875            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12876            let mut first_line_delimiter = None;
12877            let mut last_line_delimiter = None;
12878            let Some(lines_without_prefixes) = selection_text
12879                .lines()
12880                .enumerate()
12881                .map(|(ix, line)| {
12882                    let line_trimmed = line.trim_start();
12883                    if rewrap_prefix.is_some() && ix > 0 {
12884                        Ok(line_trimmed)
12885                    } else if let Some(
12886                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12887                            start,
12888                            prefix,
12889                            end,
12890                            tab_size,
12891                        })
12892                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12893                            start,
12894                            prefix,
12895                            end,
12896                            tab_size,
12897                        }),
12898                    ) = &comment_prefix
12899                    {
12900                        let line_trimmed = line_trimmed
12901                            .strip_prefix(start.as_ref())
12902                            .map(|s| {
12903                                let mut indent_size = indent_size;
12904                                indent_size.len -= tab_size;
12905                                let indent_prefix: String = indent_size.chars().collect();
12906                                first_line_delimiter = Some((indent_prefix, start));
12907                                s.trim_start()
12908                            })
12909                            .unwrap_or(line_trimmed);
12910                        let line_trimmed = line_trimmed
12911                            .strip_suffix(end.as_ref())
12912                            .map(|s| {
12913                                last_line_delimiter = Some(end);
12914                                s.trim_end()
12915                            })
12916                            .unwrap_or(line_trimmed);
12917                        let line_trimmed = line_trimmed
12918                            .strip_prefix(prefix.as_ref())
12919                            .unwrap_or(line_trimmed);
12920                        Ok(line_trimmed)
12921                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12922                        line_trimmed.strip_prefix(prefix).with_context(|| {
12923                            format!("line did not start with prefix {prefix:?}: {line:?}")
12924                        })
12925                    } else {
12926                        line_trimmed
12927                            .strip_prefix(&line_prefix.trim_start())
12928                            .with_context(|| {
12929                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12930                            })
12931                    }
12932                })
12933                .collect::<Result<Vec<_>, _>>()
12934                .log_err()
12935            else {
12936                continue;
12937            };
12938
12939            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12940                buffer
12941                    .language_settings_at(Point::new(start_row, 0), cx)
12942                    .preferred_line_length as usize
12943            });
12944
12945            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12946                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12947            } else {
12948                line_prefix.clone()
12949            };
12950
12951            let wrapped_text = {
12952                let mut wrapped_text = wrap_with_prefix(
12953                    line_prefix,
12954                    subsequent_lines_prefix,
12955                    lines_without_prefixes.join("\n"),
12956                    wrap_column,
12957                    tab_size,
12958                    options.preserve_existing_whitespace,
12959                );
12960
12961                if let Some((indent, delimiter)) = first_line_delimiter {
12962                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12963                }
12964                if let Some(last_line) = last_line_delimiter {
12965                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12966                }
12967
12968                wrapped_text
12969            };
12970
12971            // TODO: should always use char-based diff while still supporting cursor behavior that
12972            // matches vim.
12973            let mut diff_options = DiffOptions::default();
12974            if options.override_language_settings {
12975                diff_options.max_word_diff_len = 0;
12976                diff_options.max_word_diff_line_count = 0;
12977            } else {
12978                diff_options.max_word_diff_len = usize::MAX;
12979                diff_options.max_word_diff_line_count = usize::MAX;
12980            }
12981
12982            for (old_range, new_text) in
12983                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12984            {
12985                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12986                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12987                edits.push((edit_start..edit_end, new_text));
12988            }
12989
12990            rewrapped_row_ranges.push(start_row..=end_row);
12991        }
12992
12993        self.buffer
12994            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12995    }
12996
12997    pub fn cut_common(
12998        &mut self,
12999        cut_no_selection_line: bool,
13000        window: &mut Window,
13001        cx: &mut Context<Self>,
13002    ) -> ClipboardItem {
13003        let mut text = String::new();
13004        let buffer = self.buffer.read(cx).snapshot(cx);
13005        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13006        let mut clipboard_selections = Vec::with_capacity(selections.len());
13007        {
13008            let max_point = buffer.max_point();
13009            let mut is_first = true;
13010            let mut prev_selection_was_entire_line = false;
13011            for selection in &mut selections {
13012                let is_entire_line =
13013                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13014                if is_entire_line {
13015                    selection.start = Point::new(selection.start.row, 0);
13016                    if !selection.is_empty() && selection.end.column == 0 {
13017                        selection.end = cmp::min(max_point, selection.end);
13018                    } else {
13019                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13020                    }
13021                    selection.goal = SelectionGoal::None;
13022                }
13023                if is_first {
13024                    is_first = false;
13025                } else if !prev_selection_was_entire_line {
13026                    text += "\n";
13027                }
13028                prev_selection_was_entire_line = is_entire_line;
13029                let mut len = 0;
13030                for chunk in buffer.text_for_range(selection.start..selection.end) {
13031                    text.push_str(chunk);
13032                    len += chunk.len();
13033                }
13034
13035                clipboard_selections.push(ClipboardSelection::for_buffer(
13036                    len,
13037                    is_entire_line,
13038                    selection.range(),
13039                    &buffer,
13040                    self.project.as_ref(),
13041                    cx,
13042                ));
13043            }
13044        }
13045
13046        self.transact(window, cx, |this, window, cx| {
13047            this.change_selections(Default::default(), window, cx, |s| {
13048                s.select(selections);
13049            });
13050            this.insert("", window, cx);
13051        });
13052        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13053    }
13054
13055    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13056        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13057        let item = self.cut_common(true, window, cx);
13058        cx.write_to_clipboard(item);
13059    }
13060
13061    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13062        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13063        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13064            s.move_with(|snapshot, sel| {
13065                if sel.is_empty() {
13066                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13067                }
13068                if sel.is_empty() {
13069                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13070                }
13071            });
13072        });
13073        let item = self.cut_common(false, window, cx);
13074        cx.set_global(KillRing(item))
13075    }
13076
13077    pub fn kill_ring_yank(
13078        &mut self,
13079        _: &KillRingYank,
13080        window: &mut Window,
13081        cx: &mut Context<Self>,
13082    ) {
13083        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13084        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13085            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13086                (kill_ring.text().to_string(), kill_ring.metadata_json())
13087            } else {
13088                return;
13089            }
13090        } else {
13091            return;
13092        };
13093        self.do_paste(&text, metadata, false, window, cx);
13094    }
13095
13096    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13097        self.do_copy(true, cx);
13098    }
13099
13100    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13101        self.do_copy(false, cx);
13102    }
13103
13104    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13105        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13106        let buffer = self.buffer.read(cx).read(cx);
13107        let mut text = String::new();
13108
13109        let mut clipboard_selections = Vec::with_capacity(selections.len());
13110        {
13111            let max_point = buffer.max_point();
13112            let mut is_first = true;
13113            let mut prev_selection_was_entire_line = false;
13114            for selection in &selections {
13115                let mut start = selection.start;
13116                let mut end = selection.end;
13117                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13118                let mut add_trailing_newline = false;
13119                if is_entire_line {
13120                    start = Point::new(start.row, 0);
13121                    let next_line_start = Point::new(end.row + 1, 0);
13122                    if next_line_start <= max_point {
13123                        end = next_line_start;
13124                    } else {
13125                        // We're on the last line without a trailing newline.
13126                        // Copy to the end of the line and add a newline afterwards.
13127                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13128                        add_trailing_newline = true;
13129                    }
13130                }
13131
13132                let mut trimmed_selections = Vec::new();
13133                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13134                    let row = MultiBufferRow(start.row);
13135                    let first_indent = buffer.indent_size_for_line(row);
13136                    if first_indent.len == 0 || start.column > first_indent.len {
13137                        trimmed_selections.push(start..end);
13138                    } else {
13139                        trimmed_selections.push(
13140                            Point::new(row.0, first_indent.len)
13141                                ..Point::new(row.0, buffer.line_len(row)),
13142                        );
13143                        for row in start.row + 1..=end.row {
13144                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13145                            if row == end.row {
13146                                line_len = end.column;
13147                            }
13148                            if line_len == 0 {
13149                                trimmed_selections
13150                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13151                                continue;
13152                            }
13153                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13154                            if row_indent_size.len >= first_indent.len {
13155                                trimmed_selections.push(
13156                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13157                                );
13158                            } else {
13159                                trimmed_selections.clear();
13160                                trimmed_selections.push(start..end);
13161                                break;
13162                            }
13163                        }
13164                    }
13165                } else {
13166                    trimmed_selections.push(start..end);
13167                }
13168
13169                for trimmed_range in trimmed_selections {
13170                    if is_first {
13171                        is_first = false;
13172                    } else if !prev_selection_was_entire_line {
13173                        text += "\n";
13174                    }
13175                    prev_selection_was_entire_line = is_entire_line;
13176                    let mut len = 0;
13177                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13178                        text.push_str(chunk);
13179                        len += chunk.len();
13180                    }
13181                    if add_trailing_newline {
13182                        text.push('\n');
13183                        len += 1;
13184                    }
13185                    clipboard_selections.push(ClipboardSelection::for_buffer(
13186                        len,
13187                        is_entire_line,
13188                        trimmed_range,
13189                        &buffer,
13190                        self.project.as_ref(),
13191                        cx,
13192                    ));
13193                }
13194            }
13195        }
13196
13197        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13198            text,
13199            clipboard_selections,
13200        ));
13201    }
13202
13203    pub fn do_paste(
13204        &mut self,
13205        text: &String,
13206        clipboard_selections: Option<Vec<ClipboardSelection>>,
13207        handle_entire_lines: bool,
13208        window: &mut Window,
13209        cx: &mut Context<Self>,
13210    ) {
13211        if self.read_only(cx) {
13212            return;
13213        }
13214
13215        let clipboard_text = Cow::Borrowed(text.as_str());
13216
13217        self.transact(window, cx, |this, window, cx| {
13218            let had_active_edit_prediction = this.has_active_edit_prediction();
13219            let display_map = this.display_snapshot(cx);
13220            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13221            let cursor_offset = this
13222                .selections
13223                .last::<MultiBufferOffset>(&display_map)
13224                .head();
13225
13226            if let Some(mut clipboard_selections) = clipboard_selections {
13227                let all_selections_were_entire_line =
13228                    clipboard_selections.iter().all(|s| s.is_entire_line);
13229                let first_selection_indent_column =
13230                    clipboard_selections.first().map(|s| s.first_line_indent);
13231                if clipboard_selections.len() != old_selections.len() {
13232                    clipboard_selections.drain(..);
13233                }
13234                let mut auto_indent_on_paste = true;
13235
13236                this.buffer.update(cx, |buffer, cx| {
13237                    let snapshot = buffer.read(cx);
13238                    auto_indent_on_paste = snapshot
13239                        .language_settings_at(cursor_offset, cx)
13240                        .auto_indent_on_paste;
13241
13242                    let mut start_offset = 0;
13243                    let mut edits = Vec::new();
13244                    let mut original_indent_columns = Vec::new();
13245                    for (ix, selection) in old_selections.iter().enumerate() {
13246                        let to_insert;
13247                        let entire_line;
13248                        let original_indent_column;
13249                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13250                            let end_offset = start_offset + clipboard_selection.len;
13251                            to_insert = &clipboard_text[start_offset..end_offset];
13252                            entire_line = clipboard_selection.is_entire_line;
13253                            start_offset = if entire_line {
13254                                end_offset
13255                            } else {
13256                                end_offset + 1
13257                            };
13258                            original_indent_column = Some(clipboard_selection.first_line_indent);
13259                        } else {
13260                            to_insert = &*clipboard_text;
13261                            entire_line = all_selections_were_entire_line;
13262                            original_indent_column = first_selection_indent_column
13263                        }
13264
13265                        let (range, to_insert) =
13266                            if selection.is_empty() && handle_entire_lines && entire_line {
13267                                // If the corresponding selection was empty when this slice of the
13268                                // clipboard text was written, then the entire line containing the
13269                                // selection was copied. If this selection is also currently empty,
13270                                // then paste the line before the current line of the buffer.
13271                                let column = selection.start.to_point(&snapshot).column as usize;
13272                                let line_start = selection.start - column;
13273                                (line_start..line_start, Cow::Borrowed(to_insert))
13274                            } else {
13275                                let language = snapshot.language_at(selection.head());
13276                                let range = selection.range();
13277                                if let Some(language) = language
13278                                    && language.name() == "Markdown".into()
13279                                {
13280                                    edit_for_markdown_paste(
13281                                        &snapshot,
13282                                        range,
13283                                        to_insert,
13284                                        url::Url::parse(to_insert).ok(),
13285                                    )
13286                                } else {
13287                                    (range, Cow::Borrowed(to_insert))
13288                                }
13289                            };
13290
13291                        edits.push((range, to_insert));
13292                        original_indent_columns.push(original_indent_column);
13293                    }
13294                    drop(snapshot);
13295
13296                    buffer.edit(
13297                        edits,
13298                        if auto_indent_on_paste {
13299                            Some(AutoindentMode::Block {
13300                                original_indent_columns,
13301                            })
13302                        } else {
13303                            None
13304                        },
13305                        cx,
13306                    );
13307                });
13308
13309                let selections = this
13310                    .selections
13311                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13312                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13313            } else {
13314                let url = url::Url::parse(&clipboard_text).ok();
13315
13316                let auto_indent_mode = if !clipboard_text.is_empty() {
13317                    Some(AutoindentMode::Block {
13318                        original_indent_columns: Vec::new(),
13319                    })
13320                } else {
13321                    None
13322                };
13323
13324                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13325                    let snapshot = buffer.snapshot(cx);
13326
13327                    let anchors = old_selections
13328                        .iter()
13329                        .map(|s| {
13330                            let anchor = snapshot.anchor_after(s.head());
13331                            s.map(|_| anchor)
13332                        })
13333                        .collect::<Vec<_>>();
13334
13335                    let mut edits = Vec::new();
13336
13337                    for selection in old_selections.iter() {
13338                        let language = snapshot.language_at(selection.head());
13339                        let range = selection.range();
13340
13341                        let (edit_range, edit_text) = if let Some(language) = language
13342                            && language.name() == "Markdown".into()
13343                        {
13344                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13345                        } else {
13346                            (range, clipboard_text.clone())
13347                        };
13348
13349                        edits.push((edit_range, edit_text));
13350                    }
13351
13352                    drop(snapshot);
13353                    buffer.edit(edits, auto_indent_mode, cx);
13354
13355                    anchors
13356                });
13357
13358                this.change_selections(Default::default(), window, cx, |s| {
13359                    s.select_anchors(selection_anchors);
13360                });
13361            }
13362
13363            //   🤔                 |    ..     | show_in_menu |
13364            // | ..                  |   true        true
13365            // | had_edit_prediction |   false       true
13366
13367            let trigger_in_words =
13368                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13369
13370            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13371        });
13372    }
13373
13374    pub fn diff_clipboard_with_selection(
13375        &mut self,
13376        _: &DiffClipboardWithSelection,
13377        window: &mut Window,
13378        cx: &mut Context<Self>,
13379    ) {
13380        let selections = self
13381            .selections
13382            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13383
13384        if selections.is_empty() {
13385            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13386            return;
13387        };
13388
13389        let clipboard_text = match cx.read_from_clipboard() {
13390            Some(item) => match item.entries().first() {
13391                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13392                _ => None,
13393            },
13394            None => None,
13395        };
13396
13397        let Some(clipboard_text) = clipboard_text else {
13398            log::warn!("Clipboard doesn't contain text.");
13399            return;
13400        };
13401
13402        window.dispatch_action(
13403            Box::new(DiffClipboardWithSelectionData {
13404                clipboard_text,
13405                editor: cx.entity(),
13406            }),
13407            cx,
13408        );
13409    }
13410
13411    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13412        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13413        if let Some(item) = cx.read_from_clipboard() {
13414            let entries = item.entries();
13415
13416            match entries.first() {
13417                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13418                // of all the pasted entries.
13419                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13420                    .do_paste(
13421                        clipboard_string.text(),
13422                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13423                        true,
13424                        window,
13425                        cx,
13426                    ),
13427                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13428            }
13429        }
13430    }
13431
13432    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13433        if self.read_only(cx) {
13434            return;
13435        }
13436
13437        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13438
13439        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13440            if let Some((selections, _)) =
13441                self.selection_history.transaction(transaction_id).cloned()
13442            {
13443                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13444                    s.select_anchors(selections.to_vec());
13445                });
13446            } else {
13447                log::error!(
13448                    "No entry in selection_history found for undo. \
13449                     This may correspond to a bug where undo does not update the selection. \
13450                     If this is occurring, please add details to \
13451                     https://github.com/zed-industries/zed/issues/22692"
13452                );
13453            }
13454            self.request_autoscroll(Autoscroll::fit(), cx);
13455            self.unmark_text(window, cx);
13456            self.refresh_edit_prediction(true, false, window, cx);
13457            cx.emit(EditorEvent::Edited { transaction_id });
13458            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13459        }
13460    }
13461
13462    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13463        if self.read_only(cx) {
13464            return;
13465        }
13466
13467        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13468
13469        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13470            if let Some((_, Some(selections))) =
13471                self.selection_history.transaction(transaction_id).cloned()
13472            {
13473                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13474                    s.select_anchors(selections.to_vec());
13475                });
13476            } else {
13477                log::error!(
13478                    "No entry in selection_history found for redo. \
13479                     This may correspond to a bug where undo does not update the selection. \
13480                     If this is occurring, please add details to \
13481                     https://github.com/zed-industries/zed/issues/22692"
13482                );
13483            }
13484            self.request_autoscroll(Autoscroll::fit(), cx);
13485            self.unmark_text(window, cx);
13486            self.refresh_edit_prediction(true, false, window, cx);
13487            cx.emit(EditorEvent::Edited { transaction_id });
13488        }
13489    }
13490
13491    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13492        self.buffer
13493            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13494    }
13495
13496    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13497        self.buffer
13498            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13499    }
13500
13501    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13502        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13503        self.change_selections(Default::default(), window, cx, |s| {
13504            s.move_with(|map, selection| {
13505                let cursor = if selection.is_empty() {
13506                    movement::left(map, selection.start)
13507                } else {
13508                    selection.start
13509                };
13510                selection.collapse_to(cursor, SelectionGoal::None);
13511            });
13512        })
13513    }
13514
13515    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13516        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13517        self.change_selections(Default::default(), window, cx, |s| {
13518            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13519        })
13520    }
13521
13522    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13523        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13524        self.change_selections(Default::default(), window, cx, |s| {
13525            s.move_with(|map, selection| {
13526                let cursor = if selection.is_empty() {
13527                    movement::right(map, selection.end)
13528                } else {
13529                    selection.end
13530                };
13531                selection.collapse_to(cursor, SelectionGoal::None)
13532            });
13533        })
13534    }
13535
13536    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13537        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13538        self.change_selections(Default::default(), window, cx, |s| {
13539            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13540        });
13541    }
13542
13543    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13544        if self.take_rename(true, window, cx).is_some() {
13545            return;
13546        }
13547
13548        if self.mode.is_single_line() {
13549            cx.propagate();
13550            return;
13551        }
13552
13553        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13554
13555        let text_layout_details = &self.text_layout_details(window);
13556        let selection_count = self.selections.count();
13557        let first_selection = self.selections.first_anchor();
13558
13559        self.change_selections(Default::default(), window, cx, |s| {
13560            s.move_with(|map, selection| {
13561                if !selection.is_empty() {
13562                    selection.goal = SelectionGoal::None;
13563                }
13564                let (cursor, goal) = movement::up(
13565                    map,
13566                    selection.start,
13567                    selection.goal,
13568                    false,
13569                    text_layout_details,
13570                );
13571                selection.collapse_to(cursor, goal);
13572            });
13573        });
13574
13575        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13576        {
13577            cx.propagate();
13578        }
13579    }
13580
13581    pub fn move_up_by_lines(
13582        &mut self,
13583        action: &MoveUpByLines,
13584        window: &mut Window,
13585        cx: &mut Context<Self>,
13586    ) {
13587        if self.take_rename(true, window, cx).is_some() {
13588            return;
13589        }
13590
13591        if self.mode.is_single_line() {
13592            cx.propagate();
13593            return;
13594        }
13595
13596        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13597
13598        let text_layout_details = &self.text_layout_details(window);
13599
13600        self.change_selections(Default::default(), window, cx, |s| {
13601            s.move_with(|map, selection| {
13602                if !selection.is_empty() {
13603                    selection.goal = SelectionGoal::None;
13604                }
13605                let (cursor, goal) = movement::up_by_rows(
13606                    map,
13607                    selection.start,
13608                    action.lines,
13609                    selection.goal,
13610                    false,
13611                    text_layout_details,
13612                );
13613                selection.collapse_to(cursor, goal);
13614            });
13615        })
13616    }
13617
13618    pub fn move_down_by_lines(
13619        &mut self,
13620        action: &MoveDownByLines,
13621        window: &mut Window,
13622        cx: &mut Context<Self>,
13623    ) {
13624        if self.take_rename(true, window, cx).is_some() {
13625            return;
13626        }
13627
13628        if self.mode.is_single_line() {
13629            cx.propagate();
13630            return;
13631        }
13632
13633        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13634
13635        let text_layout_details = &self.text_layout_details(window);
13636
13637        self.change_selections(Default::default(), window, cx, |s| {
13638            s.move_with(|map, selection| {
13639                if !selection.is_empty() {
13640                    selection.goal = SelectionGoal::None;
13641                }
13642                let (cursor, goal) = movement::down_by_rows(
13643                    map,
13644                    selection.start,
13645                    action.lines,
13646                    selection.goal,
13647                    false,
13648                    text_layout_details,
13649                );
13650                selection.collapse_to(cursor, goal);
13651            });
13652        })
13653    }
13654
13655    pub fn select_down_by_lines(
13656        &mut self,
13657        action: &SelectDownByLines,
13658        window: &mut Window,
13659        cx: &mut Context<Self>,
13660    ) {
13661        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13662        let text_layout_details = &self.text_layout_details(window);
13663        self.change_selections(Default::default(), window, cx, |s| {
13664            s.move_heads_with(|map, head, goal| {
13665                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13666            })
13667        })
13668    }
13669
13670    pub fn select_up_by_lines(
13671        &mut self,
13672        action: &SelectUpByLines,
13673        window: &mut Window,
13674        cx: &mut Context<Self>,
13675    ) {
13676        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13677        let text_layout_details = &self.text_layout_details(window);
13678        self.change_selections(Default::default(), window, cx, |s| {
13679            s.move_heads_with(|map, head, goal| {
13680                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13681            })
13682        })
13683    }
13684
13685    pub fn select_page_up(
13686        &mut self,
13687        _: &SelectPageUp,
13688        window: &mut Window,
13689        cx: &mut Context<Self>,
13690    ) {
13691        let Some(row_count) = self.visible_row_count() else {
13692            return;
13693        };
13694
13695        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13696
13697        let text_layout_details = &self.text_layout_details(window);
13698
13699        self.change_selections(Default::default(), window, cx, |s| {
13700            s.move_heads_with(|map, head, goal| {
13701                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13702            })
13703        })
13704    }
13705
13706    pub fn move_page_up(
13707        &mut self,
13708        action: &MovePageUp,
13709        window: &mut Window,
13710        cx: &mut Context<Self>,
13711    ) {
13712        if self.take_rename(true, window, cx).is_some() {
13713            return;
13714        }
13715
13716        if self
13717            .context_menu
13718            .borrow_mut()
13719            .as_mut()
13720            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13721            .unwrap_or(false)
13722        {
13723            return;
13724        }
13725
13726        if matches!(self.mode, EditorMode::SingleLine) {
13727            cx.propagate();
13728            return;
13729        }
13730
13731        let Some(row_count) = self.visible_row_count() else {
13732            return;
13733        };
13734
13735        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13736
13737        let effects = if action.center_cursor {
13738            SelectionEffects::scroll(Autoscroll::center())
13739        } else {
13740            SelectionEffects::default()
13741        };
13742
13743        let text_layout_details = &self.text_layout_details(window);
13744
13745        self.change_selections(effects, window, cx, |s| {
13746            s.move_with(|map, selection| {
13747                if !selection.is_empty() {
13748                    selection.goal = SelectionGoal::None;
13749                }
13750                let (cursor, goal) = movement::up_by_rows(
13751                    map,
13752                    selection.end,
13753                    row_count,
13754                    selection.goal,
13755                    false,
13756                    text_layout_details,
13757                );
13758                selection.collapse_to(cursor, goal);
13759            });
13760        });
13761    }
13762
13763    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13764        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13765        let text_layout_details = &self.text_layout_details(window);
13766        self.change_selections(Default::default(), window, cx, |s| {
13767            s.move_heads_with(|map, head, goal| {
13768                movement::up(map, head, goal, false, text_layout_details)
13769            })
13770        })
13771    }
13772
13773    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13774        self.take_rename(true, window, cx);
13775
13776        if self.mode.is_single_line() {
13777            cx.propagate();
13778            return;
13779        }
13780
13781        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13782
13783        let text_layout_details = &self.text_layout_details(window);
13784        let selection_count = self.selections.count();
13785        let first_selection = self.selections.first_anchor();
13786
13787        self.change_selections(Default::default(), window, cx, |s| {
13788            s.move_with(|map, selection| {
13789                if !selection.is_empty() {
13790                    selection.goal = SelectionGoal::None;
13791                }
13792                let (cursor, goal) = movement::down(
13793                    map,
13794                    selection.end,
13795                    selection.goal,
13796                    false,
13797                    text_layout_details,
13798                );
13799                selection.collapse_to(cursor, goal);
13800            });
13801        });
13802
13803        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13804        {
13805            cx.propagate();
13806        }
13807    }
13808
13809    pub fn select_page_down(
13810        &mut self,
13811        _: &SelectPageDown,
13812        window: &mut Window,
13813        cx: &mut Context<Self>,
13814    ) {
13815        let Some(row_count) = self.visible_row_count() else {
13816            return;
13817        };
13818
13819        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13820
13821        let text_layout_details = &self.text_layout_details(window);
13822
13823        self.change_selections(Default::default(), window, cx, |s| {
13824            s.move_heads_with(|map, head, goal| {
13825                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13826            })
13827        })
13828    }
13829
13830    pub fn move_page_down(
13831        &mut self,
13832        action: &MovePageDown,
13833        window: &mut Window,
13834        cx: &mut Context<Self>,
13835    ) {
13836        if self.take_rename(true, window, cx).is_some() {
13837            return;
13838        }
13839
13840        if self
13841            .context_menu
13842            .borrow_mut()
13843            .as_mut()
13844            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13845            .unwrap_or(false)
13846        {
13847            return;
13848        }
13849
13850        if matches!(self.mode, EditorMode::SingleLine) {
13851            cx.propagate();
13852            return;
13853        }
13854
13855        let Some(row_count) = self.visible_row_count() else {
13856            return;
13857        };
13858
13859        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13860
13861        let effects = if action.center_cursor {
13862            SelectionEffects::scroll(Autoscroll::center())
13863        } else {
13864            SelectionEffects::default()
13865        };
13866
13867        let text_layout_details = &self.text_layout_details(window);
13868        self.change_selections(effects, window, cx, |s| {
13869            s.move_with(|map, selection| {
13870                if !selection.is_empty() {
13871                    selection.goal = SelectionGoal::None;
13872                }
13873                let (cursor, goal) = movement::down_by_rows(
13874                    map,
13875                    selection.end,
13876                    row_count,
13877                    selection.goal,
13878                    false,
13879                    text_layout_details,
13880                );
13881                selection.collapse_to(cursor, goal);
13882            });
13883        });
13884    }
13885
13886    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13887        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13888        let text_layout_details = &self.text_layout_details(window);
13889        self.change_selections(Default::default(), window, cx, |s| {
13890            s.move_heads_with(|map, head, goal| {
13891                movement::down(map, head, goal, false, text_layout_details)
13892            })
13893        });
13894    }
13895
13896    pub fn context_menu_first(
13897        &mut self,
13898        _: &ContextMenuFirst,
13899        window: &mut Window,
13900        cx: &mut Context<Self>,
13901    ) {
13902        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13903            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13904        }
13905    }
13906
13907    pub fn context_menu_prev(
13908        &mut self,
13909        _: &ContextMenuPrevious,
13910        window: &mut Window,
13911        cx: &mut Context<Self>,
13912    ) {
13913        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13914            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13915        }
13916    }
13917
13918    pub fn context_menu_next(
13919        &mut self,
13920        _: &ContextMenuNext,
13921        window: &mut Window,
13922        cx: &mut Context<Self>,
13923    ) {
13924        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13925            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13926        }
13927    }
13928
13929    pub fn context_menu_last(
13930        &mut self,
13931        _: &ContextMenuLast,
13932        window: &mut Window,
13933        cx: &mut Context<Self>,
13934    ) {
13935        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13936            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13937        }
13938    }
13939
13940    pub fn signature_help_prev(
13941        &mut self,
13942        _: &SignatureHelpPrevious,
13943        _: &mut Window,
13944        cx: &mut Context<Self>,
13945    ) {
13946        if let Some(popover) = self.signature_help_state.popover_mut() {
13947            if popover.current_signature == 0 {
13948                popover.current_signature = popover.signatures.len() - 1;
13949            } else {
13950                popover.current_signature -= 1;
13951            }
13952            cx.notify();
13953        }
13954    }
13955
13956    pub fn signature_help_next(
13957        &mut self,
13958        _: &SignatureHelpNext,
13959        _: &mut Window,
13960        cx: &mut Context<Self>,
13961    ) {
13962        if let Some(popover) = self.signature_help_state.popover_mut() {
13963            if popover.current_signature + 1 == popover.signatures.len() {
13964                popover.current_signature = 0;
13965            } else {
13966                popover.current_signature += 1;
13967            }
13968            cx.notify();
13969        }
13970    }
13971
13972    pub fn move_to_previous_word_start(
13973        &mut self,
13974        _: &MoveToPreviousWordStart,
13975        window: &mut Window,
13976        cx: &mut Context<Self>,
13977    ) {
13978        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13979        self.change_selections(Default::default(), window, cx, |s| {
13980            s.move_cursors_with(|map, head, _| {
13981                (
13982                    movement::previous_word_start(map, head),
13983                    SelectionGoal::None,
13984                )
13985            });
13986        })
13987    }
13988
13989    pub fn move_to_previous_subword_start(
13990        &mut self,
13991        _: &MoveToPreviousSubwordStart,
13992        window: &mut Window,
13993        cx: &mut Context<Self>,
13994    ) {
13995        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13996        self.change_selections(Default::default(), window, cx, |s| {
13997            s.move_cursors_with(|map, head, _| {
13998                (
13999                    movement::previous_subword_start(map, head),
14000                    SelectionGoal::None,
14001                )
14002            });
14003        })
14004    }
14005
14006    pub fn select_to_previous_word_start(
14007        &mut self,
14008        _: &SelectToPreviousWordStart,
14009        window: &mut Window,
14010        cx: &mut Context<Self>,
14011    ) {
14012        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14013        self.change_selections(Default::default(), window, cx, |s| {
14014            s.move_heads_with(|map, head, _| {
14015                (
14016                    movement::previous_word_start(map, head),
14017                    SelectionGoal::None,
14018                )
14019            });
14020        })
14021    }
14022
14023    pub fn select_to_previous_subword_start(
14024        &mut self,
14025        _: &SelectToPreviousSubwordStart,
14026        window: &mut Window,
14027        cx: &mut Context<Self>,
14028    ) {
14029        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14030        self.change_selections(Default::default(), window, cx, |s| {
14031            s.move_heads_with(|map, head, _| {
14032                (
14033                    movement::previous_subword_start(map, head),
14034                    SelectionGoal::None,
14035                )
14036            });
14037        })
14038    }
14039
14040    pub fn delete_to_previous_word_start(
14041        &mut self,
14042        action: &DeleteToPreviousWordStart,
14043        window: &mut Window,
14044        cx: &mut Context<Self>,
14045    ) {
14046        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14047        self.transact(window, cx, |this, window, cx| {
14048            this.select_autoclose_pair(window, cx);
14049            this.change_selections(Default::default(), window, cx, |s| {
14050                s.move_with(|map, selection| {
14051                    if selection.is_empty() {
14052                        let mut cursor = if action.ignore_newlines {
14053                            movement::previous_word_start(map, selection.head())
14054                        } else {
14055                            movement::previous_word_start_or_newline(map, selection.head())
14056                        };
14057                        cursor = movement::adjust_greedy_deletion(
14058                            map,
14059                            selection.head(),
14060                            cursor,
14061                            action.ignore_brackets,
14062                        );
14063                        selection.set_head(cursor, SelectionGoal::None);
14064                    }
14065                });
14066            });
14067            this.insert("", window, cx);
14068        });
14069    }
14070
14071    pub fn delete_to_previous_subword_start(
14072        &mut self,
14073        _: &DeleteToPreviousSubwordStart,
14074        window: &mut Window,
14075        cx: &mut Context<Self>,
14076    ) {
14077        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14078        self.transact(window, cx, |this, window, cx| {
14079            this.select_autoclose_pair(window, cx);
14080            this.change_selections(Default::default(), window, cx, |s| {
14081                s.move_with(|map, selection| {
14082                    if selection.is_empty() {
14083                        let mut cursor = movement::previous_subword_start(map, selection.head());
14084                        cursor =
14085                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14086                        selection.set_head(cursor, SelectionGoal::None);
14087                    }
14088                });
14089            });
14090            this.insert("", window, cx);
14091        });
14092    }
14093
14094    pub fn move_to_next_word_end(
14095        &mut self,
14096        _: &MoveToNextWordEnd,
14097        window: &mut Window,
14098        cx: &mut Context<Self>,
14099    ) {
14100        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14101        self.change_selections(Default::default(), window, cx, |s| {
14102            s.move_cursors_with(|map, head, _| {
14103                (movement::next_word_end(map, head), SelectionGoal::None)
14104            });
14105        })
14106    }
14107
14108    pub fn move_to_next_subword_end(
14109        &mut self,
14110        _: &MoveToNextSubwordEnd,
14111        window: &mut Window,
14112        cx: &mut Context<Self>,
14113    ) {
14114        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14115        self.change_selections(Default::default(), window, cx, |s| {
14116            s.move_cursors_with(|map, head, _| {
14117                (movement::next_subword_end(map, head), SelectionGoal::None)
14118            });
14119        })
14120    }
14121
14122    pub fn select_to_next_word_end(
14123        &mut self,
14124        _: &SelectToNextWordEnd,
14125        window: &mut Window,
14126        cx: &mut Context<Self>,
14127    ) {
14128        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14129        self.change_selections(Default::default(), window, cx, |s| {
14130            s.move_heads_with(|map, head, _| {
14131                (movement::next_word_end(map, head), SelectionGoal::None)
14132            });
14133        })
14134    }
14135
14136    pub fn select_to_next_subword_end(
14137        &mut self,
14138        _: &SelectToNextSubwordEnd,
14139        window: &mut Window,
14140        cx: &mut Context<Self>,
14141    ) {
14142        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14143        self.change_selections(Default::default(), window, cx, |s| {
14144            s.move_heads_with(|map, head, _| {
14145                (movement::next_subword_end(map, head), SelectionGoal::None)
14146            });
14147        })
14148    }
14149
14150    pub fn delete_to_next_word_end(
14151        &mut self,
14152        action: &DeleteToNextWordEnd,
14153        window: &mut Window,
14154        cx: &mut Context<Self>,
14155    ) {
14156        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14157        self.transact(window, cx, |this, window, cx| {
14158            this.change_selections(Default::default(), window, cx, |s| {
14159                s.move_with(|map, selection| {
14160                    if selection.is_empty() {
14161                        let mut cursor = if action.ignore_newlines {
14162                            movement::next_word_end(map, selection.head())
14163                        } else {
14164                            movement::next_word_end_or_newline(map, selection.head())
14165                        };
14166                        cursor = movement::adjust_greedy_deletion(
14167                            map,
14168                            selection.head(),
14169                            cursor,
14170                            action.ignore_brackets,
14171                        );
14172                        selection.set_head(cursor, SelectionGoal::None);
14173                    }
14174                });
14175            });
14176            this.insert("", window, cx);
14177        });
14178    }
14179
14180    pub fn delete_to_next_subword_end(
14181        &mut self,
14182        _: &DeleteToNextSubwordEnd,
14183        window: &mut Window,
14184        cx: &mut Context<Self>,
14185    ) {
14186        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14187        self.transact(window, cx, |this, window, cx| {
14188            this.change_selections(Default::default(), window, cx, |s| {
14189                s.move_with(|map, selection| {
14190                    if selection.is_empty() {
14191                        let mut cursor = movement::next_subword_end(map, selection.head());
14192                        cursor =
14193                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14194                        selection.set_head(cursor, SelectionGoal::None);
14195                    }
14196                });
14197            });
14198            this.insert("", window, cx);
14199        });
14200    }
14201
14202    pub fn move_to_beginning_of_line(
14203        &mut self,
14204        action: &MoveToBeginningOfLine,
14205        window: &mut Window,
14206        cx: &mut Context<Self>,
14207    ) {
14208        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14209        self.change_selections(Default::default(), window, cx, |s| {
14210            s.move_cursors_with(|map, head, _| {
14211                (
14212                    movement::indented_line_beginning(
14213                        map,
14214                        head,
14215                        action.stop_at_soft_wraps,
14216                        action.stop_at_indent,
14217                    ),
14218                    SelectionGoal::None,
14219                )
14220            });
14221        })
14222    }
14223
14224    pub fn select_to_beginning_of_line(
14225        &mut self,
14226        action: &SelectToBeginningOfLine,
14227        window: &mut Window,
14228        cx: &mut Context<Self>,
14229    ) {
14230        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14231        self.change_selections(Default::default(), window, cx, |s| {
14232            s.move_heads_with(|map, head, _| {
14233                (
14234                    movement::indented_line_beginning(
14235                        map,
14236                        head,
14237                        action.stop_at_soft_wraps,
14238                        action.stop_at_indent,
14239                    ),
14240                    SelectionGoal::None,
14241                )
14242            });
14243        });
14244    }
14245
14246    pub fn delete_to_beginning_of_line(
14247        &mut self,
14248        action: &DeleteToBeginningOfLine,
14249        window: &mut Window,
14250        cx: &mut Context<Self>,
14251    ) {
14252        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14253        self.transact(window, cx, |this, window, cx| {
14254            this.change_selections(Default::default(), window, cx, |s| {
14255                s.move_with(|_, selection| {
14256                    selection.reversed = true;
14257                });
14258            });
14259
14260            this.select_to_beginning_of_line(
14261                &SelectToBeginningOfLine {
14262                    stop_at_soft_wraps: false,
14263                    stop_at_indent: action.stop_at_indent,
14264                },
14265                window,
14266                cx,
14267            );
14268            this.backspace(&Backspace, window, cx);
14269        });
14270    }
14271
14272    pub fn move_to_end_of_line(
14273        &mut self,
14274        action: &MoveToEndOfLine,
14275        window: &mut Window,
14276        cx: &mut Context<Self>,
14277    ) {
14278        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14279        self.change_selections(Default::default(), window, cx, |s| {
14280            s.move_cursors_with(|map, head, _| {
14281                (
14282                    movement::line_end(map, head, action.stop_at_soft_wraps),
14283                    SelectionGoal::None,
14284                )
14285            });
14286        })
14287    }
14288
14289    pub fn select_to_end_of_line(
14290        &mut self,
14291        action: &SelectToEndOfLine,
14292        window: &mut Window,
14293        cx: &mut Context<Self>,
14294    ) {
14295        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14296        self.change_selections(Default::default(), window, cx, |s| {
14297            s.move_heads_with(|map, head, _| {
14298                (
14299                    movement::line_end(map, head, action.stop_at_soft_wraps),
14300                    SelectionGoal::None,
14301                )
14302            });
14303        })
14304    }
14305
14306    pub fn delete_to_end_of_line(
14307        &mut self,
14308        _: &DeleteToEndOfLine,
14309        window: &mut Window,
14310        cx: &mut Context<Self>,
14311    ) {
14312        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14313        self.transact(window, cx, |this, window, cx| {
14314            this.select_to_end_of_line(
14315                &SelectToEndOfLine {
14316                    stop_at_soft_wraps: false,
14317                },
14318                window,
14319                cx,
14320            );
14321            this.delete(&Delete, window, cx);
14322        });
14323    }
14324
14325    pub fn cut_to_end_of_line(
14326        &mut self,
14327        action: &CutToEndOfLine,
14328        window: &mut Window,
14329        cx: &mut Context<Self>,
14330    ) {
14331        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14332        self.transact(window, cx, |this, window, cx| {
14333            this.select_to_end_of_line(
14334                &SelectToEndOfLine {
14335                    stop_at_soft_wraps: false,
14336                },
14337                window,
14338                cx,
14339            );
14340            if !action.stop_at_newlines {
14341                this.change_selections(Default::default(), window, cx, |s| {
14342                    s.move_with(|_, sel| {
14343                        if sel.is_empty() {
14344                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14345                        }
14346                    });
14347                });
14348            }
14349            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14350            let item = this.cut_common(false, window, cx);
14351            cx.write_to_clipboard(item);
14352        });
14353    }
14354
14355    pub fn move_to_start_of_paragraph(
14356        &mut self,
14357        _: &MoveToStartOfParagraph,
14358        window: &mut Window,
14359        cx: &mut Context<Self>,
14360    ) {
14361        if matches!(self.mode, EditorMode::SingleLine) {
14362            cx.propagate();
14363            return;
14364        }
14365        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14366        self.change_selections(Default::default(), window, cx, |s| {
14367            s.move_with(|map, selection| {
14368                selection.collapse_to(
14369                    movement::start_of_paragraph(map, selection.head(), 1),
14370                    SelectionGoal::None,
14371                )
14372            });
14373        })
14374    }
14375
14376    pub fn move_to_end_of_paragraph(
14377        &mut self,
14378        _: &MoveToEndOfParagraph,
14379        window: &mut Window,
14380        cx: &mut Context<Self>,
14381    ) {
14382        if matches!(self.mode, EditorMode::SingleLine) {
14383            cx.propagate();
14384            return;
14385        }
14386        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14387        self.change_selections(Default::default(), window, cx, |s| {
14388            s.move_with(|map, selection| {
14389                selection.collapse_to(
14390                    movement::end_of_paragraph(map, selection.head(), 1),
14391                    SelectionGoal::None,
14392                )
14393            });
14394        })
14395    }
14396
14397    pub fn select_to_start_of_paragraph(
14398        &mut self,
14399        _: &SelectToStartOfParagraph,
14400        window: &mut Window,
14401        cx: &mut Context<Self>,
14402    ) {
14403        if matches!(self.mode, EditorMode::SingleLine) {
14404            cx.propagate();
14405            return;
14406        }
14407        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14408        self.change_selections(Default::default(), window, cx, |s| {
14409            s.move_heads_with(|map, head, _| {
14410                (
14411                    movement::start_of_paragraph(map, head, 1),
14412                    SelectionGoal::None,
14413                )
14414            });
14415        })
14416    }
14417
14418    pub fn select_to_end_of_paragraph(
14419        &mut self,
14420        _: &SelectToEndOfParagraph,
14421        window: &mut Window,
14422        cx: &mut Context<Self>,
14423    ) {
14424        if matches!(self.mode, EditorMode::SingleLine) {
14425            cx.propagate();
14426            return;
14427        }
14428        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14429        self.change_selections(Default::default(), window, cx, |s| {
14430            s.move_heads_with(|map, head, _| {
14431                (
14432                    movement::end_of_paragraph(map, head, 1),
14433                    SelectionGoal::None,
14434                )
14435            });
14436        })
14437    }
14438
14439    pub fn move_to_start_of_excerpt(
14440        &mut self,
14441        _: &MoveToStartOfExcerpt,
14442        window: &mut Window,
14443        cx: &mut Context<Self>,
14444    ) {
14445        if matches!(self.mode, EditorMode::SingleLine) {
14446            cx.propagate();
14447            return;
14448        }
14449        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14450        self.change_selections(Default::default(), window, cx, |s| {
14451            s.move_with(|map, selection| {
14452                selection.collapse_to(
14453                    movement::start_of_excerpt(
14454                        map,
14455                        selection.head(),
14456                        workspace::searchable::Direction::Prev,
14457                    ),
14458                    SelectionGoal::None,
14459                )
14460            });
14461        })
14462    }
14463
14464    pub fn move_to_start_of_next_excerpt(
14465        &mut self,
14466        _: &MoveToStartOfNextExcerpt,
14467        window: &mut Window,
14468        cx: &mut Context<Self>,
14469    ) {
14470        if matches!(self.mode, EditorMode::SingleLine) {
14471            cx.propagate();
14472            return;
14473        }
14474
14475        self.change_selections(Default::default(), window, cx, |s| {
14476            s.move_with(|map, selection| {
14477                selection.collapse_to(
14478                    movement::start_of_excerpt(
14479                        map,
14480                        selection.head(),
14481                        workspace::searchable::Direction::Next,
14482                    ),
14483                    SelectionGoal::None,
14484                )
14485            });
14486        })
14487    }
14488
14489    pub fn move_to_end_of_excerpt(
14490        &mut self,
14491        _: &MoveToEndOfExcerpt,
14492        window: &mut Window,
14493        cx: &mut Context<Self>,
14494    ) {
14495        if matches!(self.mode, EditorMode::SingleLine) {
14496            cx.propagate();
14497            return;
14498        }
14499        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14500        self.change_selections(Default::default(), window, cx, |s| {
14501            s.move_with(|map, selection| {
14502                selection.collapse_to(
14503                    movement::end_of_excerpt(
14504                        map,
14505                        selection.head(),
14506                        workspace::searchable::Direction::Next,
14507                    ),
14508                    SelectionGoal::None,
14509                )
14510            });
14511        })
14512    }
14513
14514    pub fn move_to_end_of_previous_excerpt(
14515        &mut self,
14516        _: &MoveToEndOfPreviousExcerpt,
14517        window: &mut Window,
14518        cx: &mut Context<Self>,
14519    ) {
14520        if matches!(self.mode, EditorMode::SingleLine) {
14521            cx.propagate();
14522            return;
14523        }
14524        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14525        self.change_selections(Default::default(), window, cx, |s| {
14526            s.move_with(|map, selection| {
14527                selection.collapse_to(
14528                    movement::end_of_excerpt(
14529                        map,
14530                        selection.head(),
14531                        workspace::searchable::Direction::Prev,
14532                    ),
14533                    SelectionGoal::None,
14534                )
14535            });
14536        })
14537    }
14538
14539    pub fn select_to_start_of_excerpt(
14540        &mut self,
14541        _: &SelectToStartOfExcerpt,
14542        window: &mut Window,
14543        cx: &mut Context<Self>,
14544    ) {
14545        if matches!(self.mode, EditorMode::SingleLine) {
14546            cx.propagate();
14547            return;
14548        }
14549        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14550        self.change_selections(Default::default(), window, cx, |s| {
14551            s.move_heads_with(|map, head, _| {
14552                (
14553                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14554                    SelectionGoal::None,
14555                )
14556            });
14557        })
14558    }
14559
14560    pub fn select_to_start_of_next_excerpt(
14561        &mut self,
14562        _: &SelectToStartOfNextExcerpt,
14563        window: &mut Window,
14564        cx: &mut Context<Self>,
14565    ) {
14566        if matches!(self.mode, EditorMode::SingleLine) {
14567            cx.propagate();
14568            return;
14569        }
14570        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14571        self.change_selections(Default::default(), window, cx, |s| {
14572            s.move_heads_with(|map, head, _| {
14573                (
14574                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14575                    SelectionGoal::None,
14576                )
14577            });
14578        })
14579    }
14580
14581    pub fn select_to_end_of_excerpt(
14582        &mut self,
14583        _: &SelectToEndOfExcerpt,
14584        window: &mut Window,
14585        cx: &mut Context<Self>,
14586    ) {
14587        if matches!(self.mode, EditorMode::SingleLine) {
14588            cx.propagate();
14589            return;
14590        }
14591        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14592        self.change_selections(Default::default(), window, cx, |s| {
14593            s.move_heads_with(|map, head, _| {
14594                (
14595                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14596                    SelectionGoal::None,
14597                )
14598            });
14599        })
14600    }
14601
14602    pub fn select_to_end_of_previous_excerpt(
14603        &mut self,
14604        _: &SelectToEndOfPreviousExcerpt,
14605        window: &mut Window,
14606        cx: &mut Context<Self>,
14607    ) {
14608        if matches!(self.mode, EditorMode::SingleLine) {
14609            cx.propagate();
14610            return;
14611        }
14612        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14613        self.change_selections(Default::default(), window, cx, |s| {
14614            s.move_heads_with(|map, head, _| {
14615                (
14616                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14617                    SelectionGoal::None,
14618                )
14619            });
14620        })
14621    }
14622
14623    pub fn move_to_beginning(
14624        &mut self,
14625        _: &MoveToBeginning,
14626        window: &mut Window,
14627        cx: &mut Context<Self>,
14628    ) {
14629        if matches!(self.mode, EditorMode::SingleLine) {
14630            cx.propagate();
14631            return;
14632        }
14633        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14634        self.change_selections(Default::default(), window, cx, |s| {
14635            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14636        });
14637    }
14638
14639    pub fn select_to_beginning(
14640        &mut self,
14641        _: &SelectToBeginning,
14642        window: &mut Window,
14643        cx: &mut Context<Self>,
14644    ) {
14645        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14646        selection.set_head(Point::zero(), SelectionGoal::None);
14647        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14648        self.change_selections(Default::default(), window, cx, |s| {
14649            s.select(vec![selection]);
14650        });
14651    }
14652
14653    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14654        if matches!(self.mode, EditorMode::SingleLine) {
14655            cx.propagate();
14656            return;
14657        }
14658        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14659        let cursor = self.buffer.read(cx).read(cx).len();
14660        self.change_selections(Default::default(), window, cx, |s| {
14661            s.select_ranges(vec![cursor..cursor])
14662        });
14663    }
14664
14665    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14666        self.nav_history = nav_history;
14667    }
14668
14669    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14670        self.nav_history.as_ref()
14671    }
14672
14673    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14674        self.push_to_nav_history(
14675            self.selections.newest_anchor().head(),
14676            None,
14677            false,
14678            true,
14679            cx,
14680        );
14681    }
14682
14683    fn push_to_nav_history(
14684        &mut self,
14685        cursor_anchor: Anchor,
14686        new_position: Option<Point>,
14687        is_deactivate: bool,
14688        always: bool,
14689        cx: &mut Context<Self>,
14690    ) {
14691        if let Some(nav_history) = self.nav_history.as_mut() {
14692            let buffer = self.buffer.read(cx).read(cx);
14693            let cursor_position = cursor_anchor.to_point(&buffer);
14694            let scroll_state = self.scroll_manager.anchor();
14695            let scroll_top_row = scroll_state.top_row(&buffer);
14696            drop(buffer);
14697
14698            if let Some(new_position) = new_position {
14699                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14700                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14701                    return;
14702                }
14703            }
14704
14705            nav_history.push(
14706                Some(NavigationData {
14707                    cursor_anchor,
14708                    cursor_position,
14709                    scroll_anchor: scroll_state,
14710                    scroll_top_row,
14711                }),
14712                cx,
14713            );
14714            cx.emit(EditorEvent::PushedToNavHistory {
14715                anchor: cursor_anchor,
14716                is_deactivate,
14717            })
14718        }
14719    }
14720
14721    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14722        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14723        let buffer = self.buffer.read(cx).snapshot(cx);
14724        let mut selection = self
14725            .selections
14726            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14727        selection.set_head(buffer.len(), SelectionGoal::None);
14728        self.change_selections(Default::default(), window, cx, |s| {
14729            s.select(vec![selection]);
14730        });
14731    }
14732
14733    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14734        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14735        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14736            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14737        });
14738    }
14739
14740    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14741        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14742        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14743        let mut selections = self.selections.all::<Point>(&display_map);
14744        let max_point = display_map.buffer_snapshot().max_point();
14745        for selection in &mut selections {
14746            let rows = selection.spanned_rows(true, &display_map);
14747            selection.start = Point::new(rows.start.0, 0);
14748            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14749            selection.reversed = false;
14750        }
14751        self.change_selections(Default::default(), window, cx, |s| {
14752            s.select(selections);
14753        });
14754    }
14755
14756    pub fn split_selection_into_lines(
14757        &mut self,
14758        action: &SplitSelectionIntoLines,
14759        window: &mut Window,
14760        cx: &mut Context<Self>,
14761    ) {
14762        let selections = self
14763            .selections
14764            .all::<Point>(&self.display_snapshot(cx))
14765            .into_iter()
14766            .map(|selection| selection.start..selection.end)
14767            .collect::<Vec<_>>();
14768        self.unfold_ranges(&selections, true, true, cx);
14769
14770        let mut new_selection_ranges = Vec::new();
14771        {
14772            let buffer = self.buffer.read(cx).read(cx);
14773            for selection in selections {
14774                for row in selection.start.row..selection.end.row {
14775                    let line_start = Point::new(row, 0);
14776                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14777
14778                    if action.keep_selections {
14779                        // Keep the selection range for each line
14780                        let selection_start = if row == selection.start.row {
14781                            selection.start
14782                        } else {
14783                            line_start
14784                        };
14785                        new_selection_ranges.push(selection_start..line_end);
14786                    } else {
14787                        // Collapse to cursor at end of line
14788                        new_selection_ranges.push(line_end..line_end);
14789                    }
14790                }
14791
14792                let is_multiline_selection = selection.start.row != selection.end.row;
14793                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14794                // so this action feels more ergonomic when paired with other selection operations
14795                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14796                if !should_skip_last {
14797                    if action.keep_selections {
14798                        if is_multiline_selection {
14799                            let line_start = Point::new(selection.end.row, 0);
14800                            new_selection_ranges.push(line_start..selection.end);
14801                        } else {
14802                            new_selection_ranges.push(selection.start..selection.end);
14803                        }
14804                    } else {
14805                        new_selection_ranges.push(selection.end..selection.end);
14806                    }
14807                }
14808            }
14809        }
14810        self.change_selections(Default::default(), window, cx, |s| {
14811            s.select_ranges(new_selection_ranges);
14812        });
14813    }
14814
14815    pub fn add_selection_above(
14816        &mut self,
14817        action: &AddSelectionAbove,
14818        window: &mut Window,
14819        cx: &mut Context<Self>,
14820    ) {
14821        self.add_selection(true, action.skip_soft_wrap, window, cx);
14822    }
14823
14824    pub fn add_selection_below(
14825        &mut self,
14826        action: &AddSelectionBelow,
14827        window: &mut Window,
14828        cx: &mut Context<Self>,
14829    ) {
14830        self.add_selection(false, action.skip_soft_wrap, window, cx);
14831    }
14832
14833    fn add_selection(
14834        &mut self,
14835        above: bool,
14836        skip_soft_wrap: bool,
14837        window: &mut Window,
14838        cx: &mut Context<Self>,
14839    ) {
14840        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14841
14842        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14843        let all_selections = self.selections.all::<Point>(&display_map);
14844        let text_layout_details = self.text_layout_details(window);
14845
14846        let (mut columnar_selections, new_selections_to_columnarize) = {
14847            if let Some(state) = self.add_selections_state.as_ref() {
14848                let columnar_selection_ids: HashSet<_> = state
14849                    .groups
14850                    .iter()
14851                    .flat_map(|group| group.stack.iter())
14852                    .copied()
14853                    .collect();
14854
14855                all_selections
14856                    .into_iter()
14857                    .partition(|s| columnar_selection_ids.contains(&s.id))
14858            } else {
14859                (Vec::new(), all_selections)
14860            }
14861        };
14862
14863        let mut state = self
14864            .add_selections_state
14865            .take()
14866            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14867
14868        for selection in new_selections_to_columnarize {
14869            let range = selection.display_range(&display_map).sorted();
14870            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14871            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14872            let positions = start_x.min(end_x)..start_x.max(end_x);
14873            let mut stack = Vec::new();
14874            for row in range.start.row().0..=range.end.row().0 {
14875                if let Some(selection) = self.selections.build_columnar_selection(
14876                    &display_map,
14877                    DisplayRow(row),
14878                    &positions,
14879                    selection.reversed,
14880                    &text_layout_details,
14881                ) {
14882                    stack.push(selection.id);
14883                    columnar_selections.push(selection);
14884                }
14885            }
14886            if !stack.is_empty() {
14887                if above {
14888                    stack.reverse();
14889                }
14890                state.groups.push(AddSelectionsGroup { above, stack });
14891            }
14892        }
14893
14894        let mut final_selections = Vec::new();
14895        let end_row = if above {
14896            DisplayRow(0)
14897        } else {
14898            display_map.max_point().row()
14899        };
14900
14901        let mut last_added_item_per_group = HashMap::default();
14902        for group in state.groups.iter_mut() {
14903            if let Some(last_id) = group.stack.last() {
14904                last_added_item_per_group.insert(*last_id, group);
14905            }
14906        }
14907
14908        for selection in columnar_selections {
14909            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14910                if above == group.above {
14911                    let range = selection.display_range(&display_map).sorted();
14912                    debug_assert_eq!(range.start.row(), range.end.row());
14913                    let mut row = range.start.row();
14914                    let positions =
14915                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14916                            Pixels::from(start)..Pixels::from(end)
14917                        } else {
14918                            let start_x =
14919                                display_map.x_for_display_point(range.start, &text_layout_details);
14920                            let end_x =
14921                                display_map.x_for_display_point(range.end, &text_layout_details);
14922                            start_x.min(end_x)..start_x.max(end_x)
14923                        };
14924
14925                    let mut maybe_new_selection = None;
14926                    let direction = if above { -1 } else { 1 };
14927
14928                    while row != end_row {
14929                        if skip_soft_wrap {
14930                            row = display_map
14931                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14932                                .row();
14933                        } else if above {
14934                            row.0 -= 1;
14935                        } else {
14936                            row.0 += 1;
14937                        }
14938
14939                        if let Some(new_selection) = self.selections.build_columnar_selection(
14940                            &display_map,
14941                            row,
14942                            &positions,
14943                            selection.reversed,
14944                            &text_layout_details,
14945                        ) {
14946                            maybe_new_selection = Some(new_selection);
14947                            break;
14948                        }
14949                    }
14950
14951                    if let Some(new_selection) = maybe_new_selection {
14952                        group.stack.push(new_selection.id);
14953                        if above {
14954                            final_selections.push(new_selection);
14955                            final_selections.push(selection);
14956                        } else {
14957                            final_selections.push(selection);
14958                            final_selections.push(new_selection);
14959                        }
14960                    } else {
14961                        final_selections.push(selection);
14962                    }
14963                } else {
14964                    group.stack.pop();
14965                }
14966            } else {
14967                final_selections.push(selection);
14968            }
14969        }
14970
14971        self.change_selections(Default::default(), window, cx, |s| {
14972            s.select(final_selections);
14973        });
14974
14975        let final_selection_ids: HashSet<_> = self
14976            .selections
14977            .all::<Point>(&display_map)
14978            .iter()
14979            .map(|s| s.id)
14980            .collect();
14981        state.groups.retain_mut(|group| {
14982            // selections might get merged above so we remove invalid items from stacks
14983            group.stack.retain(|id| final_selection_ids.contains(id));
14984
14985            // single selection in stack can be treated as initial state
14986            group.stack.len() > 1
14987        });
14988
14989        if !state.groups.is_empty() {
14990            self.add_selections_state = Some(state);
14991        }
14992    }
14993
14994    pub fn insert_snippet_at_selections(
14995        &mut self,
14996        action: &InsertSnippet,
14997        window: &mut Window,
14998        cx: &mut Context<Self>,
14999    ) {
15000        self.try_insert_snippet_at_selections(action, window, cx)
15001            .log_err();
15002    }
15003
15004    fn try_insert_snippet_at_selections(
15005        &mut self,
15006        action: &InsertSnippet,
15007        window: &mut Window,
15008        cx: &mut Context<Self>,
15009    ) -> Result<()> {
15010        let insertion_ranges = self
15011            .selections
15012            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15013            .into_iter()
15014            .map(|selection| selection.range())
15015            .collect_vec();
15016
15017        let snippet = if let Some(snippet_body) = &action.snippet {
15018            if action.language.is_none() && action.name.is_none() {
15019                Snippet::parse(snippet_body)?
15020            } else {
15021                bail!("`snippet` is mutually exclusive with `language` and `name`")
15022            }
15023        } else if let Some(name) = &action.name {
15024            let project = self.project().context("no project")?;
15025            let snippet_store = project.read(cx).snippets().read(cx);
15026            let snippet = snippet_store
15027                .snippets_for(action.language.clone(), cx)
15028                .into_iter()
15029                .find(|snippet| snippet.name == *name)
15030                .context("snippet not found")?;
15031            Snippet::parse(&snippet.body)?
15032        } else {
15033            // todo(andrew): open modal to select snippet
15034            bail!("`name` or `snippet` is required")
15035        };
15036
15037        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15038    }
15039
15040    fn select_match_ranges(
15041        &mut self,
15042        range: Range<MultiBufferOffset>,
15043        reversed: bool,
15044        replace_newest: bool,
15045        auto_scroll: Option<Autoscroll>,
15046        window: &mut Window,
15047        cx: &mut Context<Editor>,
15048    ) {
15049        self.unfold_ranges(
15050            std::slice::from_ref(&range),
15051            false,
15052            auto_scroll.is_some(),
15053            cx,
15054        );
15055        let effects = if let Some(scroll) = auto_scroll {
15056            SelectionEffects::scroll(scroll)
15057        } else {
15058            SelectionEffects::no_scroll()
15059        };
15060        self.change_selections(effects, window, cx, |s| {
15061            if replace_newest {
15062                s.delete(s.newest_anchor().id);
15063            }
15064            if reversed {
15065                s.insert_range(range.end..range.start);
15066            } else {
15067                s.insert_range(range);
15068            }
15069        });
15070    }
15071
15072    pub fn select_next_match_internal(
15073        &mut self,
15074        display_map: &DisplaySnapshot,
15075        replace_newest: bool,
15076        autoscroll: Option<Autoscroll>,
15077        window: &mut Window,
15078        cx: &mut Context<Self>,
15079    ) -> Result<()> {
15080        let buffer = display_map.buffer_snapshot();
15081        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15082        if let Some(mut select_next_state) = self.select_next_state.take() {
15083            let query = &select_next_state.query;
15084            if !select_next_state.done {
15085                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15086                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15087                let mut next_selected_range = None;
15088
15089                let bytes_after_last_selection =
15090                    buffer.bytes_in_range(last_selection.end..buffer.len());
15091                let bytes_before_first_selection =
15092                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15093                let query_matches = query
15094                    .stream_find_iter(bytes_after_last_selection)
15095                    .map(|result| (last_selection.end, result))
15096                    .chain(
15097                        query
15098                            .stream_find_iter(bytes_before_first_selection)
15099                            .map(|result| (MultiBufferOffset(0), result)),
15100                    );
15101
15102                for (start_offset, query_match) in query_matches {
15103                    let query_match = query_match.unwrap(); // can only fail due to I/O
15104                    let offset_range =
15105                        start_offset + query_match.start()..start_offset + query_match.end();
15106
15107                    if !select_next_state.wordwise
15108                        || (!buffer.is_inside_word(offset_range.start, None)
15109                            && !buffer.is_inside_word(offset_range.end, None))
15110                    {
15111                        let idx = selections
15112                            .partition_point(|selection| selection.end <= offset_range.start);
15113                        let overlaps = selections
15114                            .get(idx)
15115                            .map_or(false, |selection| selection.start < offset_range.end);
15116
15117                        if !overlaps {
15118                            next_selected_range = Some(offset_range);
15119                            break;
15120                        }
15121                    }
15122                }
15123
15124                if let Some(next_selected_range) = next_selected_range {
15125                    self.select_match_ranges(
15126                        next_selected_range,
15127                        last_selection.reversed,
15128                        replace_newest,
15129                        autoscroll,
15130                        window,
15131                        cx,
15132                    );
15133                } else {
15134                    select_next_state.done = true;
15135                }
15136            }
15137
15138            self.select_next_state = Some(select_next_state);
15139        } else {
15140            let mut only_carets = true;
15141            let mut same_text_selected = true;
15142            let mut selected_text = None;
15143
15144            let mut selections_iter = selections.iter().peekable();
15145            while let Some(selection) = selections_iter.next() {
15146                if selection.start != selection.end {
15147                    only_carets = false;
15148                }
15149
15150                if same_text_selected {
15151                    if selected_text.is_none() {
15152                        selected_text =
15153                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15154                    }
15155
15156                    if let Some(next_selection) = selections_iter.peek() {
15157                        if next_selection.len() == selection.len() {
15158                            let next_selected_text = buffer
15159                                .text_for_range(next_selection.range())
15160                                .collect::<String>();
15161                            if Some(next_selected_text) != selected_text {
15162                                same_text_selected = false;
15163                                selected_text = None;
15164                            }
15165                        } else {
15166                            same_text_selected = false;
15167                            selected_text = None;
15168                        }
15169                    }
15170                }
15171            }
15172
15173            if only_carets {
15174                for selection in &mut selections {
15175                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15176                    selection.start = word_range.start;
15177                    selection.end = word_range.end;
15178                    selection.goal = SelectionGoal::None;
15179                    selection.reversed = false;
15180                    self.select_match_ranges(
15181                        selection.start..selection.end,
15182                        selection.reversed,
15183                        replace_newest,
15184                        autoscroll,
15185                        window,
15186                        cx,
15187                    );
15188                }
15189
15190                if selections.len() == 1 {
15191                    let selection = selections
15192                        .last()
15193                        .expect("ensured that there's only one selection");
15194                    let query = buffer
15195                        .text_for_range(selection.start..selection.end)
15196                        .collect::<String>();
15197                    let is_empty = query.is_empty();
15198                    let select_state = SelectNextState {
15199                        query: self.build_query(&[query], cx)?,
15200                        wordwise: true,
15201                        done: is_empty,
15202                    };
15203                    self.select_next_state = Some(select_state);
15204                } else {
15205                    self.select_next_state = None;
15206                }
15207            } else if let Some(selected_text) = selected_text {
15208                self.select_next_state = Some(SelectNextState {
15209                    query: self.build_query(&[selected_text], cx)?,
15210                    wordwise: false,
15211                    done: false,
15212                });
15213                self.select_next_match_internal(
15214                    display_map,
15215                    replace_newest,
15216                    autoscroll,
15217                    window,
15218                    cx,
15219                )?;
15220            }
15221        }
15222        Ok(())
15223    }
15224
15225    pub fn select_all_matches(
15226        &mut self,
15227        _action: &SelectAllMatches,
15228        window: &mut Window,
15229        cx: &mut Context<Self>,
15230    ) -> Result<()> {
15231        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15232
15233        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15234
15235        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15236        let Some(select_next_state) = self.select_next_state.as_mut() else {
15237            return Ok(());
15238        };
15239        if select_next_state.done {
15240            return Ok(());
15241        }
15242
15243        let mut new_selections = Vec::new();
15244
15245        let reversed = self
15246            .selections
15247            .oldest::<MultiBufferOffset>(&display_map)
15248            .reversed;
15249        let buffer = display_map.buffer_snapshot();
15250        let query_matches = select_next_state
15251            .query
15252            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15253
15254        for query_match in query_matches.into_iter() {
15255            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15256            let offset_range = if reversed {
15257                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15258            } else {
15259                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15260            };
15261
15262            if !select_next_state.wordwise
15263                || (!buffer.is_inside_word(offset_range.start, None)
15264                    && !buffer.is_inside_word(offset_range.end, None))
15265            {
15266                new_selections.push(offset_range.start..offset_range.end);
15267            }
15268        }
15269
15270        select_next_state.done = true;
15271
15272        if new_selections.is_empty() {
15273            log::error!("bug: new_selections is empty in select_all_matches");
15274            return Ok(());
15275        }
15276
15277        self.unfold_ranges(&new_selections.clone(), false, false, cx);
15278        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15279            selections.select_ranges(new_selections)
15280        });
15281
15282        Ok(())
15283    }
15284
15285    pub fn select_next(
15286        &mut self,
15287        action: &SelectNext,
15288        window: &mut Window,
15289        cx: &mut Context<Self>,
15290    ) -> Result<()> {
15291        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15292        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15293        self.select_next_match_internal(
15294            &display_map,
15295            action.replace_newest,
15296            Some(Autoscroll::newest()),
15297            window,
15298            cx,
15299        )?;
15300        Ok(())
15301    }
15302
15303    pub fn select_previous(
15304        &mut self,
15305        action: &SelectPrevious,
15306        window: &mut Window,
15307        cx: &mut Context<Self>,
15308    ) -> Result<()> {
15309        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15310        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15311        let buffer = display_map.buffer_snapshot();
15312        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15313        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15314            let query = &select_prev_state.query;
15315            if !select_prev_state.done {
15316                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15317                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15318                let mut next_selected_range = None;
15319                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15320                let bytes_before_last_selection =
15321                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15322                let bytes_after_first_selection =
15323                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15324                let query_matches = query
15325                    .stream_find_iter(bytes_before_last_selection)
15326                    .map(|result| (last_selection.start, result))
15327                    .chain(
15328                        query
15329                            .stream_find_iter(bytes_after_first_selection)
15330                            .map(|result| (buffer.len(), result)),
15331                    );
15332                for (end_offset, query_match) in query_matches {
15333                    let query_match = query_match.unwrap(); // can only fail due to I/O
15334                    let offset_range =
15335                        end_offset - query_match.end()..end_offset - query_match.start();
15336
15337                    if !select_prev_state.wordwise
15338                        || (!buffer.is_inside_word(offset_range.start, None)
15339                            && !buffer.is_inside_word(offset_range.end, None))
15340                    {
15341                        next_selected_range = Some(offset_range);
15342                        break;
15343                    }
15344                }
15345
15346                if let Some(next_selected_range) = next_selected_range {
15347                    self.select_match_ranges(
15348                        next_selected_range,
15349                        last_selection.reversed,
15350                        action.replace_newest,
15351                        Some(Autoscroll::newest()),
15352                        window,
15353                        cx,
15354                    );
15355                } else {
15356                    select_prev_state.done = true;
15357                }
15358            }
15359
15360            self.select_prev_state = Some(select_prev_state);
15361        } else {
15362            let mut only_carets = true;
15363            let mut same_text_selected = true;
15364            let mut selected_text = None;
15365
15366            let mut selections_iter = selections.iter().peekable();
15367            while let Some(selection) = selections_iter.next() {
15368                if selection.start != selection.end {
15369                    only_carets = false;
15370                }
15371
15372                if same_text_selected {
15373                    if selected_text.is_none() {
15374                        selected_text =
15375                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15376                    }
15377
15378                    if let Some(next_selection) = selections_iter.peek() {
15379                        if next_selection.len() == selection.len() {
15380                            let next_selected_text = buffer
15381                                .text_for_range(next_selection.range())
15382                                .collect::<String>();
15383                            if Some(next_selected_text) != selected_text {
15384                                same_text_selected = false;
15385                                selected_text = None;
15386                            }
15387                        } else {
15388                            same_text_selected = false;
15389                            selected_text = None;
15390                        }
15391                    }
15392                }
15393            }
15394
15395            if only_carets {
15396                for selection in &mut selections {
15397                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15398                    selection.start = word_range.start;
15399                    selection.end = word_range.end;
15400                    selection.goal = SelectionGoal::None;
15401                    selection.reversed = false;
15402                    self.select_match_ranges(
15403                        selection.start..selection.end,
15404                        selection.reversed,
15405                        action.replace_newest,
15406                        Some(Autoscroll::newest()),
15407                        window,
15408                        cx,
15409                    );
15410                }
15411                if selections.len() == 1 {
15412                    let selection = selections
15413                        .last()
15414                        .expect("ensured that there's only one selection");
15415                    let query = buffer
15416                        .text_for_range(selection.start..selection.end)
15417                        .collect::<String>();
15418                    let is_empty = query.is_empty();
15419                    let select_state = SelectNextState {
15420                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15421                        wordwise: true,
15422                        done: is_empty,
15423                    };
15424                    self.select_prev_state = Some(select_state);
15425                } else {
15426                    self.select_prev_state = None;
15427                }
15428            } else if let Some(selected_text) = selected_text {
15429                self.select_prev_state = Some(SelectNextState {
15430                    query: self
15431                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15432                    wordwise: false,
15433                    done: false,
15434                });
15435                self.select_previous(action, window, cx)?;
15436            }
15437        }
15438        Ok(())
15439    }
15440
15441    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15442    /// setting the case sensitivity based on the global
15443    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15444    /// editor's settings.
15445    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15446    where
15447        I: IntoIterator<Item = P>,
15448        P: AsRef<[u8]>,
15449    {
15450        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
15451            || EditorSettings::get_global(cx).search.case_sensitive,
15452            |value| value,
15453        );
15454
15455        let mut builder = AhoCorasickBuilder::new();
15456        builder.ascii_case_insensitive(!case_sensitive);
15457        builder.build(patterns)
15458    }
15459
15460    pub fn find_next_match(
15461        &mut self,
15462        _: &FindNextMatch,
15463        window: &mut Window,
15464        cx: &mut Context<Self>,
15465    ) -> Result<()> {
15466        let selections = self.selections.disjoint_anchors_arc();
15467        match selections.first() {
15468            Some(first) if selections.len() >= 2 => {
15469                self.change_selections(Default::default(), window, cx, |s| {
15470                    s.select_ranges([first.range()]);
15471                });
15472            }
15473            _ => self.select_next(
15474                &SelectNext {
15475                    replace_newest: true,
15476                },
15477                window,
15478                cx,
15479            )?,
15480        }
15481        Ok(())
15482    }
15483
15484    pub fn find_previous_match(
15485        &mut self,
15486        _: &FindPreviousMatch,
15487        window: &mut Window,
15488        cx: &mut Context<Self>,
15489    ) -> Result<()> {
15490        let selections = self.selections.disjoint_anchors_arc();
15491        match selections.last() {
15492            Some(last) if selections.len() >= 2 => {
15493                self.change_selections(Default::default(), window, cx, |s| {
15494                    s.select_ranges([last.range()]);
15495                });
15496            }
15497            _ => self.select_previous(
15498                &SelectPrevious {
15499                    replace_newest: true,
15500                },
15501                window,
15502                cx,
15503            )?,
15504        }
15505        Ok(())
15506    }
15507
15508    pub fn toggle_comments(
15509        &mut self,
15510        action: &ToggleComments,
15511        window: &mut Window,
15512        cx: &mut Context<Self>,
15513    ) {
15514        if self.read_only(cx) {
15515            return;
15516        }
15517        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15518        let text_layout_details = &self.text_layout_details(window);
15519        self.transact(window, cx, |this, window, cx| {
15520            let mut selections = this
15521                .selections
15522                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15523            let mut edits = Vec::new();
15524            let mut selection_edit_ranges = Vec::new();
15525            let mut last_toggled_row = None;
15526            let snapshot = this.buffer.read(cx).read(cx);
15527            let empty_str: Arc<str> = Arc::default();
15528            let mut suffixes_inserted = Vec::new();
15529            let ignore_indent = action.ignore_indent;
15530
15531            fn comment_prefix_range(
15532                snapshot: &MultiBufferSnapshot,
15533                row: MultiBufferRow,
15534                comment_prefix: &str,
15535                comment_prefix_whitespace: &str,
15536                ignore_indent: bool,
15537            ) -> Range<Point> {
15538                let indent_size = if ignore_indent {
15539                    0
15540                } else {
15541                    snapshot.indent_size_for_line(row).len
15542                };
15543
15544                let start = Point::new(row.0, indent_size);
15545
15546                let mut line_bytes = snapshot
15547                    .bytes_in_range(start..snapshot.max_point())
15548                    .flatten()
15549                    .copied();
15550
15551                // If this line currently begins with the line comment prefix, then record
15552                // the range containing the prefix.
15553                if line_bytes
15554                    .by_ref()
15555                    .take(comment_prefix.len())
15556                    .eq(comment_prefix.bytes())
15557                {
15558                    // Include any whitespace that matches the comment prefix.
15559                    let matching_whitespace_len = line_bytes
15560                        .zip(comment_prefix_whitespace.bytes())
15561                        .take_while(|(a, b)| a == b)
15562                        .count() as u32;
15563                    let end = Point::new(
15564                        start.row,
15565                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15566                    );
15567                    start..end
15568                } else {
15569                    start..start
15570                }
15571            }
15572
15573            fn comment_suffix_range(
15574                snapshot: &MultiBufferSnapshot,
15575                row: MultiBufferRow,
15576                comment_suffix: &str,
15577                comment_suffix_has_leading_space: bool,
15578            ) -> Range<Point> {
15579                let end = Point::new(row.0, snapshot.line_len(row));
15580                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15581
15582                let mut line_end_bytes = snapshot
15583                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15584                    .flatten()
15585                    .copied();
15586
15587                let leading_space_len = if suffix_start_column > 0
15588                    && line_end_bytes.next() == Some(b' ')
15589                    && comment_suffix_has_leading_space
15590                {
15591                    1
15592                } else {
15593                    0
15594                };
15595
15596                // If this line currently begins with the line comment prefix, then record
15597                // the range containing the prefix.
15598                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15599                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15600                    start..end
15601                } else {
15602                    end..end
15603                }
15604            }
15605
15606            // TODO: Handle selections that cross excerpts
15607            for selection in &mut selections {
15608                let start_column = snapshot
15609                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15610                    .len;
15611                let language = if let Some(language) =
15612                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15613                {
15614                    language
15615                } else {
15616                    continue;
15617                };
15618
15619                selection_edit_ranges.clear();
15620
15621                // If multiple selections contain a given row, avoid processing that
15622                // row more than once.
15623                let mut start_row = MultiBufferRow(selection.start.row);
15624                if last_toggled_row == Some(start_row) {
15625                    start_row = start_row.next_row();
15626                }
15627                let end_row =
15628                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15629                        MultiBufferRow(selection.end.row - 1)
15630                    } else {
15631                        MultiBufferRow(selection.end.row)
15632                    };
15633                last_toggled_row = Some(end_row);
15634
15635                if start_row > end_row {
15636                    continue;
15637                }
15638
15639                // If the language has line comments, toggle those.
15640                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15641
15642                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15643                if ignore_indent {
15644                    full_comment_prefixes = full_comment_prefixes
15645                        .into_iter()
15646                        .map(|s| Arc::from(s.trim_end()))
15647                        .collect();
15648                }
15649
15650                if !full_comment_prefixes.is_empty() {
15651                    let first_prefix = full_comment_prefixes
15652                        .first()
15653                        .expect("prefixes is non-empty");
15654                    let prefix_trimmed_lengths = full_comment_prefixes
15655                        .iter()
15656                        .map(|p| p.trim_end_matches(' ').len())
15657                        .collect::<SmallVec<[usize; 4]>>();
15658
15659                    let mut all_selection_lines_are_comments = true;
15660
15661                    for row in start_row.0..=end_row.0 {
15662                        let row = MultiBufferRow(row);
15663                        if start_row < end_row && snapshot.is_line_blank(row) {
15664                            continue;
15665                        }
15666
15667                        let prefix_range = full_comment_prefixes
15668                            .iter()
15669                            .zip(prefix_trimmed_lengths.iter().copied())
15670                            .map(|(prefix, trimmed_prefix_len)| {
15671                                comment_prefix_range(
15672                                    snapshot.deref(),
15673                                    row,
15674                                    &prefix[..trimmed_prefix_len],
15675                                    &prefix[trimmed_prefix_len..],
15676                                    ignore_indent,
15677                                )
15678                            })
15679                            .max_by_key(|range| range.end.column - range.start.column)
15680                            .expect("prefixes is non-empty");
15681
15682                        if prefix_range.is_empty() {
15683                            all_selection_lines_are_comments = false;
15684                        }
15685
15686                        selection_edit_ranges.push(prefix_range);
15687                    }
15688
15689                    if all_selection_lines_are_comments {
15690                        edits.extend(
15691                            selection_edit_ranges
15692                                .iter()
15693                                .cloned()
15694                                .map(|range| (range, empty_str.clone())),
15695                        );
15696                    } else {
15697                        let min_column = selection_edit_ranges
15698                            .iter()
15699                            .map(|range| range.start.column)
15700                            .min()
15701                            .unwrap_or(0);
15702                        edits.extend(selection_edit_ranges.iter().map(|range| {
15703                            let position = Point::new(range.start.row, min_column);
15704                            (position..position, first_prefix.clone())
15705                        }));
15706                    }
15707                } else if let Some(BlockCommentConfig {
15708                    start: full_comment_prefix,
15709                    end: comment_suffix,
15710                    ..
15711                }) = language.block_comment()
15712                {
15713                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15714                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15715                    let prefix_range = comment_prefix_range(
15716                        snapshot.deref(),
15717                        start_row,
15718                        comment_prefix,
15719                        comment_prefix_whitespace,
15720                        ignore_indent,
15721                    );
15722                    let suffix_range = comment_suffix_range(
15723                        snapshot.deref(),
15724                        end_row,
15725                        comment_suffix.trim_start_matches(' '),
15726                        comment_suffix.starts_with(' '),
15727                    );
15728
15729                    if prefix_range.is_empty() || suffix_range.is_empty() {
15730                        edits.push((
15731                            prefix_range.start..prefix_range.start,
15732                            full_comment_prefix.clone(),
15733                        ));
15734                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15735                        suffixes_inserted.push((end_row, comment_suffix.len()));
15736                    } else {
15737                        edits.push((prefix_range, empty_str.clone()));
15738                        edits.push((suffix_range, empty_str.clone()));
15739                    }
15740                } else {
15741                    continue;
15742                }
15743            }
15744
15745            drop(snapshot);
15746            this.buffer.update(cx, |buffer, cx| {
15747                buffer.edit(edits, None, cx);
15748            });
15749
15750            // Adjust selections so that they end before any comment suffixes that
15751            // were inserted.
15752            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15753            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15754            let snapshot = this.buffer.read(cx).read(cx);
15755            for selection in &mut selections {
15756                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15757                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15758                        Ordering::Less => {
15759                            suffixes_inserted.next();
15760                            continue;
15761                        }
15762                        Ordering::Greater => break,
15763                        Ordering::Equal => {
15764                            if selection.end.column == snapshot.line_len(row) {
15765                                if selection.is_empty() {
15766                                    selection.start.column -= suffix_len as u32;
15767                                }
15768                                selection.end.column -= suffix_len as u32;
15769                            }
15770                            break;
15771                        }
15772                    }
15773                }
15774            }
15775
15776            drop(snapshot);
15777            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15778
15779            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15780            let selections_on_single_row = selections.windows(2).all(|selections| {
15781                selections[0].start.row == selections[1].start.row
15782                    && selections[0].end.row == selections[1].end.row
15783                    && selections[0].start.row == selections[0].end.row
15784            });
15785            let selections_selecting = selections
15786                .iter()
15787                .any(|selection| selection.start != selection.end);
15788            let advance_downwards = action.advance_downwards
15789                && selections_on_single_row
15790                && !selections_selecting
15791                && !matches!(this.mode, EditorMode::SingleLine);
15792
15793            if advance_downwards {
15794                let snapshot = this.buffer.read(cx).snapshot(cx);
15795
15796                this.change_selections(Default::default(), window, cx, |s| {
15797                    s.move_cursors_with(|display_snapshot, display_point, _| {
15798                        let mut point = display_point.to_point(display_snapshot);
15799                        point.row += 1;
15800                        point = snapshot.clip_point(point, Bias::Left);
15801                        let display_point = point.to_display_point(display_snapshot);
15802                        let goal = SelectionGoal::HorizontalPosition(
15803                            display_snapshot
15804                                .x_for_display_point(display_point, text_layout_details)
15805                                .into(),
15806                        );
15807                        (display_point, goal)
15808                    })
15809                });
15810            }
15811        });
15812    }
15813
15814    pub fn select_enclosing_symbol(
15815        &mut self,
15816        _: &SelectEnclosingSymbol,
15817        window: &mut Window,
15818        cx: &mut Context<Self>,
15819    ) {
15820        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15821
15822        let buffer = self.buffer.read(cx).snapshot(cx);
15823        let old_selections = self
15824            .selections
15825            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15826            .into_boxed_slice();
15827
15828        fn update_selection(
15829            selection: &Selection<MultiBufferOffset>,
15830            buffer_snap: &MultiBufferSnapshot,
15831        ) -> Option<Selection<MultiBufferOffset>> {
15832            let cursor = selection.head();
15833            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15834            for symbol in symbols.iter().rev() {
15835                let start = symbol.range.start.to_offset(buffer_snap);
15836                let end = symbol.range.end.to_offset(buffer_snap);
15837                let new_range = start..end;
15838                if start < selection.start || end > selection.end {
15839                    return Some(Selection {
15840                        id: selection.id,
15841                        start: new_range.start,
15842                        end: new_range.end,
15843                        goal: SelectionGoal::None,
15844                        reversed: selection.reversed,
15845                    });
15846                }
15847            }
15848            None
15849        }
15850
15851        let mut selected_larger_symbol = false;
15852        let new_selections = old_selections
15853            .iter()
15854            .map(|selection| match update_selection(selection, &buffer) {
15855                Some(new_selection) => {
15856                    if new_selection.range() != selection.range() {
15857                        selected_larger_symbol = true;
15858                    }
15859                    new_selection
15860                }
15861                None => selection.clone(),
15862            })
15863            .collect::<Vec<_>>();
15864
15865        if selected_larger_symbol {
15866            self.change_selections(Default::default(), window, cx, |s| {
15867                s.select(new_selections);
15868            });
15869        }
15870    }
15871
15872    pub fn select_larger_syntax_node(
15873        &mut self,
15874        _: &SelectLargerSyntaxNode,
15875        window: &mut Window,
15876        cx: &mut Context<Self>,
15877    ) {
15878        let Some(visible_row_count) = self.visible_row_count() else {
15879            return;
15880        };
15881        let old_selections: Box<[_]> = self
15882            .selections
15883            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15884            .into();
15885        if old_selections.is_empty() {
15886            return;
15887        }
15888
15889        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15890
15891        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15892        let buffer = self.buffer.read(cx).snapshot(cx);
15893
15894        let mut selected_larger_node = false;
15895        let mut new_selections = old_selections
15896            .iter()
15897            .map(|selection| {
15898                let old_range = selection.start..selection.end;
15899
15900                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15901                    // manually select word at selection
15902                    if ["string_content", "inline"].contains(&node.kind()) {
15903                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15904                        // ignore if word is already selected
15905                        if !word_range.is_empty() && old_range != word_range {
15906                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15907                            // only select word if start and end point belongs to same word
15908                            if word_range == last_word_range {
15909                                selected_larger_node = true;
15910                                return Selection {
15911                                    id: selection.id,
15912                                    start: word_range.start,
15913                                    end: word_range.end,
15914                                    goal: SelectionGoal::None,
15915                                    reversed: selection.reversed,
15916                                };
15917                            }
15918                        }
15919                    }
15920                }
15921
15922                let mut new_range = old_range.clone();
15923                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15924                    new_range = range;
15925                    if !node.is_named() {
15926                        continue;
15927                    }
15928                    if !display_map.intersects_fold(new_range.start)
15929                        && !display_map.intersects_fold(new_range.end)
15930                    {
15931                        break;
15932                    }
15933                }
15934
15935                selected_larger_node |= new_range != old_range;
15936                Selection {
15937                    id: selection.id,
15938                    start: new_range.start,
15939                    end: new_range.end,
15940                    goal: SelectionGoal::None,
15941                    reversed: selection.reversed,
15942                }
15943            })
15944            .collect::<Vec<_>>();
15945
15946        if !selected_larger_node {
15947            return; // don't put this call in the history
15948        }
15949
15950        // scroll based on transformation done to the last selection created by the user
15951        let (last_old, last_new) = old_selections
15952            .last()
15953            .zip(new_selections.last().cloned())
15954            .expect("old_selections isn't empty");
15955
15956        // revert selection
15957        let is_selection_reversed = {
15958            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15959            new_selections.last_mut().expect("checked above").reversed =
15960                should_newest_selection_be_reversed;
15961            should_newest_selection_be_reversed
15962        };
15963
15964        if selected_larger_node {
15965            self.select_syntax_node_history.disable_clearing = true;
15966            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15967                s.select(new_selections.clone());
15968            });
15969            self.select_syntax_node_history.disable_clearing = false;
15970        }
15971
15972        let start_row = last_new.start.to_display_point(&display_map).row().0;
15973        let end_row = last_new.end.to_display_point(&display_map).row().0;
15974        let selection_height = end_row - start_row + 1;
15975        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15976
15977        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15978        let scroll_behavior = if fits_on_the_screen {
15979            self.request_autoscroll(Autoscroll::fit(), cx);
15980            SelectSyntaxNodeScrollBehavior::FitSelection
15981        } else if is_selection_reversed {
15982            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15983            SelectSyntaxNodeScrollBehavior::CursorTop
15984        } else {
15985            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15986            SelectSyntaxNodeScrollBehavior::CursorBottom
15987        };
15988
15989        self.select_syntax_node_history.push((
15990            old_selections,
15991            scroll_behavior,
15992            is_selection_reversed,
15993        ));
15994    }
15995
15996    pub fn select_smaller_syntax_node(
15997        &mut self,
15998        _: &SelectSmallerSyntaxNode,
15999        window: &mut Window,
16000        cx: &mut Context<Self>,
16001    ) {
16002        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16003
16004        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16005            self.select_syntax_node_history.pop()
16006        {
16007            if let Some(selection) = selections.last_mut() {
16008                selection.reversed = is_selection_reversed;
16009            }
16010
16011            self.select_syntax_node_history.disable_clearing = true;
16012            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16013                s.select(selections.to_vec());
16014            });
16015            self.select_syntax_node_history.disable_clearing = false;
16016
16017            match scroll_behavior {
16018                SelectSyntaxNodeScrollBehavior::CursorTop => {
16019                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16020                }
16021                SelectSyntaxNodeScrollBehavior::FitSelection => {
16022                    self.request_autoscroll(Autoscroll::fit(), cx);
16023                }
16024                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16025                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16026                }
16027            }
16028        }
16029    }
16030
16031    pub fn unwrap_syntax_node(
16032        &mut self,
16033        _: &UnwrapSyntaxNode,
16034        window: &mut Window,
16035        cx: &mut Context<Self>,
16036    ) {
16037        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16038
16039        let buffer = self.buffer.read(cx).snapshot(cx);
16040        let selections = self
16041            .selections
16042            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16043            .into_iter()
16044            // subtracting the offset requires sorting
16045            .sorted_by_key(|i| i.start);
16046
16047        let full_edits = selections
16048            .into_iter()
16049            .filter_map(|selection| {
16050                let child = if selection.is_empty()
16051                    && let Some((_, ancestor_range)) =
16052                        buffer.syntax_ancestor(selection.start..selection.end)
16053                {
16054                    ancestor_range
16055                } else {
16056                    selection.range()
16057                };
16058
16059                let mut parent = child.clone();
16060                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16061                    parent = ancestor_range;
16062                    if parent.start < child.start || parent.end > child.end {
16063                        break;
16064                    }
16065                }
16066
16067                if parent == child {
16068                    return None;
16069                }
16070                let text = buffer.text_for_range(child).collect::<String>();
16071                Some((selection.id, parent, text))
16072            })
16073            .collect::<Vec<_>>();
16074        if full_edits.is_empty() {
16075            return;
16076        }
16077
16078        self.transact(window, cx, |this, window, cx| {
16079            this.buffer.update(cx, |buffer, cx| {
16080                buffer.edit(
16081                    full_edits
16082                        .iter()
16083                        .map(|(_, p, t)| (p.clone(), t.clone()))
16084                        .collect::<Vec<_>>(),
16085                    None,
16086                    cx,
16087                );
16088            });
16089            this.change_selections(Default::default(), window, cx, |s| {
16090                let mut offset = 0;
16091                let mut selections = vec![];
16092                for (id, parent, text) in full_edits {
16093                    let start = parent.start - offset;
16094                    offset += (parent.end - parent.start) - text.len();
16095                    selections.push(Selection {
16096                        id,
16097                        start,
16098                        end: start + text.len(),
16099                        reversed: false,
16100                        goal: Default::default(),
16101                    });
16102                }
16103                s.select(selections);
16104            });
16105        });
16106    }
16107
16108    pub fn select_next_syntax_node(
16109        &mut self,
16110        _: &SelectNextSyntaxNode,
16111        window: &mut Window,
16112        cx: &mut Context<Self>,
16113    ) {
16114        let old_selections: Box<[_]> = self
16115            .selections
16116            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16117            .into();
16118        if old_selections.is_empty() {
16119            return;
16120        }
16121
16122        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16123
16124        let buffer = self.buffer.read(cx).snapshot(cx);
16125        let mut selected_sibling = false;
16126
16127        let new_selections = old_selections
16128            .iter()
16129            .map(|selection| {
16130                let old_range = selection.start..selection.end;
16131
16132                let old_range =
16133                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16134                let excerpt = buffer.excerpt_containing(old_range.clone());
16135
16136                if let Some(mut excerpt) = excerpt
16137                    && let Some(node) = excerpt
16138                        .buffer()
16139                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16140                {
16141                    let new_range = excerpt.map_range_from_buffer(
16142                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16143                    );
16144                    selected_sibling = true;
16145                    Selection {
16146                        id: selection.id,
16147                        start: new_range.start,
16148                        end: new_range.end,
16149                        goal: SelectionGoal::None,
16150                        reversed: selection.reversed,
16151                    }
16152                } else {
16153                    selection.clone()
16154                }
16155            })
16156            .collect::<Vec<_>>();
16157
16158        if selected_sibling {
16159            self.change_selections(
16160                SelectionEffects::scroll(Autoscroll::fit()),
16161                window,
16162                cx,
16163                |s| {
16164                    s.select(new_selections);
16165                },
16166            );
16167        }
16168    }
16169
16170    pub fn select_prev_syntax_node(
16171        &mut self,
16172        _: &SelectPreviousSyntaxNode,
16173        window: &mut Window,
16174        cx: &mut Context<Self>,
16175    ) {
16176        let old_selections: Box<[_]> = self
16177            .selections
16178            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16179            .into();
16180        if old_selections.is_empty() {
16181            return;
16182        }
16183
16184        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16185
16186        let buffer = self.buffer.read(cx).snapshot(cx);
16187        let mut selected_sibling = false;
16188
16189        let new_selections = old_selections
16190            .iter()
16191            .map(|selection| {
16192                let old_range = selection.start..selection.end;
16193                let old_range =
16194                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16195                let excerpt = buffer.excerpt_containing(old_range.clone());
16196
16197                if let Some(mut excerpt) = excerpt
16198                    && let Some(node) = excerpt
16199                        .buffer()
16200                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16201                {
16202                    let new_range = excerpt.map_range_from_buffer(
16203                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16204                    );
16205                    selected_sibling = true;
16206                    Selection {
16207                        id: selection.id,
16208                        start: new_range.start,
16209                        end: new_range.end,
16210                        goal: SelectionGoal::None,
16211                        reversed: selection.reversed,
16212                    }
16213                } else {
16214                    selection.clone()
16215                }
16216            })
16217            .collect::<Vec<_>>();
16218
16219        if selected_sibling {
16220            self.change_selections(
16221                SelectionEffects::scroll(Autoscroll::fit()),
16222                window,
16223                cx,
16224                |s| {
16225                    s.select(new_selections);
16226                },
16227            );
16228        }
16229    }
16230
16231    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16232        if !EditorSettings::get_global(cx).gutter.runnables {
16233            self.clear_tasks();
16234            return Task::ready(());
16235        }
16236        let project = self.project().map(Entity::downgrade);
16237        let task_sources = self.lsp_task_sources(cx);
16238        let multi_buffer = self.buffer.downgrade();
16239        cx.spawn_in(window, async move |editor, cx| {
16240            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16241            let Some(project) = project.and_then(|p| p.upgrade()) else {
16242                return;
16243            };
16244            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16245                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16246            }) else {
16247                return;
16248            };
16249
16250            let hide_runnables = project
16251                .update(cx, |project, _| project.is_via_collab())
16252                .unwrap_or(true);
16253            if hide_runnables {
16254                return;
16255            }
16256            let new_rows =
16257                cx.background_spawn({
16258                    let snapshot = display_snapshot.clone();
16259                    async move {
16260                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16261                    }
16262                })
16263                    .await;
16264            let Ok(lsp_tasks) =
16265                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16266            else {
16267                return;
16268            };
16269            let lsp_tasks = lsp_tasks.await;
16270
16271            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16272                lsp_tasks
16273                    .into_iter()
16274                    .flat_map(|(kind, tasks)| {
16275                        tasks.into_iter().filter_map(move |(location, task)| {
16276                            Some((kind.clone(), location?, task))
16277                        })
16278                    })
16279                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16280                        let buffer = location.target.buffer;
16281                        let buffer_snapshot = buffer.read(cx).snapshot();
16282                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16283                            |(excerpt_id, snapshot, _)| {
16284                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16285                                    display_snapshot
16286                                        .buffer_snapshot()
16287                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16288                                } else {
16289                                    None
16290                                }
16291                            },
16292                        );
16293                        if let Some(offset) = offset {
16294                            let task_buffer_range =
16295                                location.target.range.to_point(&buffer_snapshot);
16296                            let context_buffer_range =
16297                                task_buffer_range.to_offset(&buffer_snapshot);
16298                            let context_range = BufferOffset(context_buffer_range.start)
16299                                ..BufferOffset(context_buffer_range.end);
16300
16301                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16302                                .or_insert_with(|| RunnableTasks {
16303                                    templates: Vec::new(),
16304                                    offset,
16305                                    column: task_buffer_range.start.column,
16306                                    extra_variables: HashMap::default(),
16307                                    context_range,
16308                                })
16309                                .templates
16310                                .push((kind, task.original_task().clone()));
16311                        }
16312
16313                        acc
16314                    })
16315            }) else {
16316                return;
16317            };
16318
16319            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16320                buffer.language_settings(cx).tasks.prefer_lsp
16321            }) else {
16322                return;
16323            };
16324
16325            let rows = Self::runnable_rows(
16326                project,
16327                display_snapshot,
16328                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16329                new_rows,
16330                cx.clone(),
16331            )
16332            .await;
16333            editor
16334                .update(cx, |editor, _| {
16335                    editor.clear_tasks();
16336                    for (key, mut value) in rows {
16337                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16338                            value.templates.extend(lsp_tasks.templates);
16339                        }
16340
16341                        editor.insert_tasks(key, value);
16342                    }
16343                    for (key, value) in lsp_tasks_by_rows {
16344                        editor.insert_tasks(key, value);
16345                    }
16346                })
16347                .ok();
16348        })
16349    }
16350    fn fetch_runnable_ranges(
16351        snapshot: &DisplaySnapshot,
16352        range: Range<Anchor>,
16353    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16354        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16355    }
16356
16357    fn runnable_rows(
16358        project: Entity<Project>,
16359        snapshot: DisplaySnapshot,
16360        prefer_lsp: bool,
16361        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16362        cx: AsyncWindowContext,
16363    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16364        cx.spawn(async move |cx| {
16365            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16366            for (run_range, mut runnable) in runnable_ranges {
16367                let Some(tasks) = cx
16368                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16369                    .ok()
16370                else {
16371                    continue;
16372                };
16373                let mut tasks = tasks.await;
16374
16375                if prefer_lsp {
16376                    tasks.retain(|(task_kind, _)| {
16377                        !matches!(task_kind, TaskSourceKind::Language { .. })
16378                    });
16379                }
16380                if tasks.is_empty() {
16381                    continue;
16382                }
16383
16384                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16385                let Some(row) = snapshot
16386                    .buffer_snapshot()
16387                    .buffer_line_for_row(MultiBufferRow(point.row))
16388                    .map(|(_, range)| range.start.row)
16389                else {
16390                    continue;
16391                };
16392
16393                let context_range =
16394                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16395                runnable_rows.push((
16396                    (runnable.buffer_id, row),
16397                    RunnableTasks {
16398                        templates: tasks,
16399                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16400                        context_range,
16401                        column: point.column,
16402                        extra_variables: runnable.extra_captures,
16403                    },
16404                ));
16405            }
16406            runnable_rows
16407        })
16408    }
16409
16410    fn templates_with_tags(
16411        project: &Entity<Project>,
16412        runnable: &mut Runnable,
16413        cx: &mut App,
16414    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16415        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16416            let (worktree_id, file) = project
16417                .buffer_for_id(runnable.buffer, cx)
16418                .and_then(|buffer| buffer.read(cx).file())
16419                .map(|file| (file.worktree_id(cx), file.clone()))
16420                .unzip();
16421
16422            (
16423                project.task_store().read(cx).task_inventory().cloned(),
16424                worktree_id,
16425                file,
16426            )
16427        });
16428
16429        let tags = mem::take(&mut runnable.tags);
16430        let language = runnable.language.clone();
16431        cx.spawn(async move |cx| {
16432            let mut templates_with_tags = Vec::new();
16433            if let Some(inventory) = inventory {
16434                for RunnableTag(tag) in tags {
16435                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16436                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16437                    }) else {
16438                        return templates_with_tags;
16439                    };
16440                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16441                        move |(_, template)| {
16442                            template.tags.iter().any(|source_tag| source_tag == &tag)
16443                        },
16444                    ));
16445                }
16446            }
16447            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16448
16449            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16450                // Strongest source wins; if we have worktree tag binding, prefer that to
16451                // global and language bindings;
16452                // if we have a global binding, prefer that to language binding.
16453                let first_mismatch = templates_with_tags
16454                    .iter()
16455                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16456                if let Some(index) = first_mismatch {
16457                    templates_with_tags.truncate(index);
16458                }
16459            }
16460
16461            templates_with_tags
16462        })
16463    }
16464
16465    pub fn move_to_enclosing_bracket(
16466        &mut self,
16467        _: &MoveToEnclosingBracket,
16468        window: &mut Window,
16469        cx: &mut Context<Self>,
16470    ) {
16471        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16472        self.change_selections(Default::default(), window, cx, |s| {
16473            s.move_offsets_with(|snapshot, selection| {
16474                let Some(enclosing_bracket_ranges) =
16475                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16476                else {
16477                    return;
16478                };
16479
16480                let mut best_length = usize::MAX;
16481                let mut best_inside = false;
16482                let mut best_in_bracket_range = false;
16483                let mut best_destination = None;
16484                for (open, close) in enclosing_bracket_ranges {
16485                    let close = close.to_inclusive();
16486                    let length = *close.end() - open.start;
16487                    let inside = selection.start >= open.end && selection.end <= *close.start();
16488                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16489                        || close.contains(&selection.head());
16490
16491                    // If best is next to a bracket and current isn't, skip
16492                    if !in_bracket_range && best_in_bracket_range {
16493                        continue;
16494                    }
16495
16496                    // Prefer smaller lengths unless best is inside and current isn't
16497                    if length > best_length && (best_inside || !inside) {
16498                        continue;
16499                    }
16500
16501                    best_length = length;
16502                    best_inside = inside;
16503                    best_in_bracket_range = in_bracket_range;
16504                    best_destination = Some(
16505                        if close.contains(&selection.start) && close.contains(&selection.end) {
16506                            if inside { open.end } else { open.start }
16507                        } else if inside {
16508                            *close.start()
16509                        } else {
16510                            *close.end()
16511                        },
16512                    );
16513                }
16514
16515                if let Some(destination) = best_destination {
16516                    selection.collapse_to(destination, SelectionGoal::None);
16517                }
16518            })
16519        });
16520    }
16521
16522    pub fn undo_selection(
16523        &mut self,
16524        _: &UndoSelection,
16525        window: &mut Window,
16526        cx: &mut Context<Self>,
16527    ) {
16528        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16529        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16530            self.selection_history.mode = SelectionHistoryMode::Undoing;
16531            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16532                this.end_selection(window, cx);
16533                this.change_selections(
16534                    SelectionEffects::scroll(Autoscroll::newest()),
16535                    window,
16536                    cx,
16537                    |s| s.select_anchors(entry.selections.to_vec()),
16538                );
16539            });
16540            self.selection_history.mode = SelectionHistoryMode::Normal;
16541
16542            self.select_next_state = entry.select_next_state;
16543            self.select_prev_state = entry.select_prev_state;
16544            self.add_selections_state = entry.add_selections_state;
16545        }
16546    }
16547
16548    pub fn redo_selection(
16549        &mut self,
16550        _: &RedoSelection,
16551        window: &mut Window,
16552        cx: &mut Context<Self>,
16553    ) {
16554        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16555        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16556            self.selection_history.mode = SelectionHistoryMode::Redoing;
16557            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16558                this.end_selection(window, cx);
16559                this.change_selections(
16560                    SelectionEffects::scroll(Autoscroll::newest()),
16561                    window,
16562                    cx,
16563                    |s| s.select_anchors(entry.selections.to_vec()),
16564                );
16565            });
16566            self.selection_history.mode = SelectionHistoryMode::Normal;
16567
16568            self.select_next_state = entry.select_next_state;
16569            self.select_prev_state = entry.select_prev_state;
16570            self.add_selections_state = entry.add_selections_state;
16571        }
16572    }
16573
16574    pub fn expand_excerpts(
16575        &mut self,
16576        action: &ExpandExcerpts,
16577        _: &mut Window,
16578        cx: &mut Context<Self>,
16579    ) {
16580        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16581    }
16582
16583    pub fn expand_excerpts_down(
16584        &mut self,
16585        action: &ExpandExcerptsDown,
16586        _: &mut Window,
16587        cx: &mut Context<Self>,
16588    ) {
16589        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16590    }
16591
16592    pub fn expand_excerpts_up(
16593        &mut self,
16594        action: &ExpandExcerptsUp,
16595        _: &mut Window,
16596        cx: &mut Context<Self>,
16597    ) {
16598        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16599    }
16600
16601    pub fn expand_excerpts_for_direction(
16602        &mut self,
16603        lines: u32,
16604        direction: ExpandExcerptDirection,
16605
16606        cx: &mut Context<Self>,
16607    ) {
16608        let selections = self.selections.disjoint_anchors_arc();
16609
16610        let lines = if lines == 0 {
16611            EditorSettings::get_global(cx).expand_excerpt_lines
16612        } else {
16613            lines
16614        };
16615
16616        self.buffer.update(cx, |buffer, cx| {
16617            let snapshot = buffer.snapshot(cx);
16618            let mut excerpt_ids = selections
16619                .iter()
16620                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16621                .collect::<Vec<_>>();
16622            excerpt_ids.sort();
16623            excerpt_ids.dedup();
16624            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16625        })
16626    }
16627
16628    pub fn expand_excerpt(
16629        &mut self,
16630        excerpt: ExcerptId,
16631        direction: ExpandExcerptDirection,
16632        window: &mut Window,
16633        cx: &mut Context<Self>,
16634    ) {
16635        let current_scroll_position = self.scroll_position(cx);
16636        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16637        let mut scroll = None;
16638
16639        if direction == ExpandExcerptDirection::Down {
16640            let multi_buffer = self.buffer.read(cx);
16641            let snapshot = multi_buffer.snapshot(cx);
16642            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16643                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16644                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16645            {
16646                let buffer_snapshot = buffer.read(cx).snapshot();
16647                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16648                let last_row = buffer_snapshot.max_point().row;
16649                let lines_below = last_row.saturating_sub(excerpt_end_row);
16650                if lines_below >= lines_to_expand {
16651                    scroll = Some(
16652                        current_scroll_position
16653                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16654                    );
16655                }
16656            }
16657        }
16658        if direction == ExpandExcerptDirection::Up
16659            && self
16660                .buffer
16661                .read(cx)
16662                .snapshot(cx)
16663                .excerpt_before(excerpt)
16664                .is_none()
16665        {
16666            scroll = Some(current_scroll_position);
16667        }
16668
16669        self.buffer.update(cx, |buffer, cx| {
16670            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16671        });
16672
16673        if let Some(new_scroll_position) = scroll {
16674            self.set_scroll_position(new_scroll_position, window, cx);
16675        }
16676    }
16677
16678    pub fn go_to_singleton_buffer_point(
16679        &mut self,
16680        point: Point,
16681        window: &mut Window,
16682        cx: &mut Context<Self>,
16683    ) {
16684        self.go_to_singleton_buffer_range(point..point, window, cx);
16685    }
16686
16687    pub fn go_to_singleton_buffer_range(
16688        &mut self,
16689        range: Range<Point>,
16690        window: &mut Window,
16691        cx: &mut Context<Self>,
16692    ) {
16693        let multibuffer = self.buffer().read(cx);
16694        let Some(buffer) = multibuffer.as_singleton() else {
16695            return;
16696        };
16697        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16698            return;
16699        };
16700        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16701            return;
16702        };
16703        self.change_selections(
16704            SelectionEffects::default().nav_history(true),
16705            window,
16706            cx,
16707            |s| s.select_anchor_ranges([start..end]),
16708        );
16709    }
16710
16711    pub fn go_to_diagnostic(
16712        &mut self,
16713        action: &GoToDiagnostic,
16714        window: &mut Window,
16715        cx: &mut Context<Self>,
16716    ) {
16717        if !self.diagnostics_enabled() {
16718            return;
16719        }
16720        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16721        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16722    }
16723
16724    pub fn go_to_prev_diagnostic(
16725        &mut self,
16726        action: &GoToPreviousDiagnostic,
16727        window: &mut Window,
16728        cx: &mut Context<Self>,
16729    ) {
16730        if !self.diagnostics_enabled() {
16731            return;
16732        }
16733        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16734        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16735    }
16736
16737    pub fn go_to_diagnostic_impl(
16738        &mut self,
16739        direction: Direction,
16740        severity: GoToDiagnosticSeverityFilter,
16741        window: &mut Window,
16742        cx: &mut Context<Self>,
16743    ) {
16744        let buffer = self.buffer.read(cx).snapshot(cx);
16745        let selection = self
16746            .selections
16747            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16748
16749        let mut active_group_id = None;
16750        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16751            && active_group.active_range.start.to_offset(&buffer) == selection.start
16752        {
16753            active_group_id = Some(active_group.group_id);
16754        }
16755
16756        fn filtered<'a>(
16757            severity: GoToDiagnosticSeverityFilter,
16758            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16759        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16760            diagnostics
16761                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16762                .filter(|entry| entry.range.start != entry.range.end)
16763                .filter(|entry| !entry.diagnostic.is_unnecessary)
16764        }
16765
16766        let before = filtered(
16767            severity,
16768            buffer
16769                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16770                .filter(|entry| entry.range.start <= selection.start),
16771        );
16772        let after = filtered(
16773            severity,
16774            buffer
16775                .diagnostics_in_range(selection.start..buffer.len())
16776                .filter(|entry| entry.range.start >= selection.start),
16777        );
16778
16779        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16780        if direction == Direction::Prev {
16781            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16782            {
16783                for diagnostic in prev_diagnostics.into_iter().rev() {
16784                    if diagnostic.range.start != selection.start
16785                        || active_group_id
16786                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16787                    {
16788                        found = Some(diagnostic);
16789                        break 'outer;
16790                    }
16791                }
16792            }
16793        } else {
16794            for diagnostic in after.chain(before) {
16795                if diagnostic.range.start != selection.start
16796                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16797                {
16798                    found = Some(diagnostic);
16799                    break;
16800                }
16801            }
16802        }
16803        let Some(next_diagnostic) = found else {
16804            return;
16805        };
16806
16807        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16808        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16809            return;
16810        };
16811        let snapshot = self.snapshot(window, cx);
16812        if snapshot.intersects_fold(next_diagnostic.range.start) {
16813            self.unfold_ranges(
16814                std::slice::from_ref(&next_diagnostic.range),
16815                true,
16816                false,
16817                cx,
16818            );
16819        }
16820        self.change_selections(Default::default(), window, cx, |s| {
16821            s.select_ranges(vec![
16822                next_diagnostic.range.start..next_diagnostic.range.start,
16823            ])
16824        });
16825        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16826        self.refresh_edit_prediction(false, true, window, cx);
16827    }
16828
16829    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16830        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16831        let snapshot = self.snapshot(window, cx);
16832        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16833        self.go_to_hunk_before_or_after_position(
16834            &snapshot,
16835            selection.head(),
16836            Direction::Next,
16837            window,
16838            cx,
16839        );
16840    }
16841
16842    pub fn go_to_hunk_before_or_after_position(
16843        &mut self,
16844        snapshot: &EditorSnapshot,
16845        position: Point,
16846        direction: Direction,
16847        window: &mut Window,
16848        cx: &mut Context<Editor>,
16849    ) {
16850        let row = if direction == Direction::Next {
16851            self.hunk_after_position(snapshot, position)
16852                .map(|hunk| hunk.row_range.start)
16853        } else {
16854            self.hunk_before_position(snapshot, position)
16855        };
16856
16857        if let Some(row) = row {
16858            let destination = Point::new(row.0, 0);
16859            let autoscroll = Autoscroll::center();
16860
16861            self.unfold_ranges(&[destination..destination], false, false, cx);
16862            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16863                s.select_ranges([destination..destination]);
16864            });
16865        }
16866    }
16867
16868    fn hunk_after_position(
16869        &mut self,
16870        snapshot: &EditorSnapshot,
16871        position: Point,
16872    ) -> Option<MultiBufferDiffHunk> {
16873        snapshot
16874            .buffer_snapshot()
16875            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16876            .find(|hunk| hunk.row_range.start.0 > position.row)
16877            .or_else(|| {
16878                snapshot
16879                    .buffer_snapshot()
16880                    .diff_hunks_in_range(Point::zero()..position)
16881                    .find(|hunk| hunk.row_range.end.0 < position.row)
16882            })
16883    }
16884
16885    fn go_to_prev_hunk(
16886        &mut self,
16887        _: &GoToPreviousHunk,
16888        window: &mut Window,
16889        cx: &mut Context<Self>,
16890    ) {
16891        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16892        let snapshot = self.snapshot(window, cx);
16893        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16894        self.go_to_hunk_before_or_after_position(
16895            &snapshot,
16896            selection.head(),
16897            Direction::Prev,
16898            window,
16899            cx,
16900        );
16901    }
16902
16903    fn hunk_before_position(
16904        &mut self,
16905        snapshot: &EditorSnapshot,
16906        position: Point,
16907    ) -> Option<MultiBufferRow> {
16908        snapshot
16909            .buffer_snapshot()
16910            .diff_hunk_before(position)
16911            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16912    }
16913
16914    fn go_to_next_change(
16915        &mut self,
16916        _: &GoToNextChange,
16917        window: &mut Window,
16918        cx: &mut Context<Self>,
16919    ) {
16920        if let Some(selections) = self
16921            .change_list
16922            .next_change(1, Direction::Next)
16923            .map(|s| s.to_vec())
16924        {
16925            self.change_selections(Default::default(), window, cx, |s| {
16926                let map = s.display_snapshot();
16927                s.select_display_ranges(selections.iter().map(|a| {
16928                    let point = a.to_display_point(&map);
16929                    point..point
16930                }))
16931            })
16932        }
16933    }
16934
16935    fn go_to_previous_change(
16936        &mut self,
16937        _: &GoToPreviousChange,
16938        window: &mut Window,
16939        cx: &mut Context<Self>,
16940    ) {
16941        if let Some(selections) = self
16942            .change_list
16943            .next_change(1, Direction::Prev)
16944            .map(|s| s.to_vec())
16945        {
16946            self.change_selections(Default::default(), window, cx, |s| {
16947                let map = s.display_snapshot();
16948                s.select_display_ranges(selections.iter().map(|a| {
16949                    let point = a.to_display_point(&map);
16950                    point..point
16951                }))
16952            })
16953        }
16954    }
16955
16956    pub fn go_to_next_document_highlight(
16957        &mut self,
16958        _: &GoToNextDocumentHighlight,
16959        window: &mut Window,
16960        cx: &mut Context<Self>,
16961    ) {
16962        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16963    }
16964
16965    pub fn go_to_prev_document_highlight(
16966        &mut self,
16967        _: &GoToPreviousDocumentHighlight,
16968        window: &mut Window,
16969        cx: &mut Context<Self>,
16970    ) {
16971        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16972    }
16973
16974    pub fn go_to_document_highlight_before_or_after_position(
16975        &mut self,
16976        direction: Direction,
16977        window: &mut Window,
16978        cx: &mut Context<Editor>,
16979    ) {
16980        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16981        let snapshot = self.snapshot(window, cx);
16982        let buffer = &snapshot.buffer_snapshot();
16983        let position = self
16984            .selections
16985            .newest::<Point>(&snapshot.display_snapshot)
16986            .head();
16987        let anchor_position = buffer.anchor_after(position);
16988
16989        // Get all document highlights (both read and write)
16990        let mut all_highlights = Vec::new();
16991
16992        if let Some((_, read_highlights)) = self
16993            .background_highlights
16994            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16995        {
16996            all_highlights.extend(read_highlights.iter());
16997        }
16998
16999        if let Some((_, write_highlights)) = self
17000            .background_highlights
17001            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
17002        {
17003            all_highlights.extend(write_highlights.iter());
17004        }
17005
17006        if all_highlights.is_empty() {
17007            return;
17008        }
17009
17010        // Sort highlights by position
17011        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17012
17013        let target_highlight = match direction {
17014            Direction::Next => {
17015                // Find the first highlight after the current position
17016                all_highlights
17017                    .iter()
17018                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17019            }
17020            Direction::Prev => {
17021                // Find the last highlight before the current position
17022                all_highlights
17023                    .iter()
17024                    .rev()
17025                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17026            }
17027        };
17028
17029        if let Some(highlight) = target_highlight {
17030            let destination = highlight.start.to_point(buffer);
17031            let autoscroll = Autoscroll::center();
17032
17033            self.unfold_ranges(&[destination..destination], false, false, cx);
17034            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17035                s.select_ranges([destination..destination]);
17036            });
17037        }
17038    }
17039
17040    fn go_to_line<T: 'static>(
17041        &mut self,
17042        position: Anchor,
17043        highlight_color: Option<Hsla>,
17044        window: &mut Window,
17045        cx: &mut Context<Self>,
17046    ) {
17047        let snapshot = self.snapshot(window, cx).display_snapshot;
17048        let position = position.to_point(&snapshot.buffer_snapshot());
17049        let start = snapshot
17050            .buffer_snapshot()
17051            .clip_point(Point::new(position.row, 0), Bias::Left);
17052        let end = start + Point::new(1, 0);
17053        let start = snapshot.buffer_snapshot().anchor_before(start);
17054        let end = snapshot.buffer_snapshot().anchor_before(end);
17055
17056        self.highlight_rows::<T>(
17057            start..end,
17058            highlight_color
17059                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17060            Default::default(),
17061            cx,
17062        );
17063
17064        if self.buffer.read(cx).is_singleton() {
17065            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17066        }
17067    }
17068
17069    pub fn go_to_definition(
17070        &mut self,
17071        _: &GoToDefinition,
17072        window: &mut Window,
17073        cx: &mut Context<Self>,
17074    ) -> Task<Result<Navigated>> {
17075        let definition =
17076            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17077        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17078        cx.spawn_in(window, async move |editor, cx| {
17079            if definition.await? == Navigated::Yes {
17080                return Ok(Navigated::Yes);
17081            }
17082            match fallback_strategy {
17083                GoToDefinitionFallback::None => Ok(Navigated::No),
17084                GoToDefinitionFallback::FindAllReferences => {
17085                    match editor.update_in(cx, |editor, window, cx| {
17086                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17087                    })? {
17088                        Some(references) => references.await,
17089                        None => Ok(Navigated::No),
17090                    }
17091                }
17092            }
17093        })
17094    }
17095
17096    pub fn go_to_declaration(
17097        &mut self,
17098        _: &GoToDeclaration,
17099        window: &mut Window,
17100        cx: &mut Context<Self>,
17101    ) -> Task<Result<Navigated>> {
17102        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17103    }
17104
17105    pub fn go_to_declaration_split(
17106        &mut self,
17107        _: &GoToDeclaration,
17108        window: &mut Window,
17109        cx: &mut Context<Self>,
17110    ) -> Task<Result<Navigated>> {
17111        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17112    }
17113
17114    pub fn go_to_implementation(
17115        &mut self,
17116        _: &GoToImplementation,
17117        window: &mut Window,
17118        cx: &mut Context<Self>,
17119    ) -> Task<Result<Navigated>> {
17120        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17121    }
17122
17123    pub fn go_to_implementation_split(
17124        &mut self,
17125        _: &GoToImplementationSplit,
17126        window: &mut Window,
17127        cx: &mut Context<Self>,
17128    ) -> Task<Result<Navigated>> {
17129        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17130    }
17131
17132    pub fn go_to_type_definition(
17133        &mut self,
17134        _: &GoToTypeDefinition,
17135        window: &mut Window,
17136        cx: &mut Context<Self>,
17137    ) -> Task<Result<Navigated>> {
17138        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17139    }
17140
17141    pub fn go_to_definition_split(
17142        &mut self,
17143        _: &GoToDefinitionSplit,
17144        window: &mut Window,
17145        cx: &mut Context<Self>,
17146    ) -> Task<Result<Navigated>> {
17147        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17148    }
17149
17150    pub fn go_to_type_definition_split(
17151        &mut self,
17152        _: &GoToTypeDefinitionSplit,
17153        window: &mut Window,
17154        cx: &mut Context<Self>,
17155    ) -> Task<Result<Navigated>> {
17156        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17157    }
17158
17159    fn go_to_definition_of_kind(
17160        &mut self,
17161        kind: GotoDefinitionKind,
17162        split: bool,
17163        window: &mut Window,
17164        cx: &mut Context<Self>,
17165    ) -> Task<Result<Navigated>> {
17166        let Some(provider) = self.semantics_provider.clone() else {
17167            return Task::ready(Ok(Navigated::No));
17168        };
17169        let head = self
17170            .selections
17171            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17172            .head();
17173        let buffer = self.buffer.read(cx);
17174        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17175            return Task::ready(Ok(Navigated::No));
17176        };
17177        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17178            return Task::ready(Ok(Navigated::No));
17179        };
17180
17181        cx.spawn_in(window, async move |editor, cx| {
17182            let Some(definitions) = definitions.await? else {
17183                return Ok(Navigated::No);
17184            };
17185            let navigated = editor
17186                .update_in(cx, |editor, window, cx| {
17187                    editor.navigate_to_hover_links(
17188                        Some(kind),
17189                        definitions
17190                            .into_iter()
17191                            .filter(|location| {
17192                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17193                            })
17194                            .map(HoverLink::Text)
17195                            .collect::<Vec<_>>(),
17196                        split,
17197                        window,
17198                        cx,
17199                    )
17200                })?
17201                .await?;
17202            anyhow::Ok(navigated)
17203        })
17204    }
17205
17206    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17207        let selection = self.selections.newest_anchor();
17208        let head = selection.head();
17209        let tail = selection.tail();
17210
17211        let Some((buffer, start_position)) =
17212            self.buffer.read(cx).text_anchor_for_position(head, cx)
17213        else {
17214            return;
17215        };
17216
17217        let end_position = if head != tail {
17218            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17219                return;
17220            };
17221            Some(pos)
17222        } else {
17223            None
17224        };
17225
17226        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17227            let url = if let Some(end_pos) = end_position {
17228                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17229            } else {
17230                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17231            };
17232
17233            if let Some(url) = url {
17234                cx.update(|window, cx| {
17235                    if parse_zed_link(&url, cx).is_some() {
17236                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17237                    } else {
17238                        cx.open_url(&url);
17239                    }
17240                })?;
17241            }
17242
17243            anyhow::Ok(())
17244        });
17245
17246        url_finder.detach();
17247    }
17248
17249    pub fn open_selected_filename(
17250        &mut self,
17251        _: &OpenSelectedFilename,
17252        window: &mut Window,
17253        cx: &mut Context<Self>,
17254    ) {
17255        let Some(workspace) = self.workspace() else {
17256            return;
17257        };
17258
17259        let position = self.selections.newest_anchor().head();
17260
17261        let Some((buffer, buffer_position)) =
17262            self.buffer.read(cx).text_anchor_for_position(position, cx)
17263        else {
17264            return;
17265        };
17266
17267        let project = self.project.clone();
17268
17269        cx.spawn_in(window, async move |_, cx| {
17270            let result = find_file(&buffer, project, buffer_position, cx).await;
17271
17272            if let Some((_, path)) = result {
17273                workspace
17274                    .update_in(cx, |workspace, window, cx| {
17275                        workspace.open_resolved_path(path, window, cx)
17276                    })?
17277                    .await?;
17278            }
17279            anyhow::Ok(())
17280        })
17281        .detach();
17282    }
17283
17284    pub(crate) fn navigate_to_hover_links(
17285        &mut self,
17286        kind: Option<GotoDefinitionKind>,
17287        definitions: Vec<HoverLink>,
17288        split: bool,
17289        window: &mut Window,
17290        cx: &mut Context<Editor>,
17291    ) -> Task<Result<Navigated>> {
17292        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17293        let mut first_url_or_file = None;
17294        let definitions: Vec<_> = definitions
17295            .into_iter()
17296            .filter_map(|def| match def {
17297                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17298                HoverLink::InlayHint(lsp_location, server_id) => {
17299                    let computation =
17300                        self.compute_target_location(lsp_location, server_id, window, cx);
17301                    Some(cx.background_spawn(computation))
17302                }
17303                HoverLink::Url(url) => {
17304                    first_url_or_file = Some(Either::Left(url));
17305                    None
17306                }
17307                HoverLink::File(path) => {
17308                    first_url_or_file = Some(Either::Right(path));
17309                    None
17310                }
17311            })
17312            .collect();
17313
17314        let workspace = self.workspace();
17315
17316        cx.spawn_in(window, async move |editor, cx| {
17317            let locations: Vec<Location> = future::join_all(definitions)
17318                .await
17319                .into_iter()
17320                .filter_map(|location| location.transpose())
17321                .collect::<Result<_>>()
17322                .context("location tasks")?;
17323            let mut locations = cx.update(|_, cx| {
17324                locations
17325                    .into_iter()
17326                    .map(|location| {
17327                        let buffer = location.buffer.read(cx);
17328                        (location.buffer, location.range.to_point(buffer))
17329                    })
17330                    .into_group_map()
17331            })?;
17332            let mut num_locations = 0;
17333            for ranges in locations.values_mut() {
17334                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17335                ranges.dedup();
17336                num_locations += ranges.len();
17337            }
17338
17339            if num_locations > 1 {
17340                let tab_kind = match kind {
17341                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17342                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17343                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17344                    Some(GotoDefinitionKind::Type) => "Types",
17345                };
17346                let title = editor
17347                    .update_in(cx, |_, _, cx| {
17348                        let target = locations
17349                            .iter()
17350                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17351                            .map(|(buffer, location)| {
17352                                buffer
17353                                    .read(cx)
17354                                    .text_for_range(location.clone())
17355                                    .collect::<String>()
17356                            })
17357                            .filter(|text| !text.contains('\n'))
17358                            .unique()
17359                            .take(3)
17360                            .join(", ");
17361                        if target.is_empty() {
17362                            tab_kind.to_owned()
17363                        } else {
17364                            format!("{tab_kind} for {target}")
17365                        }
17366                    })
17367                    .context("buffer title")?;
17368
17369                let Some(workspace) = workspace else {
17370                    return Ok(Navigated::No);
17371                };
17372
17373                let opened = workspace
17374                    .update_in(cx, |workspace, window, cx| {
17375                        let allow_preview = PreviewTabsSettings::get_global(cx)
17376                            .enable_preview_multibuffer_from_code_navigation;
17377                        Self::open_locations_in_multibuffer(
17378                            workspace,
17379                            locations,
17380                            title,
17381                            split,
17382                            allow_preview,
17383                            MultibufferSelectionMode::First,
17384                            window,
17385                            cx,
17386                        )
17387                    })
17388                    .is_ok();
17389
17390                anyhow::Ok(Navigated::from_bool(opened))
17391            } else if num_locations == 0 {
17392                // If there is one url or file, open it directly
17393                match first_url_or_file {
17394                    Some(Either::Left(url)) => {
17395                        cx.update(|_, cx| cx.open_url(&url))?;
17396                        Ok(Navigated::Yes)
17397                    }
17398                    Some(Either::Right(path)) => {
17399                        // TODO(andrew): respect preview tab settings
17400                        //               `enable_keep_preview_on_code_navigation` and
17401                        //               `enable_preview_file_from_code_navigation`
17402                        let Some(workspace) = workspace else {
17403                            return Ok(Navigated::No);
17404                        };
17405                        workspace
17406                            .update_in(cx, |workspace, window, cx| {
17407                                workspace.open_resolved_path(path, window, cx)
17408                            })?
17409                            .await?;
17410                        Ok(Navigated::Yes)
17411                    }
17412                    None => Ok(Navigated::No),
17413                }
17414            } else {
17415                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17416                let target_range = target_ranges.first().unwrap().clone();
17417
17418                editor.update_in(cx, |editor, window, cx| {
17419                    let range = target_range.to_point(target_buffer.read(cx));
17420                    let range = editor.range_for_match(&range);
17421                    let range = collapse_multiline_range(range);
17422
17423                    if !split
17424                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17425                    {
17426                        editor.go_to_singleton_buffer_range(range, window, cx);
17427                    } else {
17428                        let Some(workspace) = workspace else {
17429                            return Navigated::No;
17430                        };
17431                        let pane = workspace.read(cx).active_pane().clone();
17432                        window.defer(cx, move |window, cx| {
17433                            let target_editor: Entity<Self> =
17434                                workspace.update(cx, |workspace, cx| {
17435                                    let pane = if split {
17436                                        workspace.adjacent_pane(window, cx)
17437                                    } else {
17438                                        workspace.active_pane().clone()
17439                                    };
17440
17441                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17442                                    let keep_old_preview = preview_tabs_settings
17443                                        .enable_keep_preview_on_code_navigation;
17444                                    let allow_new_preview = preview_tabs_settings
17445                                        .enable_preview_file_from_code_navigation;
17446
17447                                    workspace.open_project_item(
17448                                        pane,
17449                                        target_buffer.clone(),
17450                                        true,
17451                                        true,
17452                                        keep_old_preview,
17453                                        allow_new_preview,
17454                                        window,
17455                                        cx,
17456                                    )
17457                                });
17458                            target_editor.update(cx, |target_editor, cx| {
17459                                // When selecting a definition in a different buffer, disable the nav history
17460                                // to avoid creating a history entry at the previous cursor location.
17461                                pane.update(cx, |pane, _| pane.disable_history());
17462                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17463                                pane.update(cx, |pane, _| pane.enable_history());
17464                            });
17465                        });
17466                    }
17467                    Navigated::Yes
17468                })
17469            }
17470        })
17471    }
17472
17473    fn compute_target_location(
17474        &self,
17475        lsp_location: lsp::Location,
17476        server_id: LanguageServerId,
17477        window: &mut Window,
17478        cx: &mut Context<Self>,
17479    ) -> Task<anyhow::Result<Option<Location>>> {
17480        let Some(project) = self.project.clone() else {
17481            return Task::ready(Ok(None));
17482        };
17483
17484        cx.spawn_in(window, async move |editor, cx| {
17485            let location_task = editor.update(cx, |_, cx| {
17486                project.update(cx, |project, cx| {
17487                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17488                })
17489            })?;
17490            let location = Some({
17491                let target_buffer_handle = location_task.await.context("open local buffer")?;
17492                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17493                    let target_start = target_buffer
17494                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17495                    let target_end = target_buffer
17496                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17497                    target_buffer.anchor_after(target_start)
17498                        ..target_buffer.anchor_before(target_end)
17499                })?;
17500                Location {
17501                    buffer: target_buffer_handle,
17502                    range,
17503                }
17504            });
17505            Ok(location)
17506        })
17507    }
17508
17509    fn go_to_next_reference(
17510        &mut self,
17511        _: &GoToNextReference,
17512        window: &mut Window,
17513        cx: &mut Context<Self>,
17514    ) {
17515        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17516        if let Some(task) = task {
17517            task.detach();
17518        };
17519    }
17520
17521    fn go_to_prev_reference(
17522        &mut self,
17523        _: &GoToPreviousReference,
17524        window: &mut Window,
17525        cx: &mut Context<Self>,
17526    ) {
17527        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17528        if let Some(task) = task {
17529            task.detach();
17530        };
17531    }
17532
17533    pub fn go_to_reference_before_or_after_position(
17534        &mut self,
17535        direction: Direction,
17536        count: usize,
17537        window: &mut Window,
17538        cx: &mut Context<Self>,
17539    ) -> Option<Task<Result<()>>> {
17540        let selection = self.selections.newest_anchor();
17541        let head = selection.head();
17542
17543        let multi_buffer = self.buffer.read(cx);
17544
17545        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17546        let workspace = self.workspace()?;
17547        let project = workspace.read(cx).project().clone();
17548        let references =
17549            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17550        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17551            let Some(locations) = references.await? else {
17552                return Ok(());
17553            };
17554
17555            if locations.is_empty() {
17556                // totally normal - the cursor may be on something which is not
17557                // a symbol (e.g. a keyword)
17558                log::info!("no references found under cursor");
17559                return Ok(());
17560            }
17561
17562            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17563
17564            let (locations, current_location_index) =
17565                multi_buffer.update(cx, |multi_buffer, cx| {
17566                    let mut locations = locations
17567                        .into_iter()
17568                        .filter_map(|loc| {
17569                            let start = multi_buffer.buffer_anchor_to_anchor(
17570                                &loc.buffer,
17571                                loc.range.start,
17572                                cx,
17573                            )?;
17574                            let end = multi_buffer.buffer_anchor_to_anchor(
17575                                &loc.buffer,
17576                                loc.range.end,
17577                                cx,
17578                            )?;
17579                            Some(start..end)
17580                        })
17581                        .collect::<Vec<_>>();
17582
17583                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17584                    // There is an O(n) implementation, but given this list will be
17585                    // small (usually <100 items), the extra O(log(n)) factor isn't
17586                    // worth the (surprisingly large amount of) extra complexity.
17587                    locations
17588                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17589
17590                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17591
17592                    let current_location_index = locations.iter().position(|loc| {
17593                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17594                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17595                    });
17596
17597                    (locations, current_location_index)
17598                })?;
17599
17600            let Some(current_location_index) = current_location_index else {
17601                // This indicates something has gone wrong, because we already
17602                // handle the "no references" case above
17603                log::error!(
17604                    "failed to find current reference under cursor. Total references: {}",
17605                    locations.len()
17606                );
17607                return Ok(());
17608            };
17609
17610            let destination_location_index = match direction {
17611                Direction::Next => (current_location_index + count) % locations.len(),
17612                Direction::Prev => {
17613                    (current_location_index + locations.len() - count % locations.len())
17614                        % locations.len()
17615                }
17616            };
17617
17618            // TODO(cameron): is this needed?
17619            // the thinking is to avoid "jumping to the current location" (avoid
17620            // polluting "jumplist" in vim terms)
17621            if current_location_index == destination_location_index {
17622                return Ok(());
17623            }
17624
17625            let Range { start, end } = locations[destination_location_index];
17626
17627            editor.update_in(cx, |editor, window, cx| {
17628                let effects = SelectionEffects::default();
17629
17630                editor.unfold_ranges(&[start..end], false, false, cx);
17631                editor.change_selections(effects, window, cx, |s| {
17632                    s.select_ranges([start..start]);
17633                });
17634            })?;
17635
17636            Ok(())
17637        }))
17638    }
17639
17640    pub fn find_all_references(
17641        &mut self,
17642        action: &FindAllReferences,
17643        window: &mut Window,
17644        cx: &mut Context<Self>,
17645    ) -> Option<Task<Result<Navigated>>> {
17646        let always_open_multibuffer = action.always_open_multibuffer;
17647        let selection = self.selections.newest_anchor();
17648        let multi_buffer = self.buffer.read(cx);
17649        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17650        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
17651        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
17652        let head = selection_offset.head();
17653
17654        let head_anchor = multi_buffer_snapshot.anchor_at(
17655            head,
17656            if head < selection_offset.tail() {
17657                Bias::Right
17658            } else {
17659                Bias::Left
17660            },
17661        );
17662
17663        match self
17664            .find_all_references_task_sources
17665            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17666        {
17667            Ok(_) => {
17668                log::info!(
17669                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17670                );
17671                return None;
17672            }
17673            Err(i) => {
17674                self.find_all_references_task_sources.insert(i, head_anchor);
17675            }
17676        }
17677
17678        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17679        let workspace = self.workspace()?;
17680        let project = workspace.read(cx).project().clone();
17681        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17682        Some(cx.spawn_in(window, async move |editor, cx| {
17683            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17684                if let Ok(i) = editor
17685                    .find_all_references_task_sources
17686                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17687                {
17688                    editor.find_all_references_task_sources.remove(i);
17689                }
17690            });
17691
17692            let Some(locations) = references.await? else {
17693                return anyhow::Ok(Navigated::No);
17694            };
17695            let mut locations = cx.update(|_, cx| {
17696                locations
17697                    .into_iter()
17698                    .map(|location| {
17699                        let buffer = location.buffer.read(cx);
17700                        (location.buffer, location.range.to_point(buffer))
17701                    })
17702                    // if special-casing the single-match case, remove ranges
17703                    // that intersect current selection
17704                    .filter(|(location_buffer, location)| {
17705                        if always_open_multibuffer || &buffer != location_buffer {
17706                            return true;
17707                        }
17708
17709                        !location.contains_inclusive(&selection_point.range())
17710                    })
17711                    .into_group_map()
17712            })?;
17713            if locations.is_empty() {
17714                return anyhow::Ok(Navigated::No);
17715            }
17716            for ranges in locations.values_mut() {
17717                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17718                ranges.dedup();
17719            }
17720            let mut num_locations = 0;
17721            for ranges in locations.values_mut() {
17722                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17723                ranges.dedup();
17724                num_locations += ranges.len();
17725            }
17726
17727            if num_locations == 1 && !always_open_multibuffer {
17728                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17729                let target_range = target_ranges.first().unwrap().clone();
17730
17731                return editor.update_in(cx, |editor, window, cx| {
17732                    let range = target_range.to_point(target_buffer.read(cx));
17733                    let range = editor.range_for_match(&range);
17734                    let range = range.start..range.start;
17735
17736                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
17737                        editor.go_to_singleton_buffer_range(range, window, cx);
17738                    } else {
17739                        let pane = workspace.read(cx).active_pane().clone();
17740                        window.defer(cx, move |window, cx| {
17741                            let target_editor: Entity<Self> =
17742                                workspace.update(cx, |workspace, cx| {
17743                                    let pane = workspace.active_pane().clone();
17744
17745                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17746                                    let keep_old_preview = preview_tabs_settings
17747                                        .enable_keep_preview_on_code_navigation;
17748                                    let allow_new_preview = preview_tabs_settings
17749                                        .enable_preview_file_from_code_navigation;
17750
17751                                    workspace.open_project_item(
17752                                        pane,
17753                                        target_buffer.clone(),
17754                                        true,
17755                                        true,
17756                                        keep_old_preview,
17757                                        allow_new_preview,
17758                                        window,
17759                                        cx,
17760                                    )
17761                                });
17762                            target_editor.update(cx, |target_editor, cx| {
17763                                // When selecting a definition in a different buffer, disable the nav history
17764                                // to avoid creating a history entry at the previous cursor location.
17765                                pane.update(cx, |pane, _| pane.disable_history());
17766                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17767                                pane.update(cx, |pane, _| pane.enable_history());
17768                            });
17769                        });
17770                    }
17771                    Navigated::No
17772                });
17773            }
17774
17775            workspace.update_in(cx, |workspace, window, cx| {
17776                let target = locations
17777                    .iter()
17778                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17779                    .map(|(buffer, location)| {
17780                        buffer
17781                            .read(cx)
17782                            .text_for_range(location.clone())
17783                            .collect::<String>()
17784                    })
17785                    .filter(|text| !text.contains('\n'))
17786                    .unique()
17787                    .take(3)
17788                    .join(", ");
17789                let title = if target.is_empty() {
17790                    "References".to_owned()
17791                } else {
17792                    format!("References to {target}")
17793                };
17794                let allow_preview = PreviewTabsSettings::get_global(cx)
17795                    .enable_preview_multibuffer_from_code_navigation;
17796                Self::open_locations_in_multibuffer(
17797                    workspace,
17798                    locations,
17799                    title,
17800                    false,
17801                    allow_preview,
17802                    MultibufferSelectionMode::First,
17803                    window,
17804                    cx,
17805                );
17806                Navigated::Yes
17807            })
17808        }))
17809    }
17810
17811    /// Opens a multibuffer with the given project locations in it.
17812    pub fn open_locations_in_multibuffer(
17813        workspace: &mut Workspace,
17814        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17815        title: String,
17816        split: bool,
17817        allow_preview: bool,
17818        multibuffer_selection_mode: MultibufferSelectionMode,
17819        window: &mut Window,
17820        cx: &mut Context<Workspace>,
17821    ) {
17822        if locations.is_empty() {
17823            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17824            return;
17825        }
17826
17827        let capability = workspace.project().read(cx).capability();
17828        let mut ranges = <Vec<Range<Anchor>>>::new();
17829
17830        // a key to find existing multibuffer editors with the same set of locations
17831        // to prevent us from opening more and more multibuffer tabs for searches and the like
17832        let mut key = (title.clone(), vec![]);
17833        let excerpt_buffer = cx.new(|cx| {
17834            let key = &mut key.1;
17835            let mut multibuffer = MultiBuffer::new(capability);
17836            for (buffer, mut ranges_for_buffer) in locations {
17837                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17838                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17839                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17840                    PathKey::for_buffer(&buffer, cx),
17841                    buffer.clone(),
17842                    ranges_for_buffer,
17843                    multibuffer_context_lines(cx),
17844                    cx,
17845                );
17846                ranges.extend(new_ranges)
17847            }
17848
17849            multibuffer.with_title(title)
17850        });
17851        let existing = workspace.active_pane().update(cx, |pane, cx| {
17852            pane.items()
17853                .filter_map(|item| item.downcast::<Editor>())
17854                .find(|editor| {
17855                    editor
17856                        .read(cx)
17857                        .lookup_key
17858                        .as_ref()
17859                        .and_then(|it| {
17860                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17861                        })
17862                        .is_some_and(|it| *it == key)
17863                })
17864        });
17865        let was_existing = existing.is_some();
17866        let editor = existing.unwrap_or_else(|| {
17867            cx.new(|cx| {
17868                let mut editor = Editor::for_multibuffer(
17869                    excerpt_buffer,
17870                    Some(workspace.project().clone()),
17871                    window,
17872                    cx,
17873                );
17874                editor.lookup_key = Some(Box::new(key));
17875                editor
17876            })
17877        });
17878        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17879            MultibufferSelectionMode::First => {
17880                if let Some(first_range) = ranges.first() {
17881                    editor.change_selections(
17882                        SelectionEffects::no_scroll(),
17883                        window,
17884                        cx,
17885                        |selections| {
17886                            selections.clear_disjoint();
17887                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17888                        },
17889                    );
17890                }
17891                editor.highlight_background::<Self>(
17892                    &ranges,
17893                    |_, theme| theme.colors().editor_highlighted_line_background,
17894                    cx,
17895                );
17896            }
17897            MultibufferSelectionMode::All => {
17898                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17899                    selections.clear_disjoint();
17900                    selections.select_anchor_ranges(ranges);
17901                });
17902            }
17903        });
17904
17905        let item = Box::new(editor);
17906
17907        let pane = if split {
17908            workspace.adjacent_pane(window, cx)
17909        } else {
17910            workspace.active_pane().clone()
17911        };
17912        let activate_pane = split;
17913
17914        let mut destination_index = None;
17915        pane.update(cx, |pane, cx| {
17916            if allow_preview && !was_existing {
17917                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
17918            }
17919            if was_existing && !allow_preview {
17920                pane.unpreview_item_if_preview(item.item_id());
17921            }
17922            pane.add_item(item, activate_pane, true, destination_index, window, cx);
17923        });
17924    }
17925
17926    pub fn rename(
17927        &mut self,
17928        _: &Rename,
17929        window: &mut Window,
17930        cx: &mut Context<Self>,
17931    ) -> Option<Task<Result<()>>> {
17932        use language::ToOffset as _;
17933
17934        let provider = self.semantics_provider.clone()?;
17935        let selection = self.selections.newest_anchor().clone();
17936        let (cursor_buffer, cursor_buffer_position) = self
17937            .buffer
17938            .read(cx)
17939            .text_anchor_for_position(selection.head(), cx)?;
17940        let (tail_buffer, cursor_buffer_position_end) = self
17941            .buffer
17942            .read(cx)
17943            .text_anchor_for_position(selection.tail(), cx)?;
17944        if tail_buffer != cursor_buffer {
17945            return None;
17946        }
17947
17948        let snapshot = cursor_buffer.read(cx).snapshot();
17949        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17950        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17951        let prepare_rename = provider
17952            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17953            .unwrap_or_else(|| Task::ready(Ok(None)));
17954        drop(snapshot);
17955
17956        Some(cx.spawn_in(window, async move |this, cx| {
17957            let rename_range = if let Some(range) = prepare_rename.await? {
17958                Some(range)
17959            } else {
17960                this.update(cx, |this, cx| {
17961                    let buffer = this.buffer.read(cx).snapshot(cx);
17962                    let mut buffer_highlights = this
17963                        .document_highlights_for_position(selection.head(), &buffer)
17964                        .filter(|highlight| {
17965                            highlight.start.excerpt_id == selection.head().excerpt_id
17966                                && highlight.end.excerpt_id == selection.head().excerpt_id
17967                        });
17968                    buffer_highlights
17969                        .next()
17970                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17971                })?
17972            };
17973            if let Some(rename_range) = rename_range {
17974                this.update_in(cx, |this, window, cx| {
17975                    let snapshot = cursor_buffer.read(cx).snapshot();
17976                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17977                    let cursor_offset_in_rename_range =
17978                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17979                    let cursor_offset_in_rename_range_end =
17980                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17981
17982                    this.take_rename(false, window, cx);
17983                    let buffer = this.buffer.read(cx).read(cx);
17984                    let cursor_offset = selection.head().to_offset(&buffer);
17985                    let rename_start =
17986                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17987                    let rename_end = rename_start + rename_buffer_range.len();
17988                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17989                    let mut old_highlight_id = None;
17990                    let old_name: Arc<str> = buffer
17991                        .chunks(rename_start..rename_end, true)
17992                        .map(|chunk| {
17993                            if old_highlight_id.is_none() {
17994                                old_highlight_id = chunk.syntax_highlight_id;
17995                            }
17996                            chunk.text
17997                        })
17998                        .collect::<String>()
17999                        .into();
18000
18001                    drop(buffer);
18002
18003                    // Position the selection in the rename editor so that it matches the current selection.
18004                    this.show_local_selections = false;
18005                    let rename_editor = cx.new(|cx| {
18006                        let mut editor = Editor::single_line(window, cx);
18007                        editor.buffer.update(cx, |buffer, cx| {
18008                            buffer.edit(
18009                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18010                                None,
18011                                cx,
18012                            )
18013                        });
18014                        let cursor_offset_in_rename_range =
18015                            MultiBufferOffset(cursor_offset_in_rename_range);
18016                        let cursor_offset_in_rename_range_end =
18017                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18018                        let rename_selection_range = match cursor_offset_in_rename_range
18019                            .cmp(&cursor_offset_in_rename_range_end)
18020                        {
18021                            Ordering::Equal => {
18022                                editor.select_all(&SelectAll, window, cx);
18023                                return editor;
18024                            }
18025                            Ordering::Less => {
18026                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18027                            }
18028                            Ordering::Greater => {
18029                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18030                            }
18031                        };
18032                        if rename_selection_range.end.0 > old_name.len() {
18033                            editor.select_all(&SelectAll, window, cx);
18034                        } else {
18035                            editor.change_selections(Default::default(), window, cx, |s| {
18036                                s.select_ranges([rename_selection_range]);
18037                            });
18038                        }
18039                        editor
18040                    });
18041                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18042                        if e == &EditorEvent::Focused {
18043                            cx.emit(EditorEvent::FocusedIn)
18044                        }
18045                    })
18046                    .detach();
18047
18048                    let write_highlights =
18049                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18050                    let read_highlights =
18051                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18052                    let ranges = write_highlights
18053                        .iter()
18054                        .flat_map(|(_, ranges)| ranges.iter())
18055                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18056                        .cloned()
18057                        .collect();
18058
18059                    this.highlight_text::<Rename>(
18060                        ranges,
18061                        HighlightStyle {
18062                            fade_out: Some(0.6),
18063                            ..Default::default()
18064                        },
18065                        cx,
18066                    );
18067                    let rename_focus_handle = rename_editor.focus_handle(cx);
18068                    window.focus(&rename_focus_handle);
18069                    let block_id = this.insert_blocks(
18070                        [BlockProperties {
18071                            style: BlockStyle::Flex,
18072                            placement: BlockPlacement::Below(range.start),
18073                            height: Some(1),
18074                            render: Arc::new({
18075                                let rename_editor = rename_editor.clone();
18076                                move |cx: &mut BlockContext| {
18077                                    let mut text_style = cx.editor_style.text.clone();
18078                                    if let Some(highlight_style) = old_highlight_id
18079                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18080                                    {
18081                                        text_style = text_style.highlight(highlight_style);
18082                                    }
18083                                    div()
18084                                        .block_mouse_except_scroll()
18085                                        .pl(cx.anchor_x)
18086                                        .child(EditorElement::new(
18087                                            &rename_editor,
18088                                            EditorStyle {
18089                                                background: cx.theme().system().transparent,
18090                                                local_player: cx.editor_style.local_player,
18091                                                text: text_style,
18092                                                scrollbar_width: cx.editor_style.scrollbar_width,
18093                                                syntax: cx.editor_style.syntax.clone(),
18094                                                status: cx.editor_style.status.clone(),
18095                                                inlay_hints_style: HighlightStyle {
18096                                                    font_weight: Some(FontWeight::BOLD),
18097                                                    ..make_inlay_hints_style(cx.app)
18098                                                },
18099                                                edit_prediction_styles: make_suggestion_styles(
18100                                                    cx.app,
18101                                                ),
18102                                                ..EditorStyle::default()
18103                                            },
18104                                        ))
18105                                        .into_any_element()
18106                                }
18107                            }),
18108                            priority: 0,
18109                        }],
18110                        Some(Autoscroll::fit()),
18111                        cx,
18112                    )[0];
18113                    this.pending_rename = Some(RenameState {
18114                        range,
18115                        old_name,
18116                        editor: rename_editor,
18117                        block_id,
18118                    });
18119                })?;
18120            }
18121
18122            Ok(())
18123        }))
18124    }
18125
18126    pub fn confirm_rename(
18127        &mut self,
18128        _: &ConfirmRename,
18129        window: &mut Window,
18130        cx: &mut Context<Self>,
18131    ) -> Option<Task<Result<()>>> {
18132        let rename = self.take_rename(false, window, cx)?;
18133        let workspace = self.workspace()?.downgrade();
18134        let (buffer, start) = self
18135            .buffer
18136            .read(cx)
18137            .text_anchor_for_position(rename.range.start, cx)?;
18138        let (end_buffer, _) = self
18139            .buffer
18140            .read(cx)
18141            .text_anchor_for_position(rename.range.end, cx)?;
18142        if buffer != end_buffer {
18143            return None;
18144        }
18145
18146        let old_name = rename.old_name;
18147        let new_name = rename.editor.read(cx).text(cx);
18148
18149        let rename = self.semantics_provider.as_ref()?.perform_rename(
18150            &buffer,
18151            start,
18152            new_name.clone(),
18153            cx,
18154        )?;
18155
18156        Some(cx.spawn_in(window, async move |editor, cx| {
18157            let project_transaction = rename.await?;
18158            Self::open_project_transaction(
18159                &editor,
18160                workspace,
18161                project_transaction,
18162                format!("Rename: {}{}", old_name, new_name),
18163                cx,
18164            )
18165            .await?;
18166
18167            editor.update(cx, |editor, cx| {
18168                editor.refresh_document_highlights(cx);
18169            })?;
18170            Ok(())
18171        }))
18172    }
18173
18174    fn take_rename(
18175        &mut self,
18176        moving_cursor: bool,
18177        window: &mut Window,
18178        cx: &mut Context<Self>,
18179    ) -> Option<RenameState> {
18180        let rename = self.pending_rename.take()?;
18181        if rename.editor.focus_handle(cx).is_focused(window) {
18182            window.focus(&self.focus_handle);
18183        }
18184
18185        self.remove_blocks(
18186            [rename.block_id].into_iter().collect(),
18187            Some(Autoscroll::fit()),
18188            cx,
18189        );
18190        self.clear_highlights::<Rename>(cx);
18191        self.show_local_selections = true;
18192
18193        if moving_cursor {
18194            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18195                editor
18196                    .selections
18197                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18198                    .head()
18199            });
18200
18201            // Update the selection to match the position of the selection inside
18202            // the rename editor.
18203            let snapshot = self.buffer.read(cx).read(cx);
18204            let rename_range = rename.range.to_offset(&snapshot);
18205            let cursor_in_editor = snapshot
18206                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18207                .min(rename_range.end);
18208            drop(snapshot);
18209
18210            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18211                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18212            });
18213        } else {
18214            self.refresh_document_highlights(cx);
18215        }
18216
18217        Some(rename)
18218    }
18219
18220    pub fn pending_rename(&self) -> Option<&RenameState> {
18221        self.pending_rename.as_ref()
18222    }
18223
18224    fn format(
18225        &mut self,
18226        _: &Format,
18227        window: &mut Window,
18228        cx: &mut Context<Self>,
18229    ) -> Option<Task<Result<()>>> {
18230        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18231
18232        let project = match &self.project {
18233            Some(project) => project.clone(),
18234            None => return None,
18235        };
18236
18237        Some(self.perform_format(
18238            project,
18239            FormatTrigger::Manual,
18240            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18241            window,
18242            cx,
18243        ))
18244    }
18245
18246    fn format_selections(
18247        &mut self,
18248        _: &FormatSelections,
18249        window: &mut Window,
18250        cx: &mut Context<Self>,
18251    ) -> Option<Task<Result<()>>> {
18252        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18253
18254        let project = match &self.project {
18255            Some(project) => project.clone(),
18256            None => return None,
18257        };
18258
18259        let ranges = self
18260            .selections
18261            .all_adjusted(&self.display_snapshot(cx))
18262            .into_iter()
18263            .map(|selection| selection.range())
18264            .collect_vec();
18265
18266        Some(self.perform_format(
18267            project,
18268            FormatTrigger::Manual,
18269            FormatTarget::Ranges(ranges),
18270            window,
18271            cx,
18272        ))
18273    }
18274
18275    fn perform_format(
18276        &mut self,
18277        project: Entity<Project>,
18278        trigger: FormatTrigger,
18279        target: FormatTarget,
18280        window: &mut Window,
18281        cx: &mut Context<Self>,
18282    ) -> Task<Result<()>> {
18283        let buffer = self.buffer.clone();
18284        let (buffers, target) = match target {
18285            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18286            FormatTarget::Ranges(selection_ranges) => {
18287                let multi_buffer = buffer.read(cx);
18288                let snapshot = multi_buffer.read(cx);
18289                let mut buffers = HashSet::default();
18290                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18291                    BTreeMap::new();
18292                for selection_range in selection_ranges {
18293                    for (buffer, buffer_range, _) in
18294                        snapshot.range_to_buffer_ranges(selection_range)
18295                    {
18296                        let buffer_id = buffer.remote_id();
18297                        let start = buffer.anchor_before(buffer_range.start);
18298                        let end = buffer.anchor_after(buffer_range.end);
18299                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18300                        buffer_id_to_ranges
18301                            .entry(buffer_id)
18302                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18303                            .or_insert_with(|| vec![start..end]);
18304                    }
18305                }
18306                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18307            }
18308        };
18309
18310        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18311        let selections_prev = transaction_id_prev
18312            .and_then(|transaction_id_prev| {
18313                // default to selections as they were after the last edit, if we have them,
18314                // instead of how they are now.
18315                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18316                // will take you back to where you made the last edit, instead of staying where you scrolled
18317                self.selection_history
18318                    .transaction(transaction_id_prev)
18319                    .map(|t| t.0.clone())
18320            })
18321            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18322
18323        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18324        let format = project.update(cx, |project, cx| {
18325            project.format(buffers, target, true, trigger, cx)
18326        });
18327
18328        cx.spawn_in(window, async move |editor, cx| {
18329            let transaction = futures::select_biased! {
18330                transaction = format.log_err().fuse() => transaction,
18331                () = timeout => {
18332                    log::warn!("timed out waiting for formatting");
18333                    None
18334                }
18335            };
18336
18337            buffer
18338                .update(cx, |buffer, cx| {
18339                    if let Some(transaction) = transaction
18340                        && !buffer.is_singleton()
18341                    {
18342                        buffer.push_transaction(&transaction.0, cx);
18343                    }
18344                    cx.notify();
18345                })
18346                .ok();
18347
18348            if let Some(transaction_id_now) =
18349                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
18350            {
18351                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18352                if has_new_transaction {
18353                    _ = editor.update(cx, |editor, _| {
18354                        editor
18355                            .selection_history
18356                            .insert_transaction(transaction_id_now, selections_prev);
18357                    });
18358                }
18359            }
18360
18361            Ok(())
18362        })
18363    }
18364
18365    fn organize_imports(
18366        &mut self,
18367        _: &OrganizeImports,
18368        window: &mut Window,
18369        cx: &mut Context<Self>,
18370    ) -> Option<Task<Result<()>>> {
18371        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18372        let project = match &self.project {
18373            Some(project) => project.clone(),
18374            None => return None,
18375        };
18376        Some(self.perform_code_action_kind(
18377            project,
18378            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18379            window,
18380            cx,
18381        ))
18382    }
18383
18384    fn perform_code_action_kind(
18385        &mut self,
18386        project: Entity<Project>,
18387        kind: CodeActionKind,
18388        window: &mut Window,
18389        cx: &mut Context<Self>,
18390    ) -> Task<Result<()>> {
18391        let buffer = self.buffer.clone();
18392        let buffers = buffer.read(cx).all_buffers();
18393        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18394        let apply_action = project.update(cx, |project, cx| {
18395            project.apply_code_action_kind(buffers, kind, true, cx)
18396        });
18397        cx.spawn_in(window, async move |_, cx| {
18398            let transaction = futures::select_biased! {
18399                () = timeout => {
18400                    log::warn!("timed out waiting for executing code action");
18401                    None
18402                }
18403                transaction = apply_action.log_err().fuse() => transaction,
18404            };
18405            buffer
18406                .update(cx, |buffer, cx| {
18407                    // check if we need this
18408                    if let Some(transaction) = transaction
18409                        && !buffer.is_singleton()
18410                    {
18411                        buffer.push_transaction(&transaction.0, cx);
18412                    }
18413                    cx.notify();
18414                })
18415                .ok();
18416            Ok(())
18417        })
18418    }
18419
18420    pub fn restart_language_server(
18421        &mut self,
18422        _: &RestartLanguageServer,
18423        _: &mut Window,
18424        cx: &mut Context<Self>,
18425    ) {
18426        if let Some(project) = self.project.clone() {
18427            self.buffer.update(cx, |multi_buffer, cx| {
18428                project.update(cx, |project, cx| {
18429                    project.restart_language_servers_for_buffers(
18430                        multi_buffer.all_buffers().into_iter().collect(),
18431                        HashSet::default(),
18432                        cx,
18433                    );
18434                });
18435            })
18436        }
18437    }
18438
18439    pub fn stop_language_server(
18440        &mut self,
18441        _: &StopLanguageServer,
18442        _: &mut Window,
18443        cx: &mut Context<Self>,
18444    ) {
18445        if let Some(project) = self.project.clone() {
18446            self.buffer.update(cx, |multi_buffer, cx| {
18447                project.update(cx, |project, cx| {
18448                    project.stop_language_servers_for_buffers(
18449                        multi_buffer.all_buffers().into_iter().collect(),
18450                        HashSet::default(),
18451                        cx,
18452                    );
18453                });
18454            });
18455            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18456        }
18457    }
18458
18459    fn cancel_language_server_work(
18460        workspace: &mut Workspace,
18461        _: &actions::CancelLanguageServerWork,
18462        _: &mut Window,
18463        cx: &mut Context<Workspace>,
18464    ) {
18465        let project = workspace.project();
18466        let buffers = workspace
18467            .active_item(cx)
18468            .and_then(|item| item.act_as::<Editor>(cx))
18469            .map_or(HashSet::default(), |editor| {
18470                editor.read(cx).buffer.read(cx).all_buffers()
18471            });
18472        project.update(cx, |project, cx| {
18473            project.cancel_language_server_work_for_buffers(buffers, cx);
18474        });
18475    }
18476
18477    fn show_character_palette(
18478        &mut self,
18479        _: &ShowCharacterPalette,
18480        window: &mut Window,
18481        _: &mut Context<Self>,
18482    ) {
18483        window.show_character_palette();
18484    }
18485
18486    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18487        if !self.diagnostics_enabled() {
18488            return;
18489        }
18490
18491        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18492            let buffer = self.buffer.read(cx).snapshot(cx);
18493            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18494            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18495            let is_valid = buffer
18496                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18497                .any(|entry| {
18498                    entry.diagnostic.is_primary
18499                        && !entry.range.is_empty()
18500                        && entry.range.start == primary_range_start
18501                        && entry.diagnostic.message == active_diagnostics.active_message
18502                });
18503
18504            if !is_valid {
18505                self.dismiss_diagnostics(cx);
18506            }
18507        }
18508    }
18509
18510    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18511        match &self.active_diagnostics {
18512            ActiveDiagnostic::Group(group) => Some(group),
18513            _ => None,
18514        }
18515    }
18516
18517    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18518        if !self.diagnostics_enabled() {
18519            return;
18520        }
18521        self.dismiss_diagnostics(cx);
18522        self.active_diagnostics = ActiveDiagnostic::All;
18523    }
18524
18525    fn activate_diagnostics(
18526        &mut self,
18527        buffer_id: BufferId,
18528        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18529        window: &mut Window,
18530        cx: &mut Context<Self>,
18531    ) {
18532        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18533            return;
18534        }
18535        self.dismiss_diagnostics(cx);
18536        let snapshot = self.snapshot(window, cx);
18537        let buffer = self.buffer.read(cx).snapshot(cx);
18538        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18539            return;
18540        };
18541
18542        let diagnostic_group = buffer
18543            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18544            .collect::<Vec<_>>();
18545
18546        let language_registry = self
18547            .project()
18548            .map(|project| project.read(cx).languages().clone());
18549
18550        let blocks = renderer.render_group(
18551            diagnostic_group,
18552            buffer_id,
18553            snapshot,
18554            cx.weak_entity(),
18555            language_registry,
18556            cx,
18557        );
18558
18559        let blocks = self.display_map.update(cx, |display_map, cx| {
18560            display_map.insert_blocks(blocks, cx).into_iter().collect()
18561        });
18562        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18563            active_range: buffer.anchor_before(diagnostic.range.start)
18564                ..buffer.anchor_after(diagnostic.range.end),
18565            active_message: diagnostic.diagnostic.message.clone(),
18566            group_id: diagnostic.diagnostic.group_id,
18567            blocks,
18568        });
18569        cx.notify();
18570    }
18571
18572    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18573        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18574            return;
18575        };
18576
18577        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18578        if let ActiveDiagnostic::Group(group) = prev {
18579            self.display_map.update(cx, |display_map, cx| {
18580                display_map.remove_blocks(group.blocks, cx);
18581            });
18582            cx.notify();
18583        }
18584    }
18585
18586    /// Disable inline diagnostics rendering for this editor.
18587    pub fn disable_inline_diagnostics(&mut self) {
18588        self.inline_diagnostics_enabled = false;
18589        self.inline_diagnostics_update = Task::ready(());
18590        self.inline_diagnostics.clear();
18591    }
18592
18593    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18594        self.diagnostics_enabled = false;
18595        self.dismiss_diagnostics(cx);
18596        self.inline_diagnostics_update = Task::ready(());
18597        self.inline_diagnostics.clear();
18598    }
18599
18600    pub fn disable_word_completions(&mut self) {
18601        self.word_completions_enabled = false;
18602    }
18603
18604    pub fn diagnostics_enabled(&self) -> bool {
18605        self.diagnostics_enabled && self.mode.is_full()
18606    }
18607
18608    pub fn inline_diagnostics_enabled(&self) -> bool {
18609        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18610    }
18611
18612    pub fn show_inline_diagnostics(&self) -> bool {
18613        self.show_inline_diagnostics
18614    }
18615
18616    pub fn toggle_inline_diagnostics(
18617        &mut self,
18618        _: &ToggleInlineDiagnostics,
18619        window: &mut Window,
18620        cx: &mut Context<Editor>,
18621    ) {
18622        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18623        self.refresh_inline_diagnostics(false, window, cx);
18624    }
18625
18626    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18627        self.diagnostics_max_severity = severity;
18628        self.display_map.update(cx, |display_map, _| {
18629            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18630        });
18631    }
18632
18633    pub fn toggle_diagnostics(
18634        &mut self,
18635        _: &ToggleDiagnostics,
18636        window: &mut Window,
18637        cx: &mut Context<Editor>,
18638    ) {
18639        if !self.diagnostics_enabled() {
18640            return;
18641        }
18642
18643        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18644            EditorSettings::get_global(cx)
18645                .diagnostics_max_severity
18646                .filter(|severity| severity != &DiagnosticSeverity::Off)
18647                .unwrap_or(DiagnosticSeverity::Hint)
18648        } else {
18649            DiagnosticSeverity::Off
18650        };
18651        self.set_max_diagnostics_severity(new_severity, cx);
18652        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18653            self.active_diagnostics = ActiveDiagnostic::None;
18654            self.inline_diagnostics_update = Task::ready(());
18655            self.inline_diagnostics.clear();
18656        } else {
18657            self.refresh_inline_diagnostics(false, window, cx);
18658        }
18659
18660        cx.notify();
18661    }
18662
18663    pub fn toggle_minimap(
18664        &mut self,
18665        _: &ToggleMinimap,
18666        window: &mut Window,
18667        cx: &mut Context<Editor>,
18668    ) {
18669        if self.supports_minimap(cx) {
18670            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18671        }
18672    }
18673
18674    fn refresh_inline_diagnostics(
18675        &mut self,
18676        debounce: bool,
18677        window: &mut Window,
18678        cx: &mut Context<Self>,
18679    ) {
18680        let max_severity = ProjectSettings::get_global(cx)
18681            .diagnostics
18682            .inline
18683            .max_severity
18684            .unwrap_or(self.diagnostics_max_severity);
18685
18686        if !self.inline_diagnostics_enabled()
18687            || !self.diagnostics_enabled()
18688            || !self.show_inline_diagnostics
18689            || max_severity == DiagnosticSeverity::Off
18690        {
18691            self.inline_diagnostics_update = Task::ready(());
18692            self.inline_diagnostics.clear();
18693            return;
18694        }
18695
18696        let debounce_ms = ProjectSettings::get_global(cx)
18697            .diagnostics
18698            .inline
18699            .update_debounce_ms;
18700        let debounce = if debounce && debounce_ms > 0 {
18701            Some(Duration::from_millis(debounce_ms))
18702        } else {
18703            None
18704        };
18705        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18706            if let Some(debounce) = debounce {
18707                cx.background_executor().timer(debounce).await;
18708            }
18709            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18710                editor
18711                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18712                    .ok()
18713            }) else {
18714                return;
18715            };
18716
18717            let new_inline_diagnostics = cx
18718                .background_spawn(async move {
18719                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18720                    for diagnostic_entry in
18721                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18722                    {
18723                        let message = diagnostic_entry
18724                            .diagnostic
18725                            .message
18726                            .split_once('\n')
18727                            .map(|(line, _)| line)
18728                            .map(SharedString::new)
18729                            .unwrap_or_else(|| {
18730                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18731                            });
18732                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18733                        let (Ok(i) | Err(i)) = inline_diagnostics
18734                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18735                        inline_diagnostics.insert(
18736                            i,
18737                            (
18738                                start_anchor,
18739                                InlineDiagnostic {
18740                                    message,
18741                                    group_id: diagnostic_entry.diagnostic.group_id,
18742                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18743                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18744                                    severity: diagnostic_entry.diagnostic.severity,
18745                                },
18746                            ),
18747                        );
18748                    }
18749                    inline_diagnostics
18750                })
18751                .await;
18752
18753            editor
18754                .update(cx, |editor, cx| {
18755                    editor.inline_diagnostics = new_inline_diagnostics;
18756                    cx.notify();
18757                })
18758                .ok();
18759        });
18760    }
18761
18762    fn pull_diagnostics(
18763        &mut self,
18764        buffer_id: Option<BufferId>,
18765        window: &Window,
18766        cx: &mut Context<Self>,
18767    ) -> Option<()> {
18768        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18769            return None;
18770        }
18771        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18772            .diagnostics
18773            .lsp_pull_diagnostics;
18774        if !pull_diagnostics_settings.enabled {
18775            return None;
18776        }
18777        let project = self.project()?.downgrade();
18778
18779        let mut edited_buffer_ids = HashSet::default();
18780        let mut edited_worktree_ids = HashSet::default();
18781        let edited_buffers = match buffer_id {
18782            Some(buffer_id) => {
18783                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
18784                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
18785                edited_buffer_ids.insert(buffer.read(cx).remote_id());
18786                edited_worktree_ids.insert(worktree_id);
18787                vec![buffer]
18788            }
18789            None => self
18790                .buffer()
18791                .read(cx)
18792                .all_buffers()
18793                .into_iter()
18794                .filter(|buffer| {
18795                    let buffer = buffer.read(cx);
18796                    match buffer.file().map(|f| f.worktree_id(cx)) {
18797                        Some(worktree_id) => {
18798                            edited_buffer_ids.insert(buffer.remote_id());
18799                            edited_worktree_ids.insert(worktree_id);
18800                            true
18801                        }
18802                        None => false,
18803                    }
18804                })
18805                .collect::<Vec<_>>(),
18806        };
18807
18808        if edited_buffers.is_empty() {
18809            self.pull_diagnostics_task = Task::ready(());
18810            self.pull_diagnostics_background_task = Task::ready(());
18811            return None;
18812        }
18813
18814        let mut already_used_buffers = HashSet::default();
18815        let related_open_buffers = self
18816            .workspace
18817            .as_ref()
18818            .and_then(|(workspace, _)| workspace.upgrade())
18819            .into_iter()
18820            .flat_map(|workspace| workspace.read(cx).panes())
18821            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
18822            .filter(|editor| editor != &cx.entity())
18823            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
18824            .filter(|buffer| {
18825                let buffer = buffer.read(cx);
18826                let buffer_id = buffer.remote_id();
18827                if already_used_buffers.insert(buffer_id) {
18828                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
18829                        return !edited_buffer_ids.contains(&buffer_id)
18830                            && !edited_worktree_ids.contains(&worktree_id);
18831                    }
18832                }
18833                false
18834            })
18835            .collect::<Vec<_>>();
18836
18837        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18838        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
18839            if buffers.is_empty() {
18840                return Task::ready(());
18841            }
18842            let project_weak = project.clone();
18843            cx.spawn_in(window, async move |_, cx| {
18844                cx.background_executor().timer(delay).await;
18845
18846                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18847                    buffers
18848                        .into_iter()
18849                        .filter_map(|buffer| {
18850                            project_weak
18851                                .update(cx, |project, cx| {
18852                                    project.lsp_store().update(cx, |lsp_store, cx| {
18853                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18854                                    })
18855                                })
18856                                .ok()
18857                        })
18858                        .collect::<FuturesUnordered<_>>()
18859                }) else {
18860                    return;
18861                };
18862
18863                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18864                    if let Err(e) = pull_task {
18865                        log::error!("Failed to update project diagnostics: {e:#}");
18866                    }
18867                }
18868            })
18869        };
18870
18871        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
18872        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
18873
18874        Some(())
18875    }
18876
18877    pub fn set_selections_from_remote(
18878        &mut self,
18879        selections: Vec<Selection<Anchor>>,
18880        pending_selection: Option<Selection<Anchor>>,
18881        window: &mut Window,
18882        cx: &mut Context<Self>,
18883    ) {
18884        let old_cursor_position = self.selections.newest_anchor().head();
18885        self.selections
18886            .change_with(&self.display_snapshot(cx), |s| {
18887                s.select_anchors(selections);
18888                if let Some(pending_selection) = pending_selection {
18889                    s.set_pending(pending_selection, SelectMode::Character);
18890                } else {
18891                    s.clear_pending();
18892                }
18893            });
18894        self.selections_did_change(
18895            false,
18896            &old_cursor_position,
18897            SelectionEffects::default(),
18898            window,
18899            cx,
18900        );
18901    }
18902
18903    pub fn transact(
18904        &mut self,
18905        window: &mut Window,
18906        cx: &mut Context<Self>,
18907        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18908    ) -> Option<TransactionId> {
18909        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18910            this.start_transaction_at(Instant::now(), window, cx);
18911            update(this, window, cx);
18912            this.end_transaction_at(Instant::now(), cx)
18913        })
18914    }
18915
18916    pub fn start_transaction_at(
18917        &mut self,
18918        now: Instant,
18919        window: &mut Window,
18920        cx: &mut Context<Self>,
18921    ) -> Option<TransactionId> {
18922        self.end_selection(window, cx);
18923        if let Some(tx_id) = self
18924            .buffer
18925            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18926        {
18927            self.selection_history
18928                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18929            cx.emit(EditorEvent::TransactionBegun {
18930                transaction_id: tx_id,
18931            });
18932            Some(tx_id)
18933        } else {
18934            None
18935        }
18936    }
18937
18938    pub fn end_transaction_at(
18939        &mut self,
18940        now: Instant,
18941        cx: &mut Context<Self>,
18942    ) -> Option<TransactionId> {
18943        if let Some(transaction_id) = self
18944            .buffer
18945            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18946        {
18947            if let Some((_, end_selections)) =
18948                self.selection_history.transaction_mut(transaction_id)
18949            {
18950                *end_selections = Some(self.selections.disjoint_anchors_arc());
18951            } else {
18952                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18953            }
18954
18955            cx.emit(EditorEvent::Edited { transaction_id });
18956            Some(transaction_id)
18957        } else {
18958            None
18959        }
18960    }
18961
18962    pub fn modify_transaction_selection_history(
18963        &mut self,
18964        transaction_id: TransactionId,
18965        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18966    ) -> bool {
18967        self.selection_history
18968            .transaction_mut(transaction_id)
18969            .map(modify)
18970            .is_some()
18971    }
18972
18973    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18974        if self.selection_mark_mode {
18975            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18976                s.move_with(|_, sel| {
18977                    sel.collapse_to(sel.head(), SelectionGoal::None);
18978                });
18979            })
18980        }
18981        self.selection_mark_mode = true;
18982        cx.notify();
18983    }
18984
18985    pub fn swap_selection_ends(
18986        &mut self,
18987        _: &actions::SwapSelectionEnds,
18988        window: &mut Window,
18989        cx: &mut Context<Self>,
18990    ) {
18991        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18992            s.move_with(|_, sel| {
18993                if sel.start != sel.end {
18994                    sel.reversed = !sel.reversed
18995                }
18996            });
18997        });
18998        self.request_autoscroll(Autoscroll::newest(), cx);
18999        cx.notify();
19000    }
19001
19002    pub fn toggle_focus(
19003        workspace: &mut Workspace,
19004        _: &actions::ToggleFocus,
19005        window: &mut Window,
19006        cx: &mut Context<Workspace>,
19007    ) {
19008        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19009            return;
19010        };
19011        workspace.activate_item(&item, true, true, window, cx);
19012    }
19013
19014    pub fn toggle_fold(
19015        &mut self,
19016        _: &actions::ToggleFold,
19017        window: &mut Window,
19018        cx: &mut Context<Self>,
19019    ) {
19020        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19021            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19022            let selection = self.selections.newest::<Point>(&display_map);
19023
19024            let range = if selection.is_empty() {
19025                let point = selection.head().to_display_point(&display_map);
19026                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19027                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19028                    .to_point(&display_map);
19029                start..end
19030            } else {
19031                selection.range()
19032            };
19033            if display_map.folds_in_range(range).next().is_some() {
19034                self.unfold_lines(&Default::default(), window, cx)
19035            } else {
19036                self.fold(&Default::default(), window, cx)
19037            }
19038        } else {
19039            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19040            let buffer_ids: HashSet<_> = self
19041                .selections
19042                .disjoint_anchor_ranges()
19043                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19044                .collect();
19045
19046            let should_unfold = buffer_ids
19047                .iter()
19048                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19049
19050            for buffer_id in buffer_ids {
19051                if should_unfold {
19052                    self.unfold_buffer(buffer_id, cx);
19053                } else {
19054                    self.fold_buffer(buffer_id, cx);
19055                }
19056            }
19057        }
19058    }
19059
19060    pub fn toggle_fold_recursive(
19061        &mut self,
19062        _: &actions::ToggleFoldRecursive,
19063        window: &mut Window,
19064        cx: &mut Context<Self>,
19065    ) {
19066        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19067
19068        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19069        let range = if selection.is_empty() {
19070            let point = selection.head().to_display_point(&display_map);
19071            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19072            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19073                .to_point(&display_map);
19074            start..end
19075        } else {
19076            selection.range()
19077        };
19078        if display_map.folds_in_range(range).next().is_some() {
19079            self.unfold_recursive(&Default::default(), window, cx)
19080        } else {
19081            self.fold_recursive(&Default::default(), window, cx)
19082        }
19083    }
19084
19085    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19086        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19087            let mut to_fold = Vec::new();
19088            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19089            let selections = self.selections.all_adjusted(&display_map);
19090
19091            for selection in selections {
19092                let range = selection.range().sorted();
19093                let buffer_start_row = range.start.row;
19094
19095                if range.start.row != range.end.row {
19096                    let mut found = false;
19097                    let mut row = range.start.row;
19098                    while row <= range.end.row {
19099                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19100                        {
19101                            found = true;
19102                            row = crease.range().end.row + 1;
19103                            to_fold.push(crease);
19104                        } else {
19105                            row += 1
19106                        }
19107                    }
19108                    if found {
19109                        continue;
19110                    }
19111                }
19112
19113                for row in (0..=range.start.row).rev() {
19114                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19115                        && crease.range().end.row >= buffer_start_row
19116                    {
19117                        to_fold.push(crease);
19118                        if row <= range.start.row {
19119                            break;
19120                        }
19121                    }
19122                }
19123            }
19124
19125            self.fold_creases(to_fold, true, window, cx);
19126        } else {
19127            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19128            let buffer_ids = self
19129                .selections
19130                .disjoint_anchor_ranges()
19131                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19132                .collect::<HashSet<_>>();
19133            for buffer_id in buffer_ids {
19134                self.fold_buffer(buffer_id, cx);
19135            }
19136        }
19137    }
19138
19139    pub fn toggle_fold_all(
19140        &mut self,
19141        _: &actions::ToggleFoldAll,
19142        window: &mut Window,
19143        cx: &mut Context<Self>,
19144    ) {
19145        if self.buffer.read(cx).is_singleton() {
19146            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19147            let has_folds = display_map
19148                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19149                .next()
19150                .is_some();
19151
19152            if has_folds {
19153                self.unfold_all(&actions::UnfoldAll, window, cx);
19154            } else {
19155                self.fold_all(&actions::FoldAll, window, cx);
19156            }
19157        } else {
19158            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19159            let should_unfold = buffer_ids
19160                .iter()
19161                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19162
19163            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19164                editor
19165                    .update_in(cx, |editor, _, cx| {
19166                        for buffer_id in buffer_ids {
19167                            if should_unfold {
19168                                editor.unfold_buffer(buffer_id, cx);
19169                            } else {
19170                                editor.fold_buffer(buffer_id, cx);
19171                            }
19172                        }
19173                    })
19174                    .ok();
19175            });
19176        }
19177    }
19178
19179    fn fold_at_level(
19180        &mut self,
19181        fold_at: &FoldAtLevel,
19182        window: &mut Window,
19183        cx: &mut Context<Self>,
19184    ) {
19185        if !self.buffer.read(cx).is_singleton() {
19186            return;
19187        }
19188
19189        let fold_at_level = fold_at.0;
19190        let snapshot = self.buffer.read(cx).snapshot(cx);
19191        let mut to_fold = Vec::new();
19192        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19193
19194        let row_ranges_to_keep: Vec<Range<u32>> = self
19195            .selections
19196            .all::<Point>(&self.display_snapshot(cx))
19197            .into_iter()
19198            .map(|sel| sel.start.row..sel.end.row)
19199            .collect();
19200
19201        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19202            while start_row < end_row {
19203                match self
19204                    .snapshot(window, cx)
19205                    .crease_for_buffer_row(MultiBufferRow(start_row))
19206                {
19207                    Some(crease) => {
19208                        let nested_start_row = crease.range().start.row + 1;
19209                        let nested_end_row = crease.range().end.row;
19210
19211                        if current_level < fold_at_level {
19212                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19213                        } else if current_level == fold_at_level {
19214                            // Fold iff there is no selection completely contained within the fold region
19215                            if !row_ranges_to_keep.iter().any(|selection| {
19216                                selection.end >= nested_start_row
19217                                    && selection.start <= nested_end_row
19218                            }) {
19219                                to_fold.push(crease);
19220                            }
19221                        }
19222
19223                        start_row = nested_end_row + 1;
19224                    }
19225                    None => start_row += 1,
19226                }
19227            }
19228        }
19229
19230        self.fold_creases(to_fold, true, window, cx);
19231    }
19232
19233    pub fn fold_at_level_1(
19234        &mut self,
19235        _: &actions::FoldAtLevel1,
19236        window: &mut Window,
19237        cx: &mut Context<Self>,
19238    ) {
19239        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19240    }
19241
19242    pub fn fold_at_level_2(
19243        &mut self,
19244        _: &actions::FoldAtLevel2,
19245        window: &mut Window,
19246        cx: &mut Context<Self>,
19247    ) {
19248        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19249    }
19250
19251    pub fn fold_at_level_3(
19252        &mut self,
19253        _: &actions::FoldAtLevel3,
19254        window: &mut Window,
19255        cx: &mut Context<Self>,
19256    ) {
19257        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19258    }
19259
19260    pub fn fold_at_level_4(
19261        &mut self,
19262        _: &actions::FoldAtLevel4,
19263        window: &mut Window,
19264        cx: &mut Context<Self>,
19265    ) {
19266        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19267    }
19268
19269    pub fn fold_at_level_5(
19270        &mut self,
19271        _: &actions::FoldAtLevel5,
19272        window: &mut Window,
19273        cx: &mut Context<Self>,
19274    ) {
19275        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19276    }
19277
19278    pub fn fold_at_level_6(
19279        &mut self,
19280        _: &actions::FoldAtLevel6,
19281        window: &mut Window,
19282        cx: &mut Context<Self>,
19283    ) {
19284        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19285    }
19286
19287    pub fn fold_at_level_7(
19288        &mut self,
19289        _: &actions::FoldAtLevel7,
19290        window: &mut Window,
19291        cx: &mut Context<Self>,
19292    ) {
19293        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19294    }
19295
19296    pub fn fold_at_level_8(
19297        &mut self,
19298        _: &actions::FoldAtLevel8,
19299        window: &mut Window,
19300        cx: &mut Context<Self>,
19301    ) {
19302        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19303    }
19304
19305    pub fn fold_at_level_9(
19306        &mut self,
19307        _: &actions::FoldAtLevel9,
19308        window: &mut Window,
19309        cx: &mut Context<Self>,
19310    ) {
19311        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19312    }
19313
19314    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19315        if self.buffer.read(cx).is_singleton() {
19316            let mut fold_ranges = Vec::new();
19317            let snapshot = self.buffer.read(cx).snapshot(cx);
19318
19319            for row in 0..snapshot.max_row().0 {
19320                if let Some(foldable_range) = self
19321                    .snapshot(window, cx)
19322                    .crease_for_buffer_row(MultiBufferRow(row))
19323                {
19324                    fold_ranges.push(foldable_range);
19325                }
19326            }
19327
19328            self.fold_creases(fold_ranges, true, window, cx);
19329        } else {
19330            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19331                editor
19332                    .update_in(cx, |editor, _, cx| {
19333                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19334                            editor.fold_buffer(buffer_id, cx);
19335                        }
19336                    })
19337                    .ok();
19338            });
19339        }
19340    }
19341
19342    pub fn fold_function_bodies(
19343        &mut self,
19344        _: &actions::FoldFunctionBodies,
19345        window: &mut Window,
19346        cx: &mut Context<Self>,
19347    ) {
19348        let snapshot = self.buffer.read(cx).snapshot(cx);
19349
19350        let ranges = snapshot
19351            .text_object_ranges(
19352                MultiBufferOffset(0)..snapshot.len(),
19353                TreeSitterOptions::default(),
19354            )
19355            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19356            .collect::<Vec<_>>();
19357
19358        let creases = ranges
19359            .into_iter()
19360            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19361            .collect();
19362
19363        self.fold_creases(creases, true, window, cx);
19364    }
19365
19366    pub fn fold_recursive(
19367        &mut self,
19368        _: &actions::FoldRecursive,
19369        window: &mut Window,
19370        cx: &mut Context<Self>,
19371    ) {
19372        let mut to_fold = Vec::new();
19373        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19374        let selections = self.selections.all_adjusted(&display_map);
19375
19376        for selection in selections {
19377            let range = selection.range().sorted();
19378            let buffer_start_row = range.start.row;
19379
19380            if range.start.row != range.end.row {
19381                let mut found = false;
19382                for row in range.start.row..=range.end.row {
19383                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19384                        found = true;
19385                        to_fold.push(crease);
19386                    }
19387                }
19388                if found {
19389                    continue;
19390                }
19391            }
19392
19393            for row in (0..=range.start.row).rev() {
19394                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19395                    if crease.range().end.row >= buffer_start_row {
19396                        to_fold.push(crease);
19397                    } else {
19398                        break;
19399                    }
19400                }
19401            }
19402        }
19403
19404        self.fold_creases(to_fold, true, window, cx);
19405    }
19406
19407    pub fn fold_at(
19408        &mut self,
19409        buffer_row: MultiBufferRow,
19410        window: &mut Window,
19411        cx: &mut Context<Self>,
19412    ) {
19413        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19414
19415        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19416            let autoscroll = self
19417                .selections
19418                .all::<Point>(&display_map)
19419                .iter()
19420                .any(|selection| crease.range().overlaps(&selection.range()));
19421
19422            self.fold_creases(vec![crease], autoscroll, window, cx);
19423        }
19424    }
19425
19426    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19427        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19428            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19429            let buffer = display_map.buffer_snapshot();
19430            let selections = self.selections.all::<Point>(&display_map);
19431            let ranges = selections
19432                .iter()
19433                .map(|s| {
19434                    let range = s.display_range(&display_map).sorted();
19435                    let mut start = range.start.to_point(&display_map);
19436                    let mut end = range.end.to_point(&display_map);
19437                    start.column = 0;
19438                    end.column = buffer.line_len(MultiBufferRow(end.row));
19439                    start..end
19440                })
19441                .collect::<Vec<_>>();
19442
19443            self.unfold_ranges(&ranges, true, true, cx);
19444        } else {
19445            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19446            let buffer_ids = self
19447                .selections
19448                .disjoint_anchor_ranges()
19449                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19450                .collect::<HashSet<_>>();
19451            for buffer_id in buffer_ids {
19452                self.unfold_buffer(buffer_id, cx);
19453            }
19454        }
19455    }
19456
19457    pub fn unfold_recursive(
19458        &mut self,
19459        _: &UnfoldRecursive,
19460        _window: &mut Window,
19461        cx: &mut Context<Self>,
19462    ) {
19463        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19464        let selections = self.selections.all::<Point>(&display_map);
19465        let ranges = selections
19466            .iter()
19467            .map(|s| {
19468                let mut range = s.display_range(&display_map).sorted();
19469                *range.start.column_mut() = 0;
19470                *range.end.column_mut() = display_map.line_len(range.end.row());
19471                let start = range.start.to_point(&display_map);
19472                let end = range.end.to_point(&display_map);
19473                start..end
19474            })
19475            .collect::<Vec<_>>();
19476
19477        self.unfold_ranges(&ranges, true, true, cx);
19478    }
19479
19480    pub fn unfold_at(
19481        &mut self,
19482        buffer_row: MultiBufferRow,
19483        _window: &mut Window,
19484        cx: &mut Context<Self>,
19485    ) {
19486        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19487
19488        let intersection_range = Point::new(buffer_row.0, 0)
19489            ..Point::new(
19490                buffer_row.0,
19491                display_map.buffer_snapshot().line_len(buffer_row),
19492            );
19493
19494        let autoscroll = self
19495            .selections
19496            .all::<Point>(&display_map)
19497            .iter()
19498            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19499
19500        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19501    }
19502
19503    pub fn unfold_all(
19504        &mut self,
19505        _: &actions::UnfoldAll,
19506        _window: &mut Window,
19507        cx: &mut Context<Self>,
19508    ) {
19509        if self.buffer.read(cx).is_singleton() {
19510            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19511            self.unfold_ranges(
19512                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19513                true,
19514                true,
19515                cx,
19516            );
19517        } else {
19518            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19519                editor
19520                    .update(cx, |editor, cx| {
19521                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19522                            editor.unfold_buffer(buffer_id, cx);
19523                        }
19524                    })
19525                    .ok();
19526            });
19527        }
19528    }
19529
19530    pub fn fold_selected_ranges(
19531        &mut self,
19532        _: &FoldSelectedRanges,
19533        window: &mut Window,
19534        cx: &mut Context<Self>,
19535    ) {
19536        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19537        let selections = self.selections.all_adjusted(&display_map);
19538        let ranges = selections
19539            .into_iter()
19540            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19541            .collect::<Vec<_>>();
19542        self.fold_creases(ranges, true, window, cx);
19543    }
19544
19545    pub fn fold_ranges<T: ToOffset + Clone>(
19546        &mut self,
19547        ranges: Vec<Range<T>>,
19548        auto_scroll: bool,
19549        window: &mut Window,
19550        cx: &mut Context<Self>,
19551    ) {
19552        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19553        let ranges = ranges
19554            .into_iter()
19555            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19556            .collect::<Vec<_>>();
19557        self.fold_creases(ranges, auto_scroll, window, cx);
19558    }
19559
19560    pub fn fold_creases<T: ToOffset + Clone>(
19561        &mut self,
19562        creases: Vec<Crease<T>>,
19563        auto_scroll: bool,
19564        _window: &mut Window,
19565        cx: &mut Context<Self>,
19566    ) {
19567        if creases.is_empty() {
19568            return;
19569        }
19570
19571        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19572
19573        if auto_scroll {
19574            self.request_autoscroll(Autoscroll::fit(), cx);
19575        }
19576
19577        cx.notify();
19578
19579        self.scrollbar_marker_state.dirty = true;
19580        self.folds_did_change(cx);
19581    }
19582
19583    /// Removes any folds whose ranges intersect any of the given ranges.
19584    pub fn unfold_ranges<T: ToOffset + Clone>(
19585        &mut self,
19586        ranges: &[Range<T>],
19587        inclusive: bool,
19588        auto_scroll: bool,
19589        cx: &mut Context<Self>,
19590    ) {
19591        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19592            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19593        });
19594        self.folds_did_change(cx);
19595    }
19596
19597    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19598        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19599            return;
19600        }
19601
19602        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19603        self.display_map.update(cx, |display_map, cx| {
19604            display_map.fold_buffers([buffer_id], cx)
19605        });
19606
19607        let snapshot = self.display_snapshot(cx);
19608        self.selections.change_with(&snapshot, |selections| {
19609            selections.remove_selections_from_buffer(buffer_id);
19610        });
19611
19612        cx.emit(EditorEvent::BufferFoldToggled {
19613            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19614            folded: true,
19615        });
19616        cx.notify();
19617    }
19618
19619    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19620        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19621            return;
19622        }
19623        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19624        self.display_map.update(cx, |display_map, cx| {
19625            display_map.unfold_buffers([buffer_id], cx);
19626        });
19627        cx.emit(EditorEvent::BufferFoldToggled {
19628            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19629            folded: false,
19630        });
19631        cx.notify();
19632    }
19633
19634    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19635        self.display_map.read(cx).is_buffer_folded(buffer)
19636    }
19637
19638    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19639        self.display_map.read(cx).folded_buffers()
19640    }
19641
19642    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19643        self.display_map.update(cx, |display_map, cx| {
19644            display_map.disable_header_for_buffer(buffer_id, cx);
19645        });
19646        cx.notify();
19647    }
19648
19649    /// Removes any folds with the given ranges.
19650    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19651        &mut self,
19652        ranges: &[Range<T>],
19653        type_id: TypeId,
19654        auto_scroll: bool,
19655        cx: &mut Context<Self>,
19656    ) {
19657        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19658            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19659        });
19660        self.folds_did_change(cx);
19661    }
19662
19663    fn remove_folds_with<T: ToOffset + Clone>(
19664        &mut self,
19665        ranges: &[Range<T>],
19666        auto_scroll: bool,
19667        cx: &mut Context<Self>,
19668        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19669    ) {
19670        if ranges.is_empty() {
19671            return;
19672        }
19673
19674        let mut buffers_affected = HashSet::default();
19675        let multi_buffer = self.buffer().read(cx);
19676        for range in ranges {
19677            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19678                buffers_affected.insert(buffer.read(cx).remote_id());
19679            };
19680        }
19681
19682        self.display_map.update(cx, update);
19683
19684        if auto_scroll {
19685            self.request_autoscroll(Autoscroll::fit(), cx);
19686        }
19687
19688        cx.notify();
19689        self.scrollbar_marker_state.dirty = true;
19690        self.active_indent_guides_state.dirty = true;
19691    }
19692
19693    pub fn update_renderer_widths(
19694        &mut self,
19695        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19696        cx: &mut Context<Self>,
19697    ) -> bool {
19698        self.display_map
19699            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19700    }
19701
19702    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19703        self.display_map.read(cx).fold_placeholder.clone()
19704    }
19705
19706    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19707        self.use_base_text_line_numbers = show;
19708    }
19709
19710    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19711        self.buffer.update(cx, |buffer, cx| {
19712            buffer.set_all_diff_hunks_expanded(cx);
19713        });
19714    }
19715
19716    pub fn expand_all_diff_hunks(
19717        &mut self,
19718        _: &ExpandAllDiffHunks,
19719        _window: &mut Window,
19720        cx: &mut Context<Self>,
19721    ) {
19722        self.buffer.update(cx, |buffer, cx| {
19723            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19724        });
19725    }
19726
19727    pub fn collapse_all_diff_hunks(
19728        &mut self,
19729        _: &CollapseAllDiffHunks,
19730        _window: &mut Window,
19731        cx: &mut Context<Self>,
19732    ) {
19733        self.buffer.update(cx, |buffer, cx| {
19734            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19735        });
19736    }
19737
19738    pub fn toggle_selected_diff_hunks(
19739        &mut self,
19740        _: &ToggleSelectedDiffHunks,
19741        _window: &mut Window,
19742        cx: &mut Context<Self>,
19743    ) {
19744        let ranges: Vec<_> = self
19745            .selections
19746            .disjoint_anchors()
19747            .iter()
19748            .map(|s| s.range())
19749            .collect();
19750        self.toggle_diff_hunks_in_ranges(ranges, cx);
19751    }
19752
19753    pub fn diff_hunks_in_ranges<'a>(
19754        &'a self,
19755        ranges: &'a [Range<Anchor>],
19756        buffer: &'a MultiBufferSnapshot,
19757    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19758        ranges.iter().flat_map(move |range| {
19759            let end_excerpt_id = range.end.excerpt_id;
19760            let range = range.to_point(buffer);
19761            let mut peek_end = range.end;
19762            if range.end.row < buffer.max_row().0 {
19763                peek_end = Point::new(range.end.row + 1, 0);
19764            }
19765            buffer
19766                .diff_hunks_in_range(range.start..peek_end)
19767                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19768        })
19769    }
19770
19771    pub fn has_stageable_diff_hunks_in_ranges(
19772        &self,
19773        ranges: &[Range<Anchor>],
19774        snapshot: &MultiBufferSnapshot,
19775    ) -> bool {
19776        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19777        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19778    }
19779
19780    pub fn toggle_staged_selected_diff_hunks(
19781        &mut self,
19782        _: &::git::ToggleStaged,
19783        _: &mut Window,
19784        cx: &mut Context<Self>,
19785    ) {
19786        let snapshot = self.buffer.read(cx).snapshot(cx);
19787        let ranges: Vec<_> = self
19788            .selections
19789            .disjoint_anchors()
19790            .iter()
19791            .map(|s| s.range())
19792            .collect();
19793        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19794        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19795    }
19796
19797    pub fn set_render_diff_hunk_controls(
19798        &mut self,
19799        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19800        cx: &mut Context<Self>,
19801    ) {
19802        self.render_diff_hunk_controls = render_diff_hunk_controls;
19803        cx.notify();
19804    }
19805
19806    pub fn stage_and_next(
19807        &mut self,
19808        _: &::git::StageAndNext,
19809        window: &mut Window,
19810        cx: &mut Context<Self>,
19811    ) {
19812        self.do_stage_or_unstage_and_next(true, window, cx);
19813    }
19814
19815    pub fn unstage_and_next(
19816        &mut self,
19817        _: &::git::UnstageAndNext,
19818        window: &mut Window,
19819        cx: &mut Context<Self>,
19820    ) {
19821        self.do_stage_or_unstage_and_next(false, window, cx);
19822    }
19823
19824    pub fn stage_or_unstage_diff_hunks(
19825        &mut self,
19826        stage: bool,
19827        ranges: Vec<Range<Anchor>>,
19828        cx: &mut Context<Self>,
19829    ) {
19830        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19831        cx.spawn(async move |this, cx| {
19832            task.await?;
19833            this.update(cx, |this, cx| {
19834                let snapshot = this.buffer.read(cx).snapshot(cx);
19835                let chunk_by = this
19836                    .diff_hunks_in_ranges(&ranges, &snapshot)
19837                    .chunk_by(|hunk| hunk.buffer_id);
19838                for (buffer_id, hunks) in &chunk_by {
19839                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19840                }
19841            })
19842        })
19843        .detach_and_log_err(cx);
19844    }
19845
19846    fn save_buffers_for_ranges_if_needed(
19847        &mut self,
19848        ranges: &[Range<Anchor>],
19849        cx: &mut Context<Editor>,
19850    ) -> Task<Result<()>> {
19851        let multibuffer = self.buffer.read(cx);
19852        let snapshot = multibuffer.read(cx);
19853        let buffer_ids: HashSet<_> = ranges
19854            .iter()
19855            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19856            .collect();
19857        drop(snapshot);
19858
19859        let mut buffers = HashSet::default();
19860        for buffer_id in buffer_ids {
19861            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19862                let buffer = buffer_entity.read(cx);
19863                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19864                {
19865                    buffers.insert(buffer_entity);
19866                }
19867            }
19868        }
19869
19870        if let Some(project) = &self.project {
19871            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19872        } else {
19873            Task::ready(Ok(()))
19874        }
19875    }
19876
19877    fn do_stage_or_unstage_and_next(
19878        &mut self,
19879        stage: bool,
19880        window: &mut Window,
19881        cx: &mut Context<Self>,
19882    ) {
19883        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19884
19885        if ranges.iter().any(|range| range.start != range.end) {
19886            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19887            return;
19888        }
19889
19890        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19891        let snapshot = self.snapshot(window, cx);
19892        let position = self
19893            .selections
19894            .newest::<Point>(&snapshot.display_snapshot)
19895            .head();
19896        let mut row = snapshot
19897            .buffer_snapshot()
19898            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19899            .find(|hunk| hunk.row_range.start.0 > position.row)
19900            .map(|hunk| hunk.row_range.start);
19901
19902        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19903        // Outside of the project diff editor, wrap around to the beginning.
19904        if !all_diff_hunks_expanded {
19905            row = row.or_else(|| {
19906                snapshot
19907                    .buffer_snapshot()
19908                    .diff_hunks_in_range(Point::zero()..position)
19909                    .find(|hunk| hunk.row_range.end.0 < position.row)
19910                    .map(|hunk| hunk.row_range.start)
19911            });
19912        }
19913
19914        if let Some(row) = row {
19915            let destination = Point::new(row.0, 0);
19916            let autoscroll = Autoscroll::center();
19917
19918            self.unfold_ranges(&[destination..destination], false, false, cx);
19919            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19920                s.select_ranges([destination..destination]);
19921            });
19922        }
19923    }
19924
19925    fn do_stage_or_unstage(
19926        &self,
19927        stage: bool,
19928        buffer_id: BufferId,
19929        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19930        cx: &mut App,
19931    ) -> Option<()> {
19932        let project = self.project()?;
19933        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19934        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19935        let buffer_snapshot = buffer.read(cx).snapshot();
19936        let file_exists = buffer_snapshot
19937            .file()
19938            .is_some_and(|file| file.disk_state().exists());
19939        diff.update(cx, |diff, cx| {
19940            diff.stage_or_unstage_hunks(
19941                stage,
19942                &hunks
19943                    .map(|hunk| buffer_diff::DiffHunk {
19944                        buffer_range: hunk.buffer_range,
19945                        // We don't need to pass in word diffs here because they're only used for rendering and
19946                        // this function changes internal state
19947                        base_word_diffs: Vec::default(),
19948                        buffer_word_diffs: Vec::default(),
19949                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19950                            ..hunk.diff_base_byte_range.end.0,
19951                        secondary_status: hunk.secondary_status,
19952                        range: Point::zero()..Point::zero(), // unused
19953                    })
19954                    .collect::<Vec<_>>(),
19955                &buffer_snapshot,
19956                file_exists,
19957                cx,
19958            )
19959        });
19960        None
19961    }
19962
19963    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19964        let ranges: Vec<_> = self
19965            .selections
19966            .disjoint_anchors()
19967            .iter()
19968            .map(|s| s.range())
19969            .collect();
19970        self.buffer
19971            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19972    }
19973
19974    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19975        self.buffer.update(cx, |buffer, cx| {
19976            let ranges = vec![Anchor::min()..Anchor::max()];
19977            if !buffer.all_diff_hunks_expanded()
19978                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19979            {
19980                buffer.collapse_diff_hunks(ranges, cx);
19981                true
19982            } else {
19983                false
19984            }
19985        })
19986    }
19987
19988    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19989        if self.buffer.read(cx).all_diff_hunks_expanded() {
19990            return true;
19991        }
19992        let ranges = vec![Anchor::min()..Anchor::max()];
19993        self.buffer
19994            .read(cx)
19995            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19996    }
19997
19998    fn toggle_diff_hunks_in_ranges(
19999        &mut self,
20000        ranges: Vec<Range<Anchor>>,
20001        cx: &mut Context<Editor>,
20002    ) {
20003        self.buffer.update(cx, |buffer, cx| {
20004            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
20005            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
20006        })
20007    }
20008
20009    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20010        self.buffer.update(cx, |buffer, cx| {
20011            let snapshot = buffer.snapshot(cx);
20012            let excerpt_id = range.end.excerpt_id;
20013            let point_range = range.to_point(&snapshot);
20014            let expand = !buffer.single_hunk_is_expanded(range, cx);
20015            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
20016        })
20017    }
20018
20019    pub(crate) fn apply_all_diff_hunks(
20020        &mut self,
20021        _: &ApplyAllDiffHunks,
20022        window: &mut Window,
20023        cx: &mut Context<Self>,
20024    ) {
20025        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20026
20027        let buffers = self.buffer.read(cx).all_buffers();
20028        for branch_buffer in buffers {
20029            branch_buffer.update(cx, |branch_buffer, cx| {
20030                branch_buffer.merge_into_base(Vec::new(), cx);
20031            });
20032        }
20033
20034        if let Some(project) = self.project.clone() {
20035            self.save(
20036                SaveOptions {
20037                    format: true,
20038                    autosave: false,
20039                },
20040                project,
20041                window,
20042                cx,
20043            )
20044            .detach_and_log_err(cx);
20045        }
20046    }
20047
20048    pub(crate) fn apply_selected_diff_hunks(
20049        &mut self,
20050        _: &ApplyDiffHunk,
20051        window: &mut Window,
20052        cx: &mut Context<Self>,
20053    ) {
20054        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20055        let snapshot = self.snapshot(window, cx);
20056        let hunks = snapshot.hunks_for_ranges(
20057            self.selections
20058                .all(&snapshot.display_snapshot)
20059                .into_iter()
20060                .map(|selection| selection.range()),
20061        );
20062        let mut ranges_by_buffer = HashMap::default();
20063        self.transact(window, cx, |editor, _window, cx| {
20064            for hunk in hunks {
20065                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20066                    ranges_by_buffer
20067                        .entry(buffer.clone())
20068                        .or_insert_with(Vec::new)
20069                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20070                }
20071            }
20072
20073            for (buffer, ranges) in ranges_by_buffer {
20074                buffer.update(cx, |buffer, cx| {
20075                    buffer.merge_into_base(ranges, cx);
20076                });
20077            }
20078        });
20079
20080        if let Some(project) = self.project.clone() {
20081            self.save(
20082                SaveOptions {
20083                    format: true,
20084                    autosave: false,
20085                },
20086                project,
20087                window,
20088                cx,
20089            )
20090            .detach_and_log_err(cx);
20091        }
20092    }
20093
20094    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20095        if hovered != self.gutter_hovered {
20096            self.gutter_hovered = hovered;
20097            cx.notify();
20098        }
20099    }
20100
20101    pub fn insert_blocks(
20102        &mut self,
20103        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20104        autoscroll: Option<Autoscroll>,
20105        cx: &mut Context<Self>,
20106    ) -> Vec<CustomBlockId> {
20107        let blocks = self
20108            .display_map
20109            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20110        if let Some(autoscroll) = autoscroll {
20111            self.request_autoscroll(autoscroll, cx);
20112        }
20113        cx.notify();
20114        blocks
20115    }
20116
20117    pub fn resize_blocks(
20118        &mut self,
20119        heights: HashMap<CustomBlockId, u32>,
20120        autoscroll: Option<Autoscroll>,
20121        cx: &mut Context<Self>,
20122    ) {
20123        self.display_map
20124            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20125        if let Some(autoscroll) = autoscroll {
20126            self.request_autoscroll(autoscroll, cx);
20127        }
20128        cx.notify();
20129    }
20130
20131    pub fn replace_blocks(
20132        &mut self,
20133        renderers: HashMap<CustomBlockId, RenderBlock>,
20134        autoscroll: Option<Autoscroll>,
20135        cx: &mut Context<Self>,
20136    ) {
20137        self.display_map
20138            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20139        if let Some(autoscroll) = autoscroll {
20140            self.request_autoscroll(autoscroll, cx);
20141        }
20142        cx.notify();
20143    }
20144
20145    pub fn remove_blocks(
20146        &mut self,
20147        block_ids: HashSet<CustomBlockId>,
20148        autoscroll: Option<Autoscroll>,
20149        cx: &mut Context<Self>,
20150    ) {
20151        self.display_map.update(cx, |display_map, cx| {
20152            display_map.remove_blocks(block_ids, cx)
20153        });
20154        if let Some(autoscroll) = autoscroll {
20155            self.request_autoscroll(autoscroll, cx);
20156        }
20157        cx.notify();
20158    }
20159
20160    pub fn row_for_block(
20161        &self,
20162        block_id: CustomBlockId,
20163        cx: &mut Context<Self>,
20164    ) -> Option<DisplayRow> {
20165        self.display_map
20166            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20167    }
20168
20169    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20170        self.focused_block = Some(focused_block);
20171    }
20172
20173    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20174        self.focused_block.take()
20175    }
20176
20177    pub fn insert_creases(
20178        &mut self,
20179        creases: impl IntoIterator<Item = Crease<Anchor>>,
20180        cx: &mut Context<Self>,
20181    ) -> Vec<CreaseId> {
20182        self.display_map
20183            .update(cx, |map, cx| map.insert_creases(creases, cx))
20184    }
20185
20186    pub fn remove_creases(
20187        &mut self,
20188        ids: impl IntoIterator<Item = CreaseId>,
20189        cx: &mut Context<Self>,
20190    ) -> Vec<(CreaseId, Range<Anchor>)> {
20191        self.display_map
20192            .update(cx, |map, cx| map.remove_creases(ids, cx))
20193    }
20194
20195    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20196        self.display_map
20197            .update(cx, |map, cx| map.snapshot(cx))
20198            .longest_row()
20199    }
20200
20201    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20202        self.display_map
20203            .update(cx, |map, cx| map.snapshot(cx))
20204            .max_point()
20205    }
20206
20207    pub fn text(&self, cx: &App) -> String {
20208        self.buffer.read(cx).read(cx).text()
20209    }
20210
20211    pub fn is_empty(&self, cx: &App) -> bool {
20212        self.buffer.read(cx).read(cx).is_empty()
20213    }
20214
20215    pub fn text_option(&self, cx: &App) -> Option<String> {
20216        let text = self.text(cx);
20217        let text = text.trim();
20218
20219        if text.is_empty() {
20220            return None;
20221        }
20222
20223        Some(text.to_string())
20224    }
20225
20226    pub fn set_text(
20227        &mut self,
20228        text: impl Into<Arc<str>>,
20229        window: &mut Window,
20230        cx: &mut Context<Self>,
20231    ) {
20232        self.transact(window, cx, |this, _, cx| {
20233            this.buffer
20234                .read(cx)
20235                .as_singleton()
20236                .expect("you can only call set_text on editors for singleton buffers")
20237                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20238        });
20239    }
20240
20241    pub fn display_text(&self, cx: &mut App) -> String {
20242        self.display_map
20243            .update(cx, |map, cx| map.snapshot(cx))
20244            .text()
20245    }
20246
20247    fn create_minimap(
20248        &self,
20249        minimap_settings: MinimapSettings,
20250        window: &mut Window,
20251        cx: &mut Context<Self>,
20252    ) -> Option<Entity<Self>> {
20253        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20254            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20255    }
20256
20257    fn initialize_new_minimap(
20258        &self,
20259        minimap_settings: MinimapSettings,
20260        window: &mut Window,
20261        cx: &mut Context<Self>,
20262    ) -> Entity<Self> {
20263        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20264
20265        let mut minimap = Editor::new_internal(
20266            EditorMode::Minimap {
20267                parent: cx.weak_entity(),
20268            },
20269            self.buffer.clone(),
20270            None,
20271            Some(self.display_map.clone()),
20272            window,
20273            cx,
20274        );
20275        minimap.scroll_manager.clone_state(&self.scroll_manager);
20276        minimap.set_text_style_refinement(TextStyleRefinement {
20277            font_size: Some(MINIMAP_FONT_SIZE),
20278            font_weight: Some(MINIMAP_FONT_WEIGHT),
20279            ..Default::default()
20280        });
20281        minimap.update_minimap_configuration(minimap_settings, cx);
20282        cx.new(|_| minimap)
20283    }
20284
20285    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20286        let current_line_highlight = minimap_settings
20287            .current_line_highlight
20288            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20289        self.set_current_line_highlight(Some(current_line_highlight));
20290    }
20291
20292    pub fn minimap(&self) -> Option<&Entity<Self>> {
20293        self.minimap
20294            .as_ref()
20295            .filter(|_| self.minimap_visibility.visible())
20296    }
20297
20298    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20299        let mut wrap_guides = smallvec![];
20300
20301        if self.show_wrap_guides == Some(false) {
20302            return wrap_guides;
20303        }
20304
20305        let settings = self.buffer.read(cx).language_settings(cx);
20306        if settings.show_wrap_guides {
20307            match self.soft_wrap_mode(cx) {
20308                SoftWrap::Column(soft_wrap) => {
20309                    wrap_guides.push((soft_wrap as usize, true));
20310                }
20311                SoftWrap::Bounded(soft_wrap) => {
20312                    wrap_guides.push((soft_wrap as usize, true));
20313                }
20314                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20315            }
20316            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20317        }
20318
20319        wrap_guides
20320    }
20321
20322    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20323        let settings = self.buffer.read(cx).language_settings(cx);
20324        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20325        match mode {
20326            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20327                SoftWrap::None
20328            }
20329            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20330            language_settings::SoftWrap::PreferredLineLength => {
20331                SoftWrap::Column(settings.preferred_line_length)
20332            }
20333            language_settings::SoftWrap::Bounded => {
20334                SoftWrap::Bounded(settings.preferred_line_length)
20335            }
20336        }
20337    }
20338
20339    pub fn set_soft_wrap_mode(
20340        &mut self,
20341        mode: language_settings::SoftWrap,
20342
20343        cx: &mut Context<Self>,
20344    ) {
20345        self.soft_wrap_mode_override = Some(mode);
20346        cx.notify();
20347    }
20348
20349    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20350        self.hard_wrap = hard_wrap;
20351        cx.notify();
20352    }
20353
20354    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20355        self.text_style_refinement = Some(style);
20356    }
20357
20358    /// called by the Element so we know what style we were most recently rendered with.
20359    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20360        // We intentionally do not inform the display map about the minimap style
20361        // so that wrapping is not recalculated and stays consistent for the editor
20362        // and its linked minimap.
20363        if !self.mode.is_minimap() {
20364            let font = style.text.font();
20365            let font_size = style.text.font_size.to_pixels(window.rem_size());
20366            let display_map = self
20367                .placeholder_display_map
20368                .as_ref()
20369                .filter(|_| self.is_empty(cx))
20370                .unwrap_or(&self.display_map);
20371
20372            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20373        }
20374        self.style = Some(style);
20375    }
20376
20377    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20378        if self.style.is_none() {
20379            self.style = Some(self.create_style(cx));
20380        }
20381        self.style.as_ref().unwrap()
20382    }
20383
20384    // Called by the element. This method is not designed to be called outside of the editor
20385    // element's layout code because it does not notify when rewrapping is computed synchronously.
20386    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20387        if self.is_empty(cx) {
20388            self.placeholder_display_map
20389                .as_ref()
20390                .map_or(false, |display_map| {
20391                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20392                })
20393        } else {
20394            self.display_map
20395                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20396        }
20397    }
20398
20399    pub fn set_soft_wrap(&mut self) {
20400        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20401    }
20402
20403    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20404        if self.soft_wrap_mode_override.is_some() {
20405            self.soft_wrap_mode_override.take();
20406        } else {
20407            let soft_wrap = match self.soft_wrap_mode(cx) {
20408                SoftWrap::GitDiff => return,
20409                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20410                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20411                    language_settings::SoftWrap::None
20412                }
20413            };
20414            self.soft_wrap_mode_override = Some(soft_wrap);
20415        }
20416        cx.notify();
20417    }
20418
20419    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20420        let Some(workspace) = self.workspace() else {
20421            return;
20422        };
20423        let fs = workspace.read(cx).app_state().fs.clone();
20424        let current_show = TabBarSettings::get_global(cx).show;
20425        update_settings_file(fs, cx, move |setting, _| {
20426            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20427        });
20428    }
20429
20430    pub fn toggle_indent_guides(
20431        &mut self,
20432        _: &ToggleIndentGuides,
20433        _: &mut Window,
20434        cx: &mut Context<Self>,
20435    ) {
20436        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20437            self.buffer
20438                .read(cx)
20439                .language_settings(cx)
20440                .indent_guides
20441                .enabled
20442        });
20443        self.show_indent_guides = Some(!currently_enabled);
20444        cx.notify();
20445    }
20446
20447    fn should_show_indent_guides(&self) -> Option<bool> {
20448        self.show_indent_guides
20449    }
20450
20451    pub fn disable_indent_guides_for_buffer(
20452        &mut self,
20453        buffer_id: BufferId,
20454        cx: &mut Context<Self>,
20455    ) {
20456        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20457        cx.notify();
20458    }
20459
20460    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20461        self.buffers_with_disabled_indent_guides
20462            .contains(&buffer_id)
20463    }
20464
20465    pub fn toggle_line_numbers(
20466        &mut self,
20467        _: &ToggleLineNumbers,
20468        _: &mut Window,
20469        cx: &mut Context<Self>,
20470    ) {
20471        let mut editor_settings = EditorSettings::get_global(cx).clone();
20472        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20473        EditorSettings::override_global(editor_settings, cx);
20474    }
20475
20476    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20477        if let Some(show_line_numbers) = self.show_line_numbers {
20478            return show_line_numbers;
20479        }
20480        EditorSettings::get_global(cx).gutter.line_numbers
20481    }
20482
20483    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
20484        match (
20485            self.use_relative_line_numbers,
20486            EditorSettings::get_global(cx).relative_line_numbers,
20487        ) {
20488            (None, setting) => setting,
20489            (Some(false), _) => RelativeLineNumbers::Disabled,
20490            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20491            (Some(true), _) => RelativeLineNumbers::Enabled,
20492        }
20493    }
20494
20495    pub fn toggle_relative_line_numbers(
20496        &mut self,
20497        _: &ToggleRelativeLineNumbers,
20498        _: &mut Window,
20499        cx: &mut Context<Self>,
20500    ) {
20501        let is_relative = self.relative_line_numbers(cx);
20502        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20503    }
20504
20505    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20506        self.use_relative_line_numbers = is_relative;
20507        cx.notify();
20508    }
20509
20510    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20511        self.show_gutter = show_gutter;
20512        cx.notify();
20513    }
20514
20515    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20516        self.show_scrollbars = ScrollbarAxes {
20517            horizontal: show,
20518            vertical: show,
20519        };
20520        cx.notify();
20521    }
20522
20523    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20524        self.show_scrollbars.vertical = show;
20525        cx.notify();
20526    }
20527
20528    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20529        self.show_scrollbars.horizontal = show;
20530        cx.notify();
20531    }
20532
20533    pub fn set_minimap_visibility(
20534        &mut self,
20535        minimap_visibility: MinimapVisibility,
20536        window: &mut Window,
20537        cx: &mut Context<Self>,
20538    ) {
20539        if self.minimap_visibility != minimap_visibility {
20540            if minimap_visibility.visible() && self.minimap.is_none() {
20541                let minimap_settings = EditorSettings::get_global(cx).minimap;
20542                self.minimap =
20543                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20544            }
20545            self.minimap_visibility = minimap_visibility;
20546            cx.notify();
20547        }
20548    }
20549
20550    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20551        self.set_show_scrollbars(false, cx);
20552        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20553    }
20554
20555    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20556        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20557    }
20558
20559    /// Normally the text in full mode and auto height editors is padded on the
20560    /// left side by roughly half a character width for improved hit testing.
20561    ///
20562    /// Use this method to disable this for cases where this is not wanted (e.g.
20563    /// if you want to align the editor text with some other text above or below)
20564    /// or if you want to add this padding to single-line editors.
20565    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20566        self.offset_content = offset_content;
20567        cx.notify();
20568    }
20569
20570    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20571        self.show_line_numbers = Some(show_line_numbers);
20572        cx.notify();
20573    }
20574
20575    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20576        self.disable_expand_excerpt_buttons = true;
20577        cx.notify();
20578    }
20579
20580    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20581        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20582        cx.notify();
20583    }
20584
20585    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20586        self.show_code_actions = Some(show_code_actions);
20587        cx.notify();
20588    }
20589
20590    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20591        self.show_runnables = Some(show_runnables);
20592        cx.notify();
20593    }
20594
20595    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20596        self.show_breakpoints = Some(show_breakpoints);
20597        cx.notify();
20598    }
20599
20600    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20601        if self.display_map.read(cx).masked != masked {
20602            self.display_map.update(cx, |map, _| map.masked = masked);
20603        }
20604        cx.notify()
20605    }
20606
20607    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20608        self.show_wrap_guides = Some(show_wrap_guides);
20609        cx.notify();
20610    }
20611
20612    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20613        self.show_indent_guides = Some(show_indent_guides);
20614        cx.notify();
20615    }
20616
20617    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20618        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20619            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20620                && let Some(dir) = file.abs_path(cx).parent()
20621            {
20622                return Some(dir.to_owned());
20623            }
20624        }
20625
20626        None
20627    }
20628
20629    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20630        self.active_excerpt(cx)?
20631            .1
20632            .read(cx)
20633            .file()
20634            .and_then(|f| f.as_local())
20635    }
20636
20637    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20638        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20639            let buffer = buffer.read(cx);
20640            if let Some(project_path) = buffer.project_path(cx) {
20641                let project = self.project()?.read(cx);
20642                project.absolute_path(&project_path, cx)
20643            } else {
20644                buffer
20645                    .file()
20646                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20647            }
20648        })
20649    }
20650
20651    pub fn reveal_in_finder(
20652        &mut self,
20653        _: &RevealInFileManager,
20654        _window: &mut Window,
20655        cx: &mut Context<Self>,
20656    ) {
20657        if let Some(target) = self.target_file(cx) {
20658            cx.reveal_path(&target.abs_path(cx));
20659        }
20660    }
20661
20662    pub fn copy_path(
20663        &mut self,
20664        _: &zed_actions::workspace::CopyPath,
20665        _window: &mut Window,
20666        cx: &mut Context<Self>,
20667    ) {
20668        if let Some(path) = self.target_file_abs_path(cx)
20669            && let Some(path) = path.to_str()
20670        {
20671            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20672        } else {
20673            cx.propagate();
20674        }
20675    }
20676
20677    pub fn copy_relative_path(
20678        &mut self,
20679        _: &zed_actions::workspace::CopyRelativePath,
20680        _window: &mut Window,
20681        cx: &mut Context<Self>,
20682    ) {
20683        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20684            let project = self.project()?.read(cx);
20685            let path = buffer.read(cx).file()?.path();
20686            let path = path.display(project.path_style(cx));
20687            Some(path)
20688        }) {
20689            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20690        } else {
20691            cx.propagate();
20692        }
20693    }
20694
20695    /// Returns the project path for the editor's buffer, if any buffer is
20696    /// opened in the editor.
20697    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20698        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20699            buffer.read(cx).project_path(cx)
20700        } else {
20701            None
20702        }
20703    }
20704
20705    // Returns true if the editor handled a go-to-line request
20706    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20707        maybe!({
20708            let breakpoint_store = self.breakpoint_store.as_ref()?;
20709
20710            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20711            else {
20712                self.clear_row_highlights::<ActiveDebugLine>();
20713                return None;
20714            };
20715
20716            let position = active_stack_frame.position;
20717            let buffer_id = position.buffer_id?;
20718            let snapshot = self
20719                .project
20720                .as_ref()?
20721                .read(cx)
20722                .buffer_for_id(buffer_id, cx)?
20723                .read(cx)
20724                .snapshot();
20725
20726            let mut handled = false;
20727            for (id, ExcerptRange { context, .. }) in
20728                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20729            {
20730                if context.start.cmp(&position, &snapshot).is_ge()
20731                    || context.end.cmp(&position, &snapshot).is_lt()
20732                {
20733                    continue;
20734                }
20735                let snapshot = self.buffer.read(cx).snapshot(cx);
20736                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20737
20738                handled = true;
20739                self.clear_row_highlights::<ActiveDebugLine>();
20740
20741                self.go_to_line::<ActiveDebugLine>(
20742                    multibuffer_anchor,
20743                    Some(cx.theme().colors().editor_debugger_active_line_background),
20744                    window,
20745                    cx,
20746                );
20747
20748                cx.notify();
20749            }
20750
20751            handled.then_some(())
20752        })
20753        .is_some()
20754    }
20755
20756    pub fn copy_file_name_without_extension(
20757        &mut self,
20758        _: &CopyFileNameWithoutExtension,
20759        _: &mut Window,
20760        cx: &mut Context<Self>,
20761    ) {
20762        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20763            let file = buffer.read(cx).file()?;
20764            file.path().file_stem()
20765        }) {
20766            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20767        }
20768    }
20769
20770    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20771        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20772            let file = buffer.read(cx).file()?;
20773            Some(file.file_name(cx))
20774        }) {
20775            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20776        }
20777    }
20778
20779    pub fn toggle_git_blame(
20780        &mut self,
20781        _: &::git::Blame,
20782        window: &mut Window,
20783        cx: &mut Context<Self>,
20784    ) {
20785        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20786
20787        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20788            self.start_git_blame(true, window, cx);
20789        }
20790
20791        cx.notify();
20792    }
20793
20794    pub fn toggle_git_blame_inline(
20795        &mut self,
20796        _: &ToggleGitBlameInline,
20797        window: &mut Window,
20798        cx: &mut Context<Self>,
20799    ) {
20800        self.toggle_git_blame_inline_internal(true, window, cx);
20801        cx.notify();
20802    }
20803
20804    pub fn open_git_blame_commit(
20805        &mut self,
20806        _: &OpenGitBlameCommit,
20807        window: &mut Window,
20808        cx: &mut Context<Self>,
20809    ) {
20810        self.open_git_blame_commit_internal(window, cx);
20811    }
20812
20813    fn open_git_blame_commit_internal(
20814        &mut self,
20815        window: &mut Window,
20816        cx: &mut Context<Self>,
20817    ) -> Option<()> {
20818        let blame = self.blame.as_ref()?;
20819        let snapshot = self.snapshot(window, cx);
20820        let cursor = self
20821            .selections
20822            .newest::<Point>(&snapshot.display_snapshot)
20823            .head();
20824        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20825        let (_, blame_entry) = blame
20826            .update(cx, |blame, cx| {
20827                blame
20828                    .blame_for_rows(
20829                        &[RowInfo {
20830                            buffer_id: Some(buffer.remote_id()),
20831                            buffer_row: Some(point.row),
20832                            ..Default::default()
20833                        }],
20834                        cx,
20835                    )
20836                    .next()
20837            })
20838            .flatten()?;
20839        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20840        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20841        let workspace = self.workspace()?.downgrade();
20842        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20843        None
20844    }
20845
20846    pub fn git_blame_inline_enabled(&self) -> bool {
20847        self.git_blame_inline_enabled
20848    }
20849
20850    pub fn toggle_selection_menu(
20851        &mut self,
20852        _: &ToggleSelectionMenu,
20853        _: &mut Window,
20854        cx: &mut Context<Self>,
20855    ) {
20856        self.show_selection_menu = self
20857            .show_selection_menu
20858            .map(|show_selections_menu| !show_selections_menu)
20859            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20860
20861        cx.notify();
20862    }
20863
20864    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20865        self.show_selection_menu
20866            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20867    }
20868
20869    fn start_git_blame(
20870        &mut self,
20871        user_triggered: bool,
20872        window: &mut Window,
20873        cx: &mut Context<Self>,
20874    ) {
20875        if let Some(project) = self.project() {
20876            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20877                && buffer.read(cx).file().is_none()
20878            {
20879                return;
20880            }
20881
20882            let focused = self.focus_handle(cx).contains_focused(window, cx);
20883
20884            let project = project.clone();
20885            let blame = cx
20886                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20887            self.blame_subscription =
20888                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20889            self.blame = Some(blame);
20890        }
20891    }
20892
20893    fn toggle_git_blame_inline_internal(
20894        &mut self,
20895        user_triggered: bool,
20896        window: &mut Window,
20897        cx: &mut Context<Self>,
20898    ) {
20899        if self.git_blame_inline_enabled {
20900            self.git_blame_inline_enabled = false;
20901            self.show_git_blame_inline = false;
20902            self.show_git_blame_inline_delay_task.take();
20903        } else {
20904            self.git_blame_inline_enabled = true;
20905            self.start_git_blame_inline(user_triggered, window, cx);
20906        }
20907
20908        cx.notify();
20909    }
20910
20911    fn start_git_blame_inline(
20912        &mut self,
20913        user_triggered: bool,
20914        window: &mut Window,
20915        cx: &mut Context<Self>,
20916    ) {
20917        self.start_git_blame(user_triggered, window, cx);
20918
20919        if ProjectSettings::get_global(cx)
20920            .git
20921            .inline_blame_delay()
20922            .is_some()
20923        {
20924            self.start_inline_blame_timer(window, cx);
20925        } else {
20926            self.show_git_blame_inline = true
20927        }
20928    }
20929
20930    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20931        self.blame.as_ref()
20932    }
20933
20934    pub fn show_git_blame_gutter(&self) -> bool {
20935        self.show_git_blame_gutter
20936    }
20937
20938    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20939        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20940    }
20941
20942    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20943        self.show_git_blame_inline
20944            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20945            && !self.newest_selection_head_on_empty_line(cx)
20946            && self.has_blame_entries(cx)
20947    }
20948
20949    fn has_blame_entries(&self, cx: &App) -> bool {
20950        self.blame()
20951            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20952    }
20953
20954    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20955        let cursor_anchor = self.selections.newest_anchor().head();
20956
20957        let snapshot = self.buffer.read(cx).snapshot(cx);
20958        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20959
20960        snapshot.line_len(buffer_row) == 0
20961    }
20962
20963    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20964        let buffer_and_selection = maybe!({
20965            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20966            let selection_range = selection.range();
20967
20968            let multi_buffer = self.buffer().read(cx);
20969            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20970            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20971
20972            let (buffer, range, _) = if selection.reversed {
20973                buffer_ranges.first()
20974            } else {
20975                buffer_ranges.last()
20976            }?;
20977
20978            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
20979            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
20980
20981            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
20982                let selection = start_row_in_buffer..end_row_in_buffer;
20983
20984                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
20985            };
20986
20987            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
20988
20989            Some((
20990                multi_buffer.buffer(buffer.remote_id()).unwrap(),
20991                buffer_diff_snapshot.row_to_base_text_row(start_row_in_buffer, buffer)
20992                    ..buffer_diff_snapshot.row_to_base_text_row(end_row_in_buffer, buffer),
20993            ))
20994        });
20995
20996        let Some((buffer, selection)) = buffer_and_selection else {
20997            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20998        };
20999
21000        let Some(project) = self.project() else {
21001            return Task::ready(Err(anyhow!("editor does not have project")));
21002        };
21003
21004        project.update(cx, |project, cx| {
21005            project.get_permalink_to_line(&buffer, selection, cx)
21006        })
21007    }
21008
21009    pub fn copy_permalink_to_line(
21010        &mut self,
21011        _: &CopyPermalinkToLine,
21012        window: &mut Window,
21013        cx: &mut Context<Self>,
21014    ) {
21015        let permalink_task = self.get_permalink_to_line(cx);
21016        let workspace = self.workspace();
21017
21018        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21019            Ok(permalink) => {
21020                cx.update(|_, cx| {
21021                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
21022                })
21023                .ok();
21024            }
21025            Err(err) => {
21026                let message = format!("Failed to copy permalink: {err}");
21027
21028                anyhow::Result::<()>::Err(err).log_err();
21029
21030                if let Some(workspace) = workspace {
21031                    workspace
21032                        .update_in(cx, |workspace, _, cx| {
21033                            struct CopyPermalinkToLine;
21034
21035                            workspace.show_toast(
21036                                Toast::new(
21037                                    NotificationId::unique::<CopyPermalinkToLine>(),
21038                                    message,
21039                                ),
21040                                cx,
21041                            )
21042                        })
21043                        .ok();
21044                }
21045            }
21046        })
21047        .detach();
21048    }
21049
21050    pub fn copy_file_location(
21051        &mut self,
21052        _: &CopyFileLocation,
21053        _: &mut Window,
21054        cx: &mut Context<Self>,
21055    ) {
21056        let selection = self
21057            .selections
21058            .newest::<Point>(&self.display_snapshot(cx))
21059            .start
21060            .row
21061            + 1;
21062        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21063            let project = self.project()?.read(cx);
21064            let file = buffer.read(cx).file()?;
21065            let path = file.path().display(project.path_style(cx));
21066
21067            Some(format!("{path}:{selection}"))
21068        }) {
21069            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
21070        }
21071    }
21072
21073    pub fn open_permalink_to_line(
21074        &mut self,
21075        _: &OpenPermalinkToLine,
21076        window: &mut Window,
21077        cx: &mut Context<Self>,
21078    ) {
21079        let permalink_task = self.get_permalink_to_line(cx);
21080        let workspace = self.workspace();
21081
21082        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21083            Ok(permalink) => {
21084                cx.update(|_, cx| {
21085                    cx.open_url(permalink.as_ref());
21086                })
21087                .ok();
21088            }
21089            Err(err) => {
21090                let message = format!("Failed to open permalink: {err}");
21091
21092                anyhow::Result::<()>::Err(err).log_err();
21093
21094                if let Some(workspace) = workspace {
21095                    workspace
21096                        .update(cx, |workspace, cx| {
21097                            struct OpenPermalinkToLine;
21098
21099                            workspace.show_toast(
21100                                Toast::new(
21101                                    NotificationId::unique::<OpenPermalinkToLine>(),
21102                                    message,
21103                                ),
21104                                cx,
21105                            )
21106                        })
21107                        .ok();
21108                }
21109            }
21110        })
21111        .detach();
21112    }
21113
21114    pub fn insert_uuid_v4(
21115        &mut self,
21116        _: &InsertUuidV4,
21117        window: &mut Window,
21118        cx: &mut Context<Self>,
21119    ) {
21120        self.insert_uuid(UuidVersion::V4, window, cx);
21121    }
21122
21123    pub fn insert_uuid_v7(
21124        &mut self,
21125        _: &InsertUuidV7,
21126        window: &mut Window,
21127        cx: &mut Context<Self>,
21128    ) {
21129        self.insert_uuid(UuidVersion::V7, window, cx);
21130    }
21131
21132    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
21133        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21134        self.transact(window, cx, |this, window, cx| {
21135            let edits = this
21136                .selections
21137                .all::<Point>(&this.display_snapshot(cx))
21138                .into_iter()
21139                .map(|selection| {
21140                    let uuid = match version {
21141                        UuidVersion::V4 => uuid::Uuid::new_v4(),
21142                        UuidVersion::V7 => uuid::Uuid::now_v7(),
21143                    };
21144
21145                    (selection.range(), uuid.to_string())
21146                });
21147            this.edit(edits, cx);
21148            this.refresh_edit_prediction(true, false, window, cx);
21149        });
21150    }
21151
21152    pub fn open_selections_in_multibuffer(
21153        &mut self,
21154        _: &OpenSelectionsInMultibuffer,
21155        window: &mut Window,
21156        cx: &mut Context<Self>,
21157    ) {
21158        let multibuffer = self.buffer.read(cx);
21159
21160        let Some(buffer) = multibuffer.as_singleton() else {
21161            return;
21162        };
21163
21164        let Some(workspace) = self.workspace() else {
21165            return;
21166        };
21167
21168        let title = multibuffer.title(cx).to_string();
21169
21170        let locations = self
21171            .selections
21172            .all_anchors(&self.display_snapshot(cx))
21173            .iter()
21174            .map(|selection| {
21175                (
21176                    buffer.clone(),
21177                    (selection.start.text_anchor..selection.end.text_anchor)
21178                        .to_point(buffer.read(cx)),
21179                )
21180            })
21181            .into_group_map();
21182
21183        cx.spawn_in(window, async move |_, cx| {
21184            workspace.update_in(cx, |workspace, window, cx| {
21185                Self::open_locations_in_multibuffer(
21186                    workspace,
21187                    locations,
21188                    format!("Selections for '{title}'"),
21189                    false,
21190                    false,
21191                    MultibufferSelectionMode::All,
21192                    window,
21193                    cx,
21194                );
21195            })
21196        })
21197        .detach();
21198    }
21199
21200    /// Adds a row highlight for the given range. If a row has multiple highlights, the
21201    /// last highlight added will be used.
21202    ///
21203    /// If the range ends at the beginning of a line, then that line will not be highlighted.
21204    pub fn highlight_rows<T: 'static>(
21205        &mut self,
21206        range: Range<Anchor>,
21207        color: Hsla,
21208        options: RowHighlightOptions,
21209        cx: &mut Context<Self>,
21210    ) {
21211        let snapshot = self.buffer().read(cx).snapshot(cx);
21212        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21213        let ix = row_highlights.binary_search_by(|highlight| {
21214            Ordering::Equal
21215                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
21216                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
21217        });
21218
21219        if let Err(mut ix) = ix {
21220            let index = post_inc(&mut self.highlight_order);
21221
21222            // If this range intersects with the preceding highlight, then merge it with
21223            // the preceding highlight. Otherwise insert a new highlight.
21224            let mut merged = false;
21225            if ix > 0 {
21226                let prev_highlight = &mut row_highlights[ix - 1];
21227                if prev_highlight
21228                    .range
21229                    .end
21230                    .cmp(&range.start, &snapshot)
21231                    .is_ge()
21232                {
21233                    ix -= 1;
21234                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
21235                        prev_highlight.range.end = range.end;
21236                    }
21237                    merged = true;
21238                    prev_highlight.index = index;
21239                    prev_highlight.color = color;
21240                    prev_highlight.options = options;
21241                }
21242            }
21243
21244            if !merged {
21245                row_highlights.insert(
21246                    ix,
21247                    RowHighlight {
21248                        range,
21249                        index,
21250                        color,
21251                        options,
21252                        type_id: TypeId::of::<T>(),
21253                    },
21254                );
21255            }
21256
21257            // If any of the following highlights intersect with this one, merge them.
21258            while let Some(next_highlight) = row_highlights.get(ix + 1) {
21259                let highlight = &row_highlights[ix];
21260                if next_highlight
21261                    .range
21262                    .start
21263                    .cmp(&highlight.range.end, &snapshot)
21264                    .is_le()
21265                {
21266                    if next_highlight
21267                        .range
21268                        .end
21269                        .cmp(&highlight.range.end, &snapshot)
21270                        .is_gt()
21271                    {
21272                        row_highlights[ix].range.end = next_highlight.range.end;
21273                    }
21274                    row_highlights.remove(ix + 1);
21275                } else {
21276                    break;
21277                }
21278            }
21279        }
21280    }
21281
21282    /// Remove any highlighted row ranges of the given type that intersect the
21283    /// given ranges.
21284    pub fn remove_highlighted_rows<T: 'static>(
21285        &mut self,
21286        ranges_to_remove: Vec<Range<Anchor>>,
21287        cx: &mut Context<Self>,
21288    ) {
21289        let snapshot = self.buffer().read(cx).snapshot(cx);
21290        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21291        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21292        row_highlights.retain(|highlight| {
21293            while let Some(range_to_remove) = ranges_to_remove.peek() {
21294                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
21295                    Ordering::Less | Ordering::Equal => {
21296                        ranges_to_remove.next();
21297                    }
21298                    Ordering::Greater => {
21299                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
21300                            Ordering::Less | Ordering::Equal => {
21301                                return false;
21302                            }
21303                            Ordering::Greater => break,
21304                        }
21305                    }
21306                }
21307            }
21308
21309            true
21310        })
21311    }
21312
21313    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
21314    pub fn clear_row_highlights<T: 'static>(&mut self) {
21315        self.highlighted_rows.remove(&TypeId::of::<T>());
21316    }
21317
21318    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
21319    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
21320        self.highlighted_rows
21321            .get(&TypeId::of::<T>())
21322            .map_or(&[] as &[_], |vec| vec.as_slice())
21323            .iter()
21324            .map(|highlight| (highlight.range.clone(), highlight.color))
21325    }
21326
21327    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
21328    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
21329    /// Allows to ignore certain kinds of highlights.
21330    pub fn highlighted_display_rows(
21331        &self,
21332        window: &mut Window,
21333        cx: &mut App,
21334    ) -> BTreeMap<DisplayRow, LineHighlight> {
21335        let snapshot = self.snapshot(window, cx);
21336        let mut used_highlight_orders = HashMap::default();
21337        self.highlighted_rows
21338            .iter()
21339            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
21340            .fold(
21341                BTreeMap::<DisplayRow, LineHighlight>::new(),
21342                |mut unique_rows, highlight| {
21343                    let start = highlight.range.start.to_display_point(&snapshot);
21344                    let end = highlight.range.end.to_display_point(&snapshot);
21345                    let start_row = start.row().0;
21346                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
21347                    {
21348                        end.row().0.saturating_sub(1)
21349                    } else {
21350                        end.row().0
21351                    };
21352                    for row in start_row..=end_row {
21353                        let used_index =
21354                            used_highlight_orders.entry(row).or_insert(highlight.index);
21355                        if highlight.index >= *used_index {
21356                            *used_index = highlight.index;
21357                            unique_rows.insert(
21358                                DisplayRow(row),
21359                                LineHighlight {
21360                                    include_gutter: highlight.options.include_gutter,
21361                                    border: None,
21362                                    background: highlight.color.into(),
21363                                    type_id: Some(highlight.type_id),
21364                                },
21365                            );
21366                        }
21367                    }
21368                    unique_rows
21369                },
21370            )
21371    }
21372
21373    pub fn highlighted_display_row_for_autoscroll(
21374        &self,
21375        snapshot: &DisplaySnapshot,
21376    ) -> Option<DisplayRow> {
21377        self.highlighted_rows
21378            .values()
21379            .flat_map(|highlighted_rows| highlighted_rows.iter())
21380            .filter_map(|highlight| {
21381                if highlight.options.autoscroll {
21382                    Some(highlight.range.start.to_display_point(snapshot).row())
21383                } else {
21384                    None
21385                }
21386            })
21387            .min()
21388    }
21389
21390    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21391        self.highlight_background::<SearchWithinRange>(
21392            ranges,
21393            |_, colors| colors.colors().editor_document_highlight_read_background,
21394            cx,
21395        )
21396    }
21397
21398    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21399        self.breadcrumb_header = Some(new_header);
21400    }
21401
21402    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21403        self.clear_background_highlights::<SearchWithinRange>(cx);
21404    }
21405
21406    pub fn highlight_background<T: 'static>(
21407        &mut self,
21408        ranges: &[Range<Anchor>],
21409        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21410        cx: &mut Context<Self>,
21411    ) {
21412        self.background_highlights.insert(
21413            HighlightKey::Type(TypeId::of::<T>()),
21414            (Arc::new(color_fetcher), Arc::from(ranges)),
21415        );
21416        self.scrollbar_marker_state.dirty = true;
21417        cx.notify();
21418    }
21419
21420    pub fn highlight_background_key<T: 'static>(
21421        &mut self,
21422        key: usize,
21423        ranges: &[Range<Anchor>],
21424        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21425        cx: &mut Context<Self>,
21426    ) {
21427        self.background_highlights.insert(
21428            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21429            (Arc::new(color_fetcher), Arc::from(ranges)),
21430        );
21431        self.scrollbar_marker_state.dirty = true;
21432        cx.notify();
21433    }
21434
21435    pub fn clear_background_highlights<T: 'static>(
21436        &mut self,
21437        cx: &mut Context<Self>,
21438    ) -> Option<BackgroundHighlight> {
21439        let text_highlights = self
21440            .background_highlights
21441            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21442        if !text_highlights.1.is_empty() {
21443            self.scrollbar_marker_state.dirty = true;
21444            cx.notify();
21445        }
21446        Some(text_highlights)
21447    }
21448
21449    pub fn highlight_gutter<T: 'static>(
21450        &mut self,
21451        ranges: impl Into<Vec<Range<Anchor>>>,
21452        color_fetcher: fn(&App) -> Hsla,
21453        cx: &mut Context<Self>,
21454    ) {
21455        self.gutter_highlights
21456            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21457        cx.notify();
21458    }
21459
21460    pub fn clear_gutter_highlights<T: 'static>(
21461        &mut self,
21462        cx: &mut Context<Self>,
21463    ) -> Option<GutterHighlight> {
21464        cx.notify();
21465        self.gutter_highlights.remove(&TypeId::of::<T>())
21466    }
21467
21468    pub fn insert_gutter_highlight<T: 'static>(
21469        &mut self,
21470        range: Range<Anchor>,
21471        color_fetcher: fn(&App) -> Hsla,
21472        cx: &mut Context<Self>,
21473    ) {
21474        let snapshot = self.buffer().read(cx).snapshot(cx);
21475        let mut highlights = self
21476            .gutter_highlights
21477            .remove(&TypeId::of::<T>())
21478            .map(|(_, highlights)| highlights)
21479            .unwrap_or_default();
21480        let ix = highlights.binary_search_by(|highlight| {
21481            Ordering::Equal
21482                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21483                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21484        });
21485        if let Err(ix) = ix {
21486            highlights.insert(ix, range);
21487        }
21488        self.gutter_highlights
21489            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21490    }
21491
21492    pub fn remove_gutter_highlights<T: 'static>(
21493        &mut self,
21494        ranges_to_remove: Vec<Range<Anchor>>,
21495        cx: &mut Context<Self>,
21496    ) {
21497        let snapshot = self.buffer().read(cx).snapshot(cx);
21498        let Some((color_fetcher, mut gutter_highlights)) =
21499            self.gutter_highlights.remove(&TypeId::of::<T>())
21500        else {
21501            return;
21502        };
21503        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21504        gutter_highlights.retain(|highlight| {
21505            while let Some(range_to_remove) = ranges_to_remove.peek() {
21506                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21507                    Ordering::Less | Ordering::Equal => {
21508                        ranges_to_remove.next();
21509                    }
21510                    Ordering::Greater => {
21511                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21512                            Ordering::Less | Ordering::Equal => {
21513                                return false;
21514                            }
21515                            Ordering::Greater => break,
21516                        }
21517                    }
21518                }
21519            }
21520
21521            true
21522        });
21523        self.gutter_highlights
21524            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21525    }
21526
21527    #[cfg(feature = "test-support")]
21528    pub fn all_text_highlights(
21529        &self,
21530        window: &mut Window,
21531        cx: &mut Context<Self>,
21532    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21533        let snapshot = self.snapshot(window, cx);
21534        self.display_map.update(cx, |display_map, _| {
21535            display_map
21536                .all_text_highlights()
21537                .map(|highlight| {
21538                    let (style, ranges) = highlight.as_ref();
21539                    (
21540                        *style,
21541                        ranges
21542                            .iter()
21543                            .map(|range| range.clone().to_display_points(&snapshot))
21544                            .collect(),
21545                    )
21546                })
21547                .collect()
21548        })
21549    }
21550
21551    #[cfg(feature = "test-support")]
21552    pub fn all_text_background_highlights(
21553        &self,
21554        window: &mut Window,
21555        cx: &mut Context<Self>,
21556    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21557        let snapshot = self.snapshot(window, cx);
21558        let buffer = &snapshot.buffer_snapshot();
21559        let start = buffer.anchor_before(MultiBufferOffset(0));
21560        let end = buffer.anchor_after(buffer.len());
21561        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21562    }
21563
21564    #[cfg(any(test, feature = "test-support"))]
21565    pub fn sorted_background_highlights_in_range(
21566        &self,
21567        search_range: Range<Anchor>,
21568        display_snapshot: &DisplaySnapshot,
21569        theme: &Theme,
21570    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21571        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21572        res.sort_by(|a, b| {
21573            a.0.start
21574                .cmp(&b.0.start)
21575                .then_with(|| a.0.end.cmp(&b.0.end))
21576                .then_with(|| a.1.cmp(&b.1))
21577        });
21578        res
21579    }
21580
21581    #[cfg(feature = "test-support")]
21582    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21583        let snapshot = self.buffer().read(cx).snapshot(cx);
21584
21585        let highlights = self
21586            .background_highlights
21587            .get(&HighlightKey::Type(TypeId::of::<
21588                items::BufferSearchHighlights,
21589            >()));
21590
21591        if let Some((_color, ranges)) = highlights {
21592            ranges
21593                .iter()
21594                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21595                .collect_vec()
21596        } else {
21597            vec![]
21598        }
21599    }
21600
21601    fn document_highlights_for_position<'a>(
21602        &'a self,
21603        position: Anchor,
21604        buffer: &'a MultiBufferSnapshot,
21605    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21606        let read_highlights = self
21607            .background_highlights
21608            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21609            .map(|h| &h.1);
21610        let write_highlights = self
21611            .background_highlights
21612            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21613            .map(|h| &h.1);
21614        let left_position = position.bias_left(buffer);
21615        let right_position = position.bias_right(buffer);
21616        read_highlights
21617            .into_iter()
21618            .chain(write_highlights)
21619            .flat_map(move |ranges| {
21620                let start_ix = match ranges.binary_search_by(|probe| {
21621                    let cmp = probe.end.cmp(&left_position, buffer);
21622                    if cmp.is_ge() {
21623                        Ordering::Greater
21624                    } else {
21625                        Ordering::Less
21626                    }
21627                }) {
21628                    Ok(i) | Err(i) => i,
21629                };
21630
21631                ranges[start_ix..]
21632                    .iter()
21633                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21634            })
21635    }
21636
21637    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21638        self.background_highlights
21639            .get(&HighlightKey::Type(TypeId::of::<T>()))
21640            .is_some_and(|(_, highlights)| !highlights.is_empty())
21641    }
21642
21643    /// Returns all background highlights for a given range.
21644    ///
21645    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21646    pub fn background_highlights_in_range(
21647        &self,
21648        search_range: Range<Anchor>,
21649        display_snapshot: &DisplaySnapshot,
21650        theme: &Theme,
21651    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21652        let mut results = Vec::new();
21653        for (color_fetcher, ranges) in self.background_highlights.values() {
21654            let start_ix = match ranges.binary_search_by(|probe| {
21655                let cmp = probe
21656                    .end
21657                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21658                if cmp.is_gt() {
21659                    Ordering::Greater
21660                } else {
21661                    Ordering::Less
21662                }
21663            }) {
21664                Ok(i) | Err(i) => i,
21665            };
21666            for (index, range) in ranges[start_ix..].iter().enumerate() {
21667                if range
21668                    .start
21669                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21670                    .is_ge()
21671                {
21672                    break;
21673                }
21674
21675                let color = color_fetcher(&(start_ix + index), theme);
21676                let start = range.start.to_display_point(display_snapshot);
21677                let end = range.end.to_display_point(display_snapshot);
21678                results.push((start..end, color))
21679            }
21680        }
21681        results
21682    }
21683
21684    pub fn gutter_highlights_in_range(
21685        &self,
21686        search_range: Range<Anchor>,
21687        display_snapshot: &DisplaySnapshot,
21688        cx: &App,
21689    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21690        let mut results = Vec::new();
21691        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21692            let color = color_fetcher(cx);
21693            let start_ix = match ranges.binary_search_by(|probe| {
21694                let cmp = probe
21695                    .end
21696                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21697                if cmp.is_gt() {
21698                    Ordering::Greater
21699                } else {
21700                    Ordering::Less
21701                }
21702            }) {
21703                Ok(i) | Err(i) => i,
21704            };
21705            for range in &ranges[start_ix..] {
21706                if range
21707                    .start
21708                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21709                    .is_ge()
21710                {
21711                    break;
21712                }
21713
21714                let start = range.start.to_display_point(display_snapshot);
21715                let end = range.end.to_display_point(display_snapshot);
21716                results.push((start..end, color))
21717            }
21718        }
21719        results
21720    }
21721
21722    /// Get the text ranges corresponding to the redaction query
21723    pub fn redacted_ranges(
21724        &self,
21725        search_range: Range<Anchor>,
21726        display_snapshot: &DisplaySnapshot,
21727        cx: &App,
21728    ) -> Vec<Range<DisplayPoint>> {
21729        display_snapshot
21730            .buffer_snapshot()
21731            .redacted_ranges(search_range, |file| {
21732                if let Some(file) = file {
21733                    file.is_private()
21734                        && EditorSettings::get(
21735                            Some(SettingsLocation {
21736                                worktree_id: file.worktree_id(cx),
21737                                path: file.path().as_ref(),
21738                            }),
21739                            cx,
21740                        )
21741                        .redact_private_values
21742                } else {
21743                    false
21744                }
21745            })
21746            .map(|range| {
21747                range.start.to_display_point(display_snapshot)
21748                    ..range.end.to_display_point(display_snapshot)
21749            })
21750            .collect()
21751    }
21752
21753    pub fn highlight_text_key<T: 'static>(
21754        &mut self,
21755        key: usize,
21756        ranges: Vec<Range<Anchor>>,
21757        style: HighlightStyle,
21758        merge: bool,
21759        cx: &mut Context<Self>,
21760    ) {
21761        self.display_map.update(cx, |map, cx| {
21762            map.highlight_text(
21763                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21764                ranges,
21765                style,
21766                merge,
21767                cx,
21768            );
21769        });
21770        cx.notify();
21771    }
21772
21773    pub fn highlight_text<T: 'static>(
21774        &mut self,
21775        ranges: Vec<Range<Anchor>>,
21776        style: HighlightStyle,
21777        cx: &mut Context<Self>,
21778    ) {
21779        self.display_map.update(cx, |map, cx| {
21780            map.highlight_text(
21781                HighlightKey::Type(TypeId::of::<T>()),
21782                ranges,
21783                style,
21784                false,
21785                cx,
21786            )
21787        });
21788        cx.notify();
21789    }
21790
21791    pub fn text_highlights<'a, T: 'static>(
21792        &'a self,
21793        cx: &'a App,
21794    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21795        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21796    }
21797
21798    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21799        let cleared = self
21800            .display_map
21801            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21802        if cleared {
21803            cx.notify();
21804        }
21805    }
21806
21807    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21808        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21809            && self.focus_handle.is_focused(window)
21810    }
21811
21812    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21813        self.show_cursor_when_unfocused = is_enabled;
21814        cx.notify();
21815    }
21816
21817    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21818        cx.notify();
21819    }
21820
21821    fn on_debug_session_event(
21822        &mut self,
21823        _session: Entity<Session>,
21824        event: &SessionEvent,
21825        cx: &mut Context<Self>,
21826    ) {
21827        if let SessionEvent::InvalidateInlineValue = event {
21828            self.refresh_inline_values(cx);
21829        }
21830    }
21831
21832    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21833        let Some(project) = self.project.clone() else {
21834            return;
21835        };
21836
21837        if !self.inline_value_cache.enabled {
21838            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21839            self.splice_inlays(&inlays, Vec::new(), cx);
21840            return;
21841        }
21842
21843        let current_execution_position = self
21844            .highlighted_rows
21845            .get(&TypeId::of::<ActiveDebugLine>())
21846            .and_then(|lines| lines.last().map(|line| line.range.end));
21847
21848        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21849            let inline_values = editor
21850                .update(cx, |editor, cx| {
21851                    let Some(current_execution_position) = current_execution_position else {
21852                        return Some(Task::ready(Ok(Vec::new())));
21853                    };
21854
21855                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21856                        let snapshot = buffer.snapshot(cx);
21857
21858                        let excerpt = snapshot.excerpt_containing(
21859                            current_execution_position..current_execution_position,
21860                        )?;
21861
21862                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21863                    })?;
21864
21865                    let range =
21866                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21867
21868                    project.inline_values(buffer, range, cx)
21869                })
21870                .ok()
21871                .flatten()?
21872                .await
21873                .context("refreshing debugger inlays")
21874                .log_err()?;
21875
21876            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21877
21878            for (buffer_id, inline_value) in inline_values
21879                .into_iter()
21880                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21881            {
21882                buffer_inline_values
21883                    .entry(buffer_id)
21884                    .or_default()
21885                    .push(inline_value);
21886            }
21887
21888            editor
21889                .update(cx, |editor, cx| {
21890                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21891                    let mut new_inlays = Vec::default();
21892
21893                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21894                        let buffer_id = buffer_snapshot.remote_id();
21895                        buffer_inline_values
21896                            .get(&buffer_id)
21897                            .into_iter()
21898                            .flatten()
21899                            .for_each(|hint| {
21900                                let inlay = Inlay::debugger(
21901                                    post_inc(&mut editor.next_inlay_id),
21902                                    Anchor::in_buffer(excerpt_id, hint.position),
21903                                    hint.text(),
21904                                );
21905                                if !inlay.text().chars().contains(&'\n') {
21906                                    new_inlays.push(inlay);
21907                                }
21908                            });
21909                    }
21910
21911                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21912                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21913
21914                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21915                })
21916                .ok()?;
21917            Some(())
21918        });
21919    }
21920
21921    fn on_buffer_event(
21922        &mut self,
21923        multibuffer: &Entity<MultiBuffer>,
21924        event: &multi_buffer::Event,
21925        window: &mut Window,
21926        cx: &mut Context<Self>,
21927    ) {
21928        match event {
21929            multi_buffer::Event::Edited { edited_buffer } => {
21930                self.scrollbar_marker_state.dirty = true;
21931                self.active_indent_guides_state.dirty = true;
21932                self.refresh_active_diagnostics(cx);
21933                self.refresh_code_actions(window, cx);
21934                self.refresh_single_line_folds(window, cx);
21935                self.refresh_matching_bracket_highlights(window, cx);
21936                if self.has_active_edit_prediction() {
21937                    self.update_visible_edit_prediction(window, cx);
21938                }
21939
21940                if let Some(buffer) = edited_buffer {
21941                    if buffer.read(cx).file().is_none() {
21942                        cx.emit(EditorEvent::TitleChanged);
21943                    }
21944
21945                    if self.project.is_some() {
21946                        let buffer_id = buffer.read(cx).remote_id();
21947                        self.register_buffer(buffer_id, cx);
21948                        self.update_lsp_data(Some(buffer_id), window, cx);
21949                        self.refresh_inlay_hints(
21950                            InlayHintRefreshReason::BufferEdited(buffer_id),
21951                            cx,
21952                        );
21953                    }
21954                }
21955
21956                cx.emit(EditorEvent::BufferEdited);
21957                cx.emit(SearchEvent::MatchesInvalidated);
21958
21959                let Some(project) = &self.project else { return };
21960                let (telemetry, is_via_ssh) = {
21961                    let project = project.read(cx);
21962                    let telemetry = project.client().telemetry().clone();
21963                    let is_via_ssh = project.is_via_remote_server();
21964                    (telemetry, is_via_ssh)
21965                };
21966                telemetry.log_edit_event("editor", is_via_ssh);
21967            }
21968            multi_buffer::Event::ExcerptsAdded {
21969                buffer,
21970                predecessor,
21971                excerpts,
21972            } => {
21973                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21974                let buffer_id = buffer.read(cx).remote_id();
21975                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21976                    && let Some(project) = &self.project
21977                {
21978                    update_uncommitted_diff_for_buffer(
21979                        cx.entity(),
21980                        project,
21981                        [buffer.clone()],
21982                        self.buffer.clone(),
21983                        cx,
21984                    )
21985                    .detach();
21986                }
21987                self.update_lsp_data(Some(buffer_id), window, cx);
21988                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21989                self.colorize_brackets(false, cx);
21990                cx.emit(EditorEvent::ExcerptsAdded {
21991                    buffer: buffer.clone(),
21992                    predecessor: *predecessor,
21993                    excerpts: excerpts.clone(),
21994                });
21995            }
21996            multi_buffer::Event::ExcerptsRemoved {
21997                ids,
21998                removed_buffer_ids,
21999            } => {
22000                if let Some(inlay_hints) = &mut self.inlay_hints {
22001                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
22002                }
22003                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
22004                for buffer_id in removed_buffer_ids {
22005                    self.registered_buffers.remove(buffer_id);
22006                }
22007                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22008                cx.emit(EditorEvent::ExcerptsRemoved {
22009                    ids: ids.clone(),
22010                    removed_buffer_ids: removed_buffer_ids.clone(),
22011                });
22012            }
22013            multi_buffer::Event::ExcerptsEdited {
22014                excerpt_ids,
22015                buffer_ids,
22016            } => {
22017                self.display_map.update(cx, |map, cx| {
22018                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
22019                });
22020                cx.emit(EditorEvent::ExcerptsEdited {
22021                    ids: excerpt_ids.clone(),
22022                });
22023            }
22024            multi_buffer::Event::ExcerptsExpanded { ids } => {
22025                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22026                self.refresh_document_highlights(cx);
22027                for id in ids {
22028                    self.fetched_tree_sitter_chunks.remove(id);
22029                }
22030                self.colorize_brackets(false, cx);
22031                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
22032            }
22033            multi_buffer::Event::Reparsed(buffer_id) => {
22034                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22035                self.refresh_selected_text_highlights(true, window, cx);
22036                self.colorize_brackets(true, cx);
22037                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22038
22039                cx.emit(EditorEvent::Reparsed(*buffer_id));
22040            }
22041            multi_buffer::Event::DiffHunksToggled => {
22042                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22043            }
22044            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
22045                if !is_fresh_language {
22046                    self.registered_buffers.remove(&buffer_id);
22047                }
22048                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22049                cx.emit(EditorEvent::Reparsed(*buffer_id));
22050                cx.notify();
22051            }
22052            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
22053            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
22054            multi_buffer::Event::FileHandleChanged
22055            | multi_buffer::Event::Reloaded
22056            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
22057            multi_buffer::Event::DiagnosticsUpdated => {
22058                self.update_diagnostics_state(window, cx);
22059            }
22060            _ => {}
22061        };
22062    }
22063
22064    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
22065        if !self.diagnostics_enabled() {
22066            return;
22067        }
22068        self.refresh_active_diagnostics(cx);
22069        self.refresh_inline_diagnostics(true, window, cx);
22070        self.scrollbar_marker_state.dirty = true;
22071        cx.notify();
22072    }
22073
22074    pub fn start_temporary_diff_override(&mut self) {
22075        self.load_diff_task.take();
22076        self.temporary_diff_override = true;
22077    }
22078
22079    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
22080        self.temporary_diff_override = false;
22081        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
22082        self.buffer.update(cx, |buffer, cx| {
22083            buffer.set_all_diff_hunks_collapsed(cx);
22084        });
22085
22086        if let Some(project) = self.project.clone() {
22087            self.load_diff_task = Some(
22088                update_uncommitted_diff_for_buffer(
22089                    cx.entity(),
22090                    &project,
22091                    self.buffer.read(cx).all_buffers(),
22092                    self.buffer.clone(),
22093                    cx,
22094                )
22095                .shared(),
22096            );
22097        }
22098    }
22099
22100    fn on_display_map_changed(
22101        &mut self,
22102        _: Entity<DisplayMap>,
22103        _: &mut Window,
22104        cx: &mut Context<Self>,
22105    ) {
22106        cx.notify();
22107    }
22108
22109    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
22110        if !self.mode.is_full() {
22111            return None;
22112        }
22113
22114        let theme_settings = theme::ThemeSettings::get_global(cx);
22115        let theme = cx.theme();
22116        let accent_colors = theme.accents().clone();
22117
22118        let accent_overrides = theme_settings
22119            .theme_overrides
22120            .get(theme.name.as_ref())
22121            .map(|theme_style| &theme_style.accents)
22122            .into_iter()
22123            .flatten()
22124            .chain(
22125                theme_settings
22126                    .experimental_theme_overrides
22127                    .as_ref()
22128                    .map(|overrides| &overrides.accents)
22129                    .into_iter()
22130                    .flatten(),
22131            )
22132            .flat_map(|accent| accent.0.clone())
22133            .collect();
22134
22135        Some(AccentData {
22136            colors: accent_colors,
22137            overrides: accent_overrides,
22138        })
22139    }
22140
22141    fn fetch_applicable_language_settings(
22142        &self,
22143        cx: &App,
22144    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
22145        if !self.mode.is_full() {
22146            return HashMap::default();
22147        }
22148
22149        self.buffer().read(cx).all_buffers().into_iter().fold(
22150            HashMap::default(),
22151            |mut acc, buffer| {
22152                let buffer = buffer.read(cx);
22153                let language = buffer.language().map(|language| language.name());
22154                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
22155                    let file = buffer.file();
22156                    v.insert(language_settings(language, file, cx).into_owned());
22157                }
22158                acc
22159            },
22160        )
22161    }
22162
22163    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22164        let new_language_settings = self.fetch_applicable_language_settings(cx);
22165        let language_settings_changed = new_language_settings != self.applicable_language_settings;
22166        self.applicable_language_settings = new_language_settings;
22167
22168        let new_accents = self.fetch_accent_data(cx);
22169        let accents_changed = new_accents != self.accent_data;
22170        self.accent_data = new_accents;
22171
22172        if self.diagnostics_enabled() {
22173            let new_severity = EditorSettings::get_global(cx)
22174                .diagnostics_max_severity
22175                .unwrap_or(DiagnosticSeverity::Hint);
22176            self.set_max_diagnostics_severity(new_severity, cx);
22177        }
22178        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22179        self.update_edit_prediction_settings(cx);
22180        self.refresh_edit_prediction(true, false, window, cx);
22181        self.refresh_inline_values(cx);
22182        self.refresh_inlay_hints(
22183            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
22184                self.selections.newest_anchor().head(),
22185                &self.buffer.read(cx).snapshot(cx),
22186                cx,
22187            )),
22188            cx,
22189        );
22190
22191        let old_cursor_shape = self.cursor_shape;
22192        let old_show_breadcrumbs = self.show_breadcrumbs;
22193
22194        {
22195            let editor_settings = EditorSettings::get_global(cx);
22196            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
22197            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
22198            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
22199            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
22200        }
22201
22202        if old_cursor_shape != self.cursor_shape {
22203            cx.emit(EditorEvent::CursorShapeChanged);
22204        }
22205
22206        if old_show_breadcrumbs != self.show_breadcrumbs {
22207            cx.emit(EditorEvent::BreadcrumbsChanged);
22208        }
22209
22210        let project_settings = ProjectSettings::get_global(cx);
22211        self.buffer_serialization = self
22212            .should_serialize_buffer()
22213            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
22214
22215        if self.mode.is_full() {
22216            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
22217            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
22218            if self.show_inline_diagnostics != show_inline_diagnostics {
22219                self.show_inline_diagnostics = show_inline_diagnostics;
22220                self.refresh_inline_diagnostics(false, window, cx);
22221            }
22222
22223            if self.git_blame_inline_enabled != inline_blame_enabled {
22224                self.toggle_git_blame_inline_internal(false, window, cx);
22225            }
22226
22227            let minimap_settings = EditorSettings::get_global(cx).minimap;
22228            if self.minimap_visibility != MinimapVisibility::Disabled {
22229                if self.minimap_visibility.settings_visibility()
22230                    != minimap_settings.minimap_enabled()
22231                {
22232                    self.set_minimap_visibility(
22233                        MinimapVisibility::for_mode(self.mode(), cx),
22234                        window,
22235                        cx,
22236                    );
22237                } else if let Some(minimap_entity) = self.minimap.as_ref() {
22238                    minimap_entity.update(cx, |minimap_editor, cx| {
22239                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
22240                    })
22241                }
22242            }
22243
22244            if language_settings_changed || accents_changed {
22245                self.colorize_brackets(true, cx);
22246            }
22247
22248            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
22249                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
22250            }) {
22251                if !inlay_splice.is_empty() {
22252                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
22253                }
22254                self.refresh_colors_for_visible_range(None, window, cx);
22255            }
22256        }
22257
22258        cx.notify();
22259    }
22260
22261    pub fn set_searchable(&mut self, searchable: bool) {
22262        self.searchable = searchable;
22263    }
22264
22265    pub fn searchable(&self) -> bool {
22266        self.searchable
22267    }
22268
22269    pub fn open_excerpts_in_split(
22270        &mut self,
22271        _: &OpenExcerptsSplit,
22272        window: &mut Window,
22273        cx: &mut Context<Self>,
22274    ) {
22275        self.open_excerpts_common(None, true, window, cx)
22276    }
22277
22278    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
22279        self.open_excerpts_common(None, false, window, cx)
22280    }
22281
22282    fn open_excerpts_common(
22283        &mut self,
22284        jump_data: Option<JumpData>,
22285        split: bool,
22286        window: &mut Window,
22287        cx: &mut Context<Self>,
22288    ) {
22289        let Some(workspace) = self.workspace() else {
22290            cx.propagate();
22291            return;
22292        };
22293
22294        if self.buffer.read(cx).is_singleton() {
22295            cx.propagate();
22296            return;
22297        }
22298
22299        let mut new_selections_by_buffer = HashMap::default();
22300        match &jump_data {
22301            Some(JumpData::MultiBufferPoint {
22302                excerpt_id,
22303                position,
22304                anchor,
22305                line_offset_from_top,
22306            }) => {
22307                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22308                if let Some(buffer) = multi_buffer_snapshot
22309                    .buffer_id_for_excerpt(*excerpt_id)
22310                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
22311                {
22312                    let buffer_snapshot = buffer.read(cx).snapshot();
22313                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
22314                        language::ToPoint::to_point(anchor, &buffer_snapshot)
22315                    } else {
22316                        buffer_snapshot.clip_point(*position, Bias::Left)
22317                    };
22318                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
22319                    new_selections_by_buffer.insert(
22320                        buffer,
22321                        (
22322                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
22323                            Some(*line_offset_from_top),
22324                        ),
22325                    );
22326                }
22327            }
22328            Some(JumpData::MultiBufferRow {
22329                row,
22330                line_offset_from_top,
22331            }) => {
22332                let point = MultiBufferPoint::new(row.0, 0);
22333                if let Some((buffer, buffer_point, _)) =
22334                    self.buffer.read(cx).point_to_buffer_point(point, cx)
22335                {
22336                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
22337                    new_selections_by_buffer
22338                        .entry(buffer)
22339                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
22340                        .0
22341                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
22342                }
22343            }
22344            None => {
22345                let selections = self
22346                    .selections
22347                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
22348                let multi_buffer = self.buffer.read(cx);
22349                for selection in selections {
22350                    for (snapshot, range, _, anchor) in multi_buffer
22351                        .snapshot(cx)
22352                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
22353                    {
22354                        if let Some(anchor) = anchor {
22355                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
22356                            else {
22357                                continue;
22358                            };
22359                            let offset = text::ToOffset::to_offset(
22360                                &anchor.text_anchor,
22361                                &buffer_handle.read(cx).snapshot(),
22362                            );
22363                            let range = BufferOffset(offset)..BufferOffset(offset);
22364                            new_selections_by_buffer
22365                                .entry(buffer_handle)
22366                                .or_insert((Vec::new(), None))
22367                                .0
22368                                .push(range)
22369                        } else {
22370                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22371                            else {
22372                                continue;
22373                            };
22374                            new_selections_by_buffer
22375                                .entry(buffer_handle)
22376                                .or_insert((Vec::new(), None))
22377                                .0
22378                                .push(range)
22379                        }
22380                    }
22381                }
22382            }
22383        }
22384
22385        new_selections_by_buffer
22386            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
22387
22388        if new_selections_by_buffer.is_empty() {
22389            return;
22390        }
22391
22392        // We defer the pane interaction because we ourselves are a workspace item
22393        // and activating a new item causes the pane to call a method on us reentrantly,
22394        // which panics if we're on the stack.
22395        window.defer(cx, move |window, cx| {
22396            workspace.update(cx, |workspace, cx| {
22397                let pane = if split {
22398                    workspace.adjacent_pane(window, cx)
22399                } else {
22400                    workspace.active_pane().clone()
22401                };
22402
22403                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22404                    let buffer_read = buffer.read(cx);
22405                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22406                        (true, project::File::from_dyn(Some(file)).is_some())
22407                    } else {
22408                        (false, false)
22409                    };
22410
22411                    // If project file is none workspace.open_project_item will fail to open the excerpt
22412                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22413                    // so we check if there's a tab match in that case first
22414                    let editor = (!has_file || !is_project_file)
22415                        .then(|| {
22416                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22417                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22418                            // Instead, we try to activate the existing editor in the pane first.
22419                            let (editor, pane_item_index, pane_item_id) =
22420                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22421                                    let editor = item.downcast::<Editor>()?;
22422                                    let singleton_buffer =
22423                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22424                                    if singleton_buffer == buffer {
22425                                        Some((editor, i, item.item_id()))
22426                                    } else {
22427                                        None
22428                                    }
22429                                })?;
22430                            pane.update(cx, |pane, cx| {
22431                                pane.activate_item(pane_item_index, true, true, window, cx);
22432                                if !PreviewTabsSettings::get_global(cx)
22433                                    .enable_preview_from_multibuffer
22434                                {
22435                                    pane.unpreview_item_if_preview(pane_item_id);
22436                                }
22437                            });
22438                            Some(editor)
22439                        })
22440                        .flatten()
22441                        .unwrap_or_else(|| {
22442                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22443                                .enable_keep_preview_on_code_navigation;
22444                            let allow_new_preview =
22445                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22446                            workspace.open_project_item::<Self>(
22447                                pane.clone(),
22448                                buffer,
22449                                true,
22450                                true,
22451                                keep_old_preview,
22452                                allow_new_preview,
22453                                window,
22454                                cx,
22455                            )
22456                        });
22457
22458                    editor.update(cx, |editor, cx| {
22459                        if has_file && !is_project_file {
22460                            editor.set_read_only(true);
22461                        }
22462                        let autoscroll = match scroll_offset {
22463                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22464                            None => Autoscroll::newest(),
22465                        };
22466                        let nav_history = editor.nav_history.take();
22467                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
22468                        let Some((&excerpt_id, _, buffer_snapshot)) =
22469                            multibuffer_snapshot.as_singleton()
22470                        else {
22471                            return;
22472                        };
22473                        editor.change_selections(
22474                            SelectionEffects::scroll(autoscroll),
22475                            window,
22476                            cx,
22477                            |s| {
22478                                s.select_ranges(ranges.into_iter().map(|range| {
22479                                    let range = buffer_snapshot.anchor_before(range.start)
22480                                        ..buffer_snapshot.anchor_after(range.end);
22481                                    multibuffer_snapshot
22482                                        .anchor_range_in_excerpt(excerpt_id, range)
22483                                        .unwrap()
22484                                }));
22485                            },
22486                        );
22487                        editor.nav_history = nav_history;
22488                    });
22489                }
22490            })
22491        });
22492    }
22493
22494    // Allow opening excerpts for buffers that either belong to the current project
22495    // or represent synthetic/non-local files (e.g., git blobs). File-less buffers
22496    // are also supported so tests and other in-memory views keep working.
22497    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
22498        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some() || !file.is_local())
22499    }
22500
22501    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22502        let snapshot = self.buffer.read(cx).read(cx);
22503        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22504        Some(
22505            ranges
22506                .iter()
22507                .map(move |range| {
22508                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22509                })
22510                .collect(),
22511        )
22512    }
22513
22514    fn selection_replacement_ranges(
22515        &self,
22516        range: Range<MultiBufferOffsetUtf16>,
22517        cx: &mut App,
22518    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22519        let selections = self
22520            .selections
22521            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22522        let newest_selection = selections
22523            .iter()
22524            .max_by_key(|selection| selection.id)
22525            .unwrap();
22526        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22527        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22528        let snapshot = self.buffer.read(cx).read(cx);
22529        selections
22530            .into_iter()
22531            .map(|mut selection| {
22532                selection.start.0.0 =
22533                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22534                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22535                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22536                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22537            })
22538            .collect()
22539    }
22540
22541    fn report_editor_event(
22542        &self,
22543        reported_event: ReportEditorEvent,
22544        file_extension: Option<String>,
22545        cx: &App,
22546    ) {
22547        if cfg!(any(test, feature = "test-support")) {
22548            return;
22549        }
22550
22551        let Some(project) = &self.project else { return };
22552
22553        // If None, we are in a file without an extension
22554        let file = self
22555            .buffer
22556            .read(cx)
22557            .as_singleton()
22558            .and_then(|b| b.read(cx).file());
22559        let file_extension = file_extension.or(file
22560            .as_ref()
22561            .and_then(|file| Path::new(file.file_name(cx)).extension())
22562            .and_then(|e| e.to_str())
22563            .map(|a| a.to_string()));
22564
22565        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22566            .map(|vim_mode| vim_mode.0)
22567            .unwrap_or(false);
22568
22569        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22570        let copilot_enabled = edit_predictions_provider
22571            == language::language_settings::EditPredictionProvider::Copilot;
22572        let copilot_enabled_for_language = self
22573            .buffer
22574            .read(cx)
22575            .language_settings(cx)
22576            .show_edit_predictions;
22577
22578        let project = project.read(cx);
22579        let event_type = reported_event.event_type();
22580
22581        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22582            telemetry::event!(
22583                event_type,
22584                type = if auto_saved {"autosave"} else {"manual"},
22585                file_extension,
22586                vim_mode,
22587                copilot_enabled,
22588                copilot_enabled_for_language,
22589                edit_predictions_provider,
22590                is_via_ssh = project.is_via_remote_server(),
22591            );
22592        } else {
22593            telemetry::event!(
22594                event_type,
22595                file_extension,
22596                vim_mode,
22597                copilot_enabled,
22598                copilot_enabled_for_language,
22599                edit_predictions_provider,
22600                is_via_ssh = project.is_via_remote_server(),
22601            );
22602        };
22603    }
22604
22605    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22606    /// with each line being an array of {text, highlight} objects.
22607    fn copy_highlight_json(
22608        &mut self,
22609        _: &CopyHighlightJson,
22610        window: &mut Window,
22611        cx: &mut Context<Self>,
22612    ) {
22613        #[derive(Serialize)]
22614        struct Chunk<'a> {
22615            text: String,
22616            highlight: Option<&'a str>,
22617        }
22618
22619        let snapshot = self.buffer.read(cx).snapshot(cx);
22620        let range = self
22621            .selected_text_range(false, window, cx)
22622            .and_then(|selection| {
22623                if selection.range.is_empty() {
22624                    None
22625                } else {
22626                    Some(
22627                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22628                            selection.range.start,
22629                        )))
22630                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22631                                selection.range.end,
22632                            ))),
22633                    )
22634                }
22635            })
22636            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22637
22638        let chunks = snapshot.chunks(range, true);
22639        let mut lines = Vec::new();
22640        let mut line: VecDeque<Chunk> = VecDeque::new();
22641
22642        let Some(style) = self.style.as_ref() else {
22643            return;
22644        };
22645
22646        for chunk in chunks {
22647            let highlight = chunk
22648                .syntax_highlight_id
22649                .and_then(|id| id.name(&style.syntax));
22650            let mut chunk_lines = chunk.text.split('\n').peekable();
22651            while let Some(text) = chunk_lines.next() {
22652                let mut merged_with_last_token = false;
22653                if let Some(last_token) = line.back_mut()
22654                    && last_token.highlight == highlight
22655                {
22656                    last_token.text.push_str(text);
22657                    merged_with_last_token = true;
22658                }
22659
22660                if !merged_with_last_token {
22661                    line.push_back(Chunk {
22662                        text: text.into(),
22663                        highlight,
22664                    });
22665                }
22666
22667                if chunk_lines.peek().is_some() {
22668                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22669                        line.pop_front();
22670                    }
22671                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22672                        line.pop_back();
22673                    }
22674
22675                    lines.push(mem::take(&mut line));
22676                }
22677            }
22678        }
22679
22680        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22681            return;
22682        };
22683        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22684    }
22685
22686    pub fn open_context_menu(
22687        &mut self,
22688        _: &OpenContextMenu,
22689        window: &mut Window,
22690        cx: &mut Context<Self>,
22691    ) {
22692        self.request_autoscroll(Autoscroll::newest(), cx);
22693        let position = self
22694            .selections
22695            .newest_display(&self.display_snapshot(cx))
22696            .start;
22697        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22698    }
22699
22700    pub fn replay_insert_event(
22701        &mut self,
22702        text: &str,
22703        relative_utf16_range: Option<Range<isize>>,
22704        window: &mut Window,
22705        cx: &mut Context<Self>,
22706    ) {
22707        if !self.input_enabled {
22708            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22709            return;
22710        }
22711        if let Some(relative_utf16_range) = relative_utf16_range {
22712            let selections = self
22713                .selections
22714                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22715            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22716                let new_ranges = selections.into_iter().map(|range| {
22717                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22718                        range
22719                            .head()
22720                            .0
22721                            .0
22722                            .saturating_add_signed(relative_utf16_range.start),
22723                    ));
22724                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22725                        range
22726                            .head()
22727                            .0
22728                            .0
22729                            .saturating_add_signed(relative_utf16_range.end),
22730                    ));
22731                    start..end
22732                });
22733                s.select_ranges(new_ranges);
22734            });
22735        }
22736
22737        self.handle_input(text, window, cx);
22738    }
22739
22740    pub fn is_focused(&self, window: &Window) -> bool {
22741        self.focus_handle.is_focused(window)
22742    }
22743
22744    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22745        cx.emit(EditorEvent::Focused);
22746
22747        if let Some(descendant) = self
22748            .last_focused_descendant
22749            .take()
22750            .and_then(|descendant| descendant.upgrade())
22751        {
22752            window.focus(&descendant);
22753        } else {
22754            if let Some(blame) = self.blame.as_ref() {
22755                blame.update(cx, GitBlame::focus)
22756            }
22757
22758            self.blink_manager.update(cx, BlinkManager::enable);
22759            self.show_cursor_names(window, cx);
22760            self.buffer.update(cx, |buffer, cx| {
22761                buffer.finalize_last_transaction(cx);
22762                if self.leader_id.is_none() {
22763                    buffer.set_active_selections(
22764                        &self.selections.disjoint_anchors_arc(),
22765                        self.selections.line_mode(),
22766                        self.cursor_shape,
22767                        cx,
22768                    );
22769                }
22770            });
22771
22772            if let Some(position_map) = self.last_position_map.clone() {
22773                EditorElement::mouse_moved(
22774                    self,
22775                    &MouseMoveEvent {
22776                        position: window.mouse_position(),
22777                        pressed_button: None,
22778                        modifiers: window.modifiers(),
22779                    },
22780                    &position_map,
22781                    window,
22782                    cx,
22783                );
22784            }
22785        }
22786    }
22787
22788    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22789        cx.emit(EditorEvent::FocusedIn)
22790    }
22791
22792    fn handle_focus_out(
22793        &mut self,
22794        event: FocusOutEvent,
22795        _window: &mut Window,
22796        cx: &mut Context<Self>,
22797    ) {
22798        if event.blurred != self.focus_handle {
22799            self.last_focused_descendant = Some(event.blurred);
22800        }
22801        self.selection_drag_state = SelectionDragState::None;
22802        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22803    }
22804
22805    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22806        self.blink_manager.update(cx, BlinkManager::disable);
22807        self.buffer
22808            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22809
22810        if let Some(blame) = self.blame.as_ref() {
22811            blame.update(cx, GitBlame::blur)
22812        }
22813        if !self.hover_state.focused(window, cx) {
22814            hide_hover(self, cx);
22815        }
22816        if !self
22817            .context_menu
22818            .borrow()
22819            .as_ref()
22820            .is_some_and(|context_menu| context_menu.focused(window, cx))
22821        {
22822            self.hide_context_menu(window, cx);
22823        }
22824        self.take_active_edit_prediction(cx);
22825        cx.emit(EditorEvent::Blurred);
22826        cx.notify();
22827    }
22828
22829    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22830        let mut pending: String = window
22831            .pending_input_keystrokes()
22832            .into_iter()
22833            .flatten()
22834            .filter_map(|keystroke| keystroke.key_char.clone())
22835            .collect();
22836
22837        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22838            pending = "".to_string();
22839        }
22840
22841        let existing_pending = self
22842            .text_highlights::<PendingInput>(cx)
22843            .map(|(_, ranges)| ranges.to_vec());
22844        if existing_pending.is_none() && pending.is_empty() {
22845            return;
22846        }
22847        let transaction =
22848            self.transact(window, cx, |this, window, cx| {
22849                let selections = this
22850                    .selections
22851                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22852                let edits = selections
22853                    .iter()
22854                    .map(|selection| (selection.end..selection.end, pending.clone()));
22855                this.edit(edits, cx);
22856                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22857                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22858                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22859                    }));
22860                });
22861                if let Some(existing_ranges) = existing_pending {
22862                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22863                    this.edit(edits, cx);
22864                }
22865            });
22866
22867        let snapshot = self.snapshot(window, cx);
22868        let ranges = self
22869            .selections
22870            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22871            .into_iter()
22872            .map(|selection| {
22873                snapshot.buffer_snapshot().anchor_after(selection.end)
22874                    ..snapshot
22875                        .buffer_snapshot()
22876                        .anchor_before(selection.end + pending.len())
22877            })
22878            .collect();
22879
22880        if pending.is_empty() {
22881            self.clear_highlights::<PendingInput>(cx);
22882        } else {
22883            self.highlight_text::<PendingInput>(
22884                ranges,
22885                HighlightStyle {
22886                    underline: Some(UnderlineStyle {
22887                        thickness: px(1.),
22888                        color: None,
22889                        wavy: false,
22890                    }),
22891                    ..Default::default()
22892                },
22893                cx,
22894            );
22895        }
22896
22897        self.ime_transaction = self.ime_transaction.or(transaction);
22898        if let Some(transaction) = self.ime_transaction {
22899            self.buffer.update(cx, |buffer, cx| {
22900                buffer.group_until_transaction(transaction, cx);
22901            });
22902        }
22903
22904        if self.text_highlights::<PendingInput>(cx).is_none() {
22905            self.ime_transaction.take();
22906        }
22907    }
22908
22909    pub fn register_action_renderer(
22910        &mut self,
22911        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22912    ) -> Subscription {
22913        let id = self.next_editor_action_id.post_inc();
22914        self.editor_actions
22915            .borrow_mut()
22916            .insert(id, Box::new(listener));
22917
22918        let editor_actions = self.editor_actions.clone();
22919        Subscription::new(move || {
22920            editor_actions.borrow_mut().remove(&id);
22921        })
22922    }
22923
22924    pub fn register_action<A: Action>(
22925        &mut self,
22926        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22927    ) -> Subscription {
22928        let id = self.next_editor_action_id.post_inc();
22929        let listener = Arc::new(listener);
22930        self.editor_actions.borrow_mut().insert(
22931            id,
22932            Box::new(move |_, window, _| {
22933                let listener = listener.clone();
22934                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22935                    let action = action.downcast_ref().unwrap();
22936                    if phase == DispatchPhase::Bubble {
22937                        listener(action, window, cx)
22938                    }
22939                })
22940            }),
22941        );
22942
22943        let editor_actions = self.editor_actions.clone();
22944        Subscription::new(move || {
22945            editor_actions.borrow_mut().remove(&id);
22946        })
22947    }
22948
22949    pub fn file_header_size(&self) -> u32 {
22950        FILE_HEADER_HEIGHT
22951    }
22952
22953    pub fn restore(
22954        &mut self,
22955        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22956        window: &mut Window,
22957        cx: &mut Context<Self>,
22958    ) {
22959        let workspace = self.workspace();
22960        let project = self.project();
22961        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22962            let mut tasks = Vec::new();
22963            for (buffer_id, changes) in revert_changes {
22964                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22965                    buffer.update(cx, |buffer, cx| {
22966                        buffer.edit(
22967                            changes
22968                                .into_iter()
22969                                .map(|(range, text)| (range, text.to_string())),
22970                            None,
22971                            cx,
22972                        );
22973                    });
22974
22975                    if let Some(project) =
22976                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22977                    {
22978                        project.update(cx, |project, cx| {
22979                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22980                        })
22981                    }
22982                }
22983            }
22984            tasks
22985        });
22986        cx.spawn_in(window, async move |_, cx| {
22987            for (buffer, task) in save_tasks {
22988                let result = task.await;
22989                if result.is_err() {
22990                    let Some(path) = buffer
22991                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22992                        .ok()
22993                    else {
22994                        continue;
22995                    };
22996                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22997                        let Some(task) = cx
22998                            .update_window_entity(workspace, |workspace, window, cx| {
22999                                workspace
23000                                    .open_path_preview(path, None, false, false, false, window, cx)
23001                            })
23002                            .ok()
23003                        else {
23004                            continue;
23005                        };
23006                        task.await.log_err();
23007                    }
23008                }
23009            }
23010        })
23011        .detach();
23012        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23013            selections.refresh()
23014        });
23015    }
23016
23017    pub fn to_pixel_point(
23018        &mut self,
23019        source: multi_buffer::Anchor,
23020        editor_snapshot: &EditorSnapshot,
23021        window: &mut Window,
23022        cx: &App,
23023    ) -> Option<gpui::Point<Pixels>> {
23024        let source_point = source.to_display_point(editor_snapshot);
23025        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
23026    }
23027
23028    pub fn display_to_pixel_point(
23029        &mut self,
23030        source: DisplayPoint,
23031        editor_snapshot: &EditorSnapshot,
23032        window: &mut Window,
23033        cx: &App,
23034    ) -> Option<gpui::Point<Pixels>> {
23035        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
23036        let text_layout_details = self.text_layout_details(window);
23037        let scroll_top = text_layout_details
23038            .scroll_anchor
23039            .scroll_position(editor_snapshot)
23040            .y;
23041
23042        if source.row().as_f64() < scroll_top.floor() {
23043            return None;
23044        }
23045        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
23046        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
23047        Some(gpui::Point::new(source_x, source_y))
23048    }
23049
23050    pub fn has_visible_completions_menu(&self) -> bool {
23051        !self.edit_prediction_preview_is_active()
23052            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
23053                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
23054            })
23055    }
23056
23057    pub fn register_addon<T: Addon>(&mut self, instance: T) {
23058        if self.mode.is_minimap() {
23059            return;
23060        }
23061        self.addons
23062            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
23063    }
23064
23065    pub fn unregister_addon<T: Addon>(&mut self) {
23066        self.addons.remove(&std::any::TypeId::of::<T>());
23067    }
23068
23069    pub fn addon<T: Addon>(&self) -> Option<&T> {
23070        let type_id = std::any::TypeId::of::<T>();
23071        self.addons
23072            .get(&type_id)
23073            .and_then(|item| item.to_any().downcast_ref::<T>())
23074    }
23075
23076    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
23077        let type_id = std::any::TypeId::of::<T>();
23078        self.addons
23079            .get_mut(&type_id)
23080            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
23081    }
23082
23083    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
23084        let text_layout_details = self.text_layout_details(window);
23085        let style = &text_layout_details.editor_style;
23086        let font_id = window.text_system().resolve_font(&style.text.font());
23087        let font_size = style.text.font_size.to_pixels(window.rem_size());
23088        let line_height = style.text.line_height_in_pixels(window.rem_size());
23089        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
23090        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
23091
23092        CharacterDimensions {
23093            em_width,
23094            em_advance,
23095            line_height,
23096        }
23097    }
23098
23099    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
23100        self.load_diff_task.clone()
23101    }
23102
23103    fn read_metadata_from_db(
23104        &mut self,
23105        item_id: u64,
23106        workspace_id: WorkspaceId,
23107        window: &mut Window,
23108        cx: &mut Context<Editor>,
23109    ) {
23110        if self.buffer_kind(cx) == ItemBufferKind::Singleton
23111            && !self.mode.is_minimap()
23112            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
23113        {
23114            let buffer_snapshot = OnceCell::new();
23115
23116            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
23117                && !folds.is_empty()
23118            {
23119                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23120                self.fold_ranges(
23121                    folds
23122                        .into_iter()
23123                        .map(|(start, end)| {
23124                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23125                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23126                        })
23127                        .collect(),
23128                    false,
23129                    window,
23130                    cx,
23131                );
23132            }
23133
23134            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
23135                && !selections.is_empty()
23136            {
23137                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23138                // skip adding the initial selection to selection history
23139                self.selection_history.mode = SelectionHistoryMode::Skipping;
23140                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23141                    s.select_ranges(selections.into_iter().map(|(start, end)| {
23142                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23143                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23144                    }));
23145                });
23146                self.selection_history.mode = SelectionHistoryMode::Normal;
23147            };
23148        }
23149
23150        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
23151    }
23152
23153    fn update_lsp_data(
23154        &mut self,
23155        for_buffer: Option<BufferId>,
23156        window: &mut Window,
23157        cx: &mut Context<'_, Self>,
23158    ) {
23159        self.pull_diagnostics(for_buffer, window, cx);
23160        self.refresh_colors_for_visible_range(for_buffer, window, cx);
23161    }
23162
23163    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
23164        if self.ignore_lsp_data() {
23165            return;
23166        }
23167        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
23168            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
23169        }
23170    }
23171
23172    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
23173        if self.ignore_lsp_data() {
23174            return;
23175        }
23176
23177        if !self.registered_buffers.contains_key(&buffer_id)
23178            && let Some(project) = self.project.as_ref()
23179        {
23180            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
23181                project.update(cx, |project, cx| {
23182                    self.registered_buffers.insert(
23183                        buffer_id,
23184                        project.register_buffer_with_language_servers(&buffer, cx),
23185                    );
23186                });
23187            } else {
23188                self.registered_buffers.remove(&buffer_id);
23189            }
23190        }
23191    }
23192
23193    fn ignore_lsp_data(&self) -> bool {
23194        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
23195        // skip any LSP updates for it.
23196        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
23197    }
23198
23199    fn create_style(&self, cx: &App) -> EditorStyle {
23200        let settings = ThemeSettings::get_global(cx);
23201
23202        let mut text_style = match self.mode {
23203            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23204                color: cx.theme().colors().editor_foreground,
23205                font_family: settings.ui_font.family.clone(),
23206                font_features: settings.ui_font.features.clone(),
23207                font_fallbacks: settings.ui_font.fallbacks.clone(),
23208                font_size: rems(0.875).into(),
23209                font_weight: settings.ui_font.weight,
23210                line_height: relative(settings.buffer_line_height.value()),
23211                ..Default::default()
23212            },
23213            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23214                color: cx.theme().colors().editor_foreground,
23215                font_family: settings.buffer_font.family.clone(),
23216                font_features: settings.buffer_font.features.clone(),
23217                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23218                font_size: settings.buffer_font_size(cx).into(),
23219                font_weight: settings.buffer_font.weight,
23220                line_height: relative(settings.buffer_line_height.value()),
23221                ..Default::default()
23222            },
23223        };
23224        if let Some(text_style_refinement) = &self.text_style_refinement {
23225            text_style.refine(text_style_refinement)
23226        }
23227
23228        let background = match self.mode {
23229            EditorMode::SingleLine => cx.theme().system().transparent,
23230            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23231            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23232            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23233        };
23234
23235        EditorStyle {
23236            background,
23237            border: cx.theme().colors().border,
23238            local_player: cx.theme().players().local(),
23239            text: text_style,
23240            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23241            syntax: cx.theme().syntax().clone(),
23242            status: cx.theme().status().clone(),
23243            inlay_hints_style: make_inlay_hints_style(cx),
23244            edit_prediction_styles: make_suggestion_styles(cx),
23245            unnecessary_code_fade: settings.unnecessary_code_fade,
23246            show_underlines: self.diagnostics_enabled(),
23247        }
23248    }
23249}
23250
23251fn edit_for_markdown_paste<'a>(
23252    buffer: &MultiBufferSnapshot,
23253    range: Range<MultiBufferOffset>,
23254    to_insert: &'a str,
23255    url: Option<url::Url>,
23256) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
23257    if url.is_none() {
23258        return (range, Cow::Borrowed(to_insert));
23259    };
23260
23261    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
23262
23263    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
23264        Cow::Borrowed(to_insert)
23265    } else {
23266        Cow::Owned(format!("[{old_text}]({to_insert})"))
23267    };
23268    (range, new_text)
23269}
23270
23271fn process_completion_for_edit(
23272    completion: &Completion,
23273    intent: CompletionIntent,
23274    buffer: &Entity<Buffer>,
23275    cursor_position: &text::Anchor,
23276    cx: &mut Context<Editor>,
23277) -> CompletionEdit {
23278    let buffer = buffer.read(cx);
23279    let buffer_snapshot = buffer.snapshot();
23280    let (snippet, new_text) = if completion.is_snippet() {
23281        let mut snippet_source = completion.new_text.clone();
23282        // Workaround for typescript language server issues so that methods don't expand within
23283        // strings and functions with type expressions. The previous point is used because the query
23284        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
23285        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
23286        let previous_point = if previous_point.column > 0 {
23287            cursor_position.to_previous_offset(&buffer_snapshot)
23288        } else {
23289            cursor_position.to_offset(&buffer_snapshot)
23290        };
23291        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
23292            && scope.prefers_label_for_snippet_in_completion()
23293            && let Some(label) = completion.label()
23294            && matches!(
23295                completion.kind(),
23296                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
23297            )
23298        {
23299            snippet_source = label;
23300        }
23301        match Snippet::parse(&snippet_source).log_err() {
23302            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
23303            None => (None, completion.new_text.clone()),
23304        }
23305    } else {
23306        (None, completion.new_text.clone())
23307    };
23308
23309    let mut range_to_replace = {
23310        let replace_range = &completion.replace_range;
23311        if let CompletionSource::Lsp {
23312            insert_range: Some(insert_range),
23313            ..
23314        } = &completion.source
23315        {
23316            debug_assert_eq!(
23317                insert_range.start, replace_range.start,
23318                "insert_range and replace_range should start at the same position"
23319            );
23320            debug_assert!(
23321                insert_range
23322                    .start
23323                    .cmp(cursor_position, &buffer_snapshot)
23324                    .is_le(),
23325                "insert_range should start before or at cursor position"
23326            );
23327            debug_assert!(
23328                replace_range
23329                    .start
23330                    .cmp(cursor_position, &buffer_snapshot)
23331                    .is_le(),
23332                "replace_range should start before or at cursor position"
23333            );
23334
23335            let should_replace = match intent {
23336                CompletionIntent::CompleteWithInsert => false,
23337                CompletionIntent::CompleteWithReplace => true,
23338                CompletionIntent::Complete | CompletionIntent::Compose => {
23339                    let insert_mode =
23340                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
23341                            .completions
23342                            .lsp_insert_mode;
23343                    match insert_mode {
23344                        LspInsertMode::Insert => false,
23345                        LspInsertMode::Replace => true,
23346                        LspInsertMode::ReplaceSubsequence => {
23347                            let mut text_to_replace = buffer.chars_for_range(
23348                                buffer.anchor_before(replace_range.start)
23349                                    ..buffer.anchor_after(replace_range.end),
23350                            );
23351                            let mut current_needle = text_to_replace.next();
23352                            for haystack_ch in completion.label.text.chars() {
23353                                if let Some(needle_ch) = current_needle
23354                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
23355                                {
23356                                    current_needle = text_to_replace.next();
23357                                }
23358                            }
23359                            current_needle.is_none()
23360                        }
23361                        LspInsertMode::ReplaceSuffix => {
23362                            if replace_range
23363                                .end
23364                                .cmp(cursor_position, &buffer_snapshot)
23365                                .is_gt()
23366                            {
23367                                let range_after_cursor = *cursor_position..replace_range.end;
23368                                let text_after_cursor = buffer
23369                                    .text_for_range(
23370                                        buffer.anchor_before(range_after_cursor.start)
23371                                            ..buffer.anchor_after(range_after_cursor.end),
23372                                    )
23373                                    .collect::<String>()
23374                                    .to_ascii_lowercase();
23375                                completion
23376                                    .label
23377                                    .text
23378                                    .to_ascii_lowercase()
23379                                    .ends_with(&text_after_cursor)
23380                            } else {
23381                                true
23382                            }
23383                        }
23384                    }
23385                }
23386            };
23387
23388            if should_replace {
23389                replace_range.clone()
23390            } else {
23391                insert_range.clone()
23392            }
23393        } else {
23394            replace_range.clone()
23395        }
23396    };
23397
23398    if range_to_replace
23399        .end
23400        .cmp(cursor_position, &buffer_snapshot)
23401        .is_lt()
23402    {
23403        range_to_replace.end = *cursor_position;
23404    }
23405
23406    let replace_range = range_to_replace.to_offset(buffer);
23407    CompletionEdit {
23408        new_text,
23409        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
23410        snippet,
23411    }
23412}
23413
23414struct CompletionEdit {
23415    new_text: String,
23416    replace_range: Range<BufferOffset>,
23417    snippet: Option<Snippet>,
23418}
23419
23420fn insert_extra_newline_brackets(
23421    buffer: &MultiBufferSnapshot,
23422    range: Range<MultiBufferOffset>,
23423    language: &language::LanguageScope,
23424) -> bool {
23425    let leading_whitespace_len = buffer
23426        .reversed_chars_at(range.start)
23427        .take_while(|c| c.is_whitespace() && *c != '\n')
23428        .map(|c| c.len_utf8())
23429        .sum::<usize>();
23430    let trailing_whitespace_len = buffer
23431        .chars_at(range.end)
23432        .take_while(|c| c.is_whitespace() && *c != '\n')
23433        .map(|c| c.len_utf8())
23434        .sum::<usize>();
23435    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
23436
23437    language.brackets().any(|(pair, enabled)| {
23438        let pair_start = pair.start.trim_end();
23439        let pair_end = pair.end.trim_start();
23440
23441        enabled
23442            && pair.newline
23443            && buffer.contains_str_at(range.end, pair_end)
23444            && buffer.contains_str_at(
23445                range.start.saturating_sub_usize(pair_start.len()),
23446                pair_start,
23447            )
23448    })
23449}
23450
23451fn insert_extra_newline_tree_sitter(
23452    buffer: &MultiBufferSnapshot,
23453    range: Range<MultiBufferOffset>,
23454) -> bool {
23455    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
23456        [(buffer, range, _)] => (*buffer, range.clone()),
23457        _ => return false,
23458    };
23459    let pair = {
23460        let mut result: Option<BracketMatch<usize>> = None;
23461
23462        for pair in buffer
23463            .all_bracket_ranges(range.start.0..range.end.0)
23464            .filter(move |pair| {
23465                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
23466            })
23467        {
23468            let len = pair.close_range.end - pair.open_range.start;
23469
23470            if let Some(existing) = &result {
23471                let existing_len = existing.close_range.end - existing.open_range.start;
23472                if len > existing_len {
23473                    continue;
23474                }
23475            }
23476
23477            result = Some(pair);
23478        }
23479
23480        result
23481    };
23482    let Some(pair) = pair else {
23483        return false;
23484    };
23485    pair.newline_only
23486        && buffer
23487            .chars_for_range(pair.open_range.end..range.start.0)
23488            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
23489            .all(|c| c.is_whitespace() && c != '\n')
23490}
23491
23492fn update_uncommitted_diff_for_buffer(
23493    editor: Entity<Editor>,
23494    project: &Entity<Project>,
23495    buffers: impl IntoIterator<Item = Entity<Buffer>>,
23496    buffer: Entity<MultiBuffer>,
23497    cx: &mut App,
23498) -> Task<()> {
23499    let mut tasks = Vec::new();
23500    project.update(cx, |project, cx| {
23501        for buffer in buffers {
23502            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
23503                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
23504            }
23505        }
23506    });
23507    cx.spawn(async move |cx| {
23508        let diffs = future::join_all(tasks).await;
23509        if editor
23510            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
23511            .unwrap_or(false)
23512        {
23513            return;
23514        }
23515
23516        buffer
23517            .update(cx, |buffer, cx| {
23518                for diff in diffs.into_iter().flatten() {
23519                    buffer.add_diff(diff, cx);
23520                }
23521            })
23522            .ok();
23523    })
23524}
23525
23526fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
23527    let tab_size = tab_size.get() as usize;
23528    let mut width = offset;
23529
23530    for ch in text.chars() {
23531        width += if ch == '\t' {
23532            tab_size - (width % tab_size)
23533        } else {
23534            1
23535        };
23536    }
23537
23538    width - offset
23539}
23540
23541#[cfg(test)]
23542mod tests {
23543    use super::*;
23544
23545    #[test]
23546    fn test_string_size_with_expanded_tabs() {
23547        let nz = |val| NonZeroU32::new(val).unwrap();
23548        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
23549        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
23550        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
23551        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
23552        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
23553        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
23554        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
23555        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
23556    }
23557}
23558
23559/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
23560struct WordBreakingTokenizer<'a> {
23561    input: &'a str,
23562}
23563
23564impl<'a> WordBreakingTokenizer<'a> {
23565    fn new(input: &'a str) -> Self {
23566        Self { input }
23567    }
23568}
23569
23570fn is_char_ideographic(ch: char) -> bool {
23571    use unicode_script::Script::*;
23572    use unicode_script::UnicodeScript;
23573    matches!(ch.script(), Han | Tangut | Yi)
23574}
23575
23576fn is_grapheme_ideographic(text: &str) -> bool {
23577    text.chars().any(is_char_ideographic)
23578}
23579
23580fn is_grapheme_whitespace(text: &str) -> bool {
23581    text.chars().any(|x| x.is_whitespace())
23582}
23583
23584fn should_stay_with_preceding_ideograph(text: &str) -> bool {
23585    text.chars()
23586        .next()
23587        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
23588}
23589
23590#[derive(PartialEq, Eq, Debug, Clone, Copy)]
23591enum WordBreakToken<'a> {
23592    Word { token: &'a str, grapheme_len: usize },
23593    InlineWhitespace { token: &'a str, grapheme_len: usize },
23594    Newline,
23595}
23596
23597impl<'a> Iterator for WordBreakingTokenizer<'a> {
23598    /// Yields a span, the count of graphemes in the token, and whether it was
23599    /// whitespace. Note that it also breaks at word boundaries.
23600    type Item = WordBreakToken<'a>;
23601
23602    fn next(&mut self) -> Option<Self::Item> {
23603        use unicode_segmentation::UnicodeSegmentation;
23604        if self.input.is_empty() {
23605            return None;
23606        }
23607
23608        let mut iter = self.input.graphemes(true).peekable();
23609        let mut offset = 0;
23610        let mut grapheme_len = 0;
23611        if let Some(first_grapheme) = iter.next() {
23612            let is_newline = first_grapheme == "\n";
23613            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23614            offset += first_grapheme.len();
23615            grapheme_len += 1;
23616            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
23617                if let Some(grapheme) = iter.peek().copied()
23618                    && should_stay_with_preceding_ideograph(grapheme)
23619                {
23620                    offset += grapheme.len();
23621                    grapheme_len += 1;
23622                }
23623            } else {
23624                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23625                let mut next_word_bound = words.peek().copied();
23626                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23627                    next_word_bound = words.next();
23628                }
23629                while let Some(grapheme) = iter.peek().copied() {
23630                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23631                        break;
23632                    };
23633                    if is_grapheme_whitespace(grapheme) != is_whitespace
23634                        || (grapheme == "\n") != is_newline
23635                    {
23636                        break;
23637                    };
23638                    offset += grapheme.len();
23639                    grapheme_len += 1;
23640                    iter.next();
23641                }
23642            }
23643            let token = &self.input[..offset];
23644            self.input = &self.input[offset..];
23645            if token == "\n" {
23646                Some(WordBreakToken::Newline)
23647            } else if is_whitespace {
23648                Some(WordBreakToken::InlineWhitespace {
23649                    token,
23650                    grapheme_len,
23651                })
23652            } else {
23653                Some(WordBreakToken::Word {
23654                    token,
23655                    grapheme_len,
23656                })
23657            }
23658        } else {
23659            None
23660        }
23661    }
23662}
23663
23664#[test]
23665fn test_word_breaking_tokenizer() {
23666    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23667        ("", &[]),
23668        ("  ", &[whitespace("  ", 2)]),
23669        ("Ʒ", &[word("Ʒ", 1)]),
23670        ("Ǽ", &[word("Ǽ", 1)]),
23671        ("", &[word("", 1)]),
23672        ("⋑⋑", &[word("⋑⋑", 2)]),
23673        (
23674            "原理,进而",
23675            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23676        ),
23677        (
23678            "hello world",
23679            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23680        ),
23681        (
23682            "hello, world",
23683            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23684        ),
23685        (
23686            "  hello world",
23687            &[
23688                whitespace("  ", 2),
23689                word("hello", 5),
23690                whitespace(" ", 1),
23691                word("world", 5),
23692            ],
23693        ),
23694        (
23695            "这是什么 \n 钢笔",
23696            &[
23697                word("", 1),
23698                word("", 1),
23699                word("", 1),
23700                word("", 1),
23701                whitespace(" ", 1),
23702                newline(),
23703                whitespace(" ", 1),
23704                word("", 1),
23705                word("", 1),
23706            ],
23707        ),
23708        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23709    ];
23710
23711    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23712        WordBreakToken::Word {
23713            token,
23714            grapheme_len,
23715        }
23716    }
23717
23718    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23719        WordBreakToken::InlineWhitespace {
23720            token,
23721            grapheme_len,
23722        }
23723    }
23724
23725    fn newline() -> WordBreakToken<'static> {
23726        WordBreakToken::Newline
23727    }
23728
23729    for (input, result) in tests {
23730        assert_eq!(
23731            WordBreakingTokenizer::new(input)
23732                .collect::<Vec<_>>()
23733                .as_slice(),
23734            *result,
23735        );
23736    }
23737}
23738
23739fn wrap_with_prefix(
23740    first_line_prefix: String,
23741    subsequent_lines_prefix: String,
23742    unwrapped_text: String,
23743    wrap_column: usize,
23744    tab_size: NonZeroU32,
23745    preserve_existing_whitespace: bool,
23746) -> String {
23747    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23748    let subsequent_lines_prefix_len =
23749        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23750    let mut wrapped_text = String::new();
23751    let mut current_line = first_line_prefix;
23752    let mut is_first_line = true;
23753
23754    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23755    let mut current_line_len = first_line_prefix_len;
23756    let mut in_whitespace = false;
23757    for token in tokenizer {
23758        let have_preceding_whitespace = in_whitespace;
23759        match token {
23760            WordBreakToken::Word {
23761                token,
23762                grapheme_len,
23763            } => {
23764                in_whitespace = false;
23765                let current_prefix_len = if is_first_line {
23766                    first_line_prefix_len
23767                } else {
23768                    subsequent_lines_prefix_len
23769                };
23770                if current_line_len + grapheme_len > wrap_column
23771                    && current_line_len != current_prefix_len
23772                {
23773                    wrapped_text.push_str(current_line.trim_end());
23774                    wrapped_text.push('\n');
23775                    is_first_line = false;
23776                    current_line = subsequent_lines_prefix.clone();
23777                    current_line_len = subsequent_lines_prefix_len;
23778                }
23779                current_line.push_str(token);
23780                current_line_len += grapheme_len;
23781            }
23782            WordBreakToken::InlineWhitespace {
23783                mut token,
23784                mut grapheme_len,
23785            } => {
23786                in_whitespace = true;
23787                if have_preceding_whitespace && !preserve_existing_whitespace {
23788                    continue;
23789                }
23790                if !preserve_existing_whitespace {
23791                    // Keep a single whitespace grapheme as-is
23792                    if let Some(first) =
23793                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23794                    {
23795                        token = first;
23796                    } else {
23797                        token = " ";
23798                    }
23799                    grapheme_len = 1;
23800                }
23801                let current_prefix_len = if is_first_line {
23802                    first_line_prefix_len
23803                } else {
23804                    subsequent_lines_prefix_len
23805                };
23806                if current_line_len + grapheme_len > wrap_column {
23807                    wrapped_text.push_str(current_line.trim_end());
23808                    wrapped_text.push('\n');
23809                    is_first_line = false;
23810                    current_line = subsequent_lines_prefix.clone();
23811                    current_line_len = subsequent_lines_prefix_len;
23812                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23813                    current_line.push_str(token);
23814                    current_line_len += grapheme_len;
23815                }
23816            }
23817            WordBreakToken::Newline => {
23818                in_whitespace = true;
23819                let current_prefix_len = if is_first_line {
23820                    first_line_prefix_len
23821                } else {
23822                    subsequent_lines_prefix_len
23823                };
23824                if preserve_existing_whitespace {
23825                    wrapped_text.push_str(current_line.trim_end());
23826                    wrapped_text.push('\n');
23827                    is_first_line = false;
23828                    current_line = subsequent_lines_prefix.clone();
23829                    current_line_len = subsequent_lines_prefix_len;
23830                } else if have_preceding_whitespace {
23831                    continue;
23832                } else if current_line_len + 1 > wrap_column
23833                    && current_line_len != current_prefix_len
23834                {
23835                    wrapped_text.push_str(current_line.trim_end());
23836                    wrapped_text.push('\n');
23837                    is_first_line = false;
23838                    current_line = subsequent_lines_prefix.clone();
23839                    current_line_len = subsequent_lines_prefix_len;
23840                } else if current_line_len != current_prefix_len {
23841                    current_line.push(' ');
23842                    current_line_len += 1;
23843                }
23844            }
23845        }
23846    }
23847
23848    if !current_line.is_empty() {
23849        wrapped_text.push_str(&current_line);
23850    }
23851    wrapped_text
23852}
23853
23854#[test]
23855fn test_wrap_with_prefix() {
23856    assert_eq!(
23857        wrap_with_prefix(
23858            "# ".to_string(),
23859            "# ".to_string(),
23860            "abcdefg".to_string(),
23861            4,
23862            NonZeroU32::new(4).unwrap(),
23863            false,
23864        ),
23865        "# abcdefg"
23866    );
23867    assert_eq!(
23868        wrap_with_prefix(
23869            "".to_string(),
23870            "".to_string(),
23871            "\thello world".to_string(),
23872            8,
23873            NonZeroU32::new(4).unwrap(),
23874            false,
23875        ),
23876        "hello\nworld"
23877    );
23878    assert_eq!(
23879        wrap_with_prefix(
23880            "// ".to_string(),
23881            "// ".to_string(),
23882            "xx \nyy zz aa bb cc".to_string(),
23883            12,
23884            NonZeroU32::new(4).unwrap(),
23885            false,
23886        ),
23887        "// xx yy zz\n// aa bb cc"
23888    );
23889    assert_eq!(
23890        wrap_with_prefix(
23891            String::new(),
23892            String::new(),
23893            "这是什么 \n 钢笔".to_string(),
23894            3,
23895            NonZeroU32::new(4).unwrap(),
23896            false,
23897        ),
23898        "这是什\n么 钢\n"
23899    );
23900    assert_eq!(
23901        wrap_with_prefix(
23902            String::new(),
23903            String::new(),
23904            format!("foo{}bar", '\u{2009}'), // thin space
23905            80,
23906            NonZeroU32::new(4).unwrap(),
23907            false,
23908        ),
23909        format!("foo{}bar", '\u{2009}')
23910    );
23911}
23912
23913pub trait CollaborationHub {
23914    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23915    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23916    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23917}
23918
23919impl CollaborationHub for Entity<Project> {
23920    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23921        self.read(cx).collaborators()
23922    }
23923
23924    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23925        self.read(cx).user_store().read(cx).participant_indices()
23926    }
23927
23928    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23929        let this = self.read(cx);
23930        let user_ids = this.collaborators().values().map(|c| c.user_id);
23931        this.user_store().read(cx).participant_names(user_ids, cx)
23932    }
23933}
23934
23935pub trait SemanticsProvider {
23936    fn hover(
23937        &self,
23938        buffer: &Entity<Buffer>,
23939        position: text::Anchor,
23940        cx: &mut App,
23941    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23942
23943    fn inline_values(
23944        &self,
23945        buffer_handle: Entity<Buffer>,
23946        range: Range<text::Anchor>,
23947        cx: &mut App,
23948    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23949
23950    fn applicable_inlay_chunks(
23951        &self,
23952        buffer: &Entity<Buffer>,
23953        ranges: &[Range<text::Anchor>],
23954        cx: &mut App,
23955    ) -> Vec<Range<BufferRow>>;
23956
23957    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23958
23959    fn inlay_hints(
23960        &self,
23961        invalidate: InvalidationStrategy,
23962        buffer: Entity<Buffer>,
23963        ranges: Vec<Range<text::Anchor>>,
23964        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23965        cx: &mut App,
23966    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23967
23968    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23969
23970    fn document_highlights(
23971        &self,
23972        buffer: &Entity<Buffer>,
23973        position: text::Anchor,
23974        cx: &mut App,
23975    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23976
23977    fn definitions(
23978        &self,
23979        buffer: &Entity<Buffer>,
23980        position: text::Anchor,
23981        kind: GotoDefinitionKind,
23982        cx: &mut App,
23983    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23984
23985    fn range_for_rename(
23986        &self,
23987        buffer: &Entity<Buffer>,
23988        position: text::Anchor,
23989        cx: &mut App,
23990    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23991
23992    fn perform_rename(
23993        &self,
23994        buffer: &Entity<Buffer>,
23995        position: text::Anchor,
23996        new_name: String,
23997        cx: &mut App,
23998    ) -> Option<Task<Result<ProjectTransaction>>>;
23999}
24000
24001pub trait CompletionProvider {
24002    fn completions(
24003        &self,
24004        excerpt_id: ExcerptId,
24005        buffer: &Entity<Buffer>,
24006        buffer_position: text::Anchor,
24007        trigger: CompletionContext,
24008        window: &mut Window,
24009        cx: &mut Context<Editor>,
24010    ) -> Task<Result<Vec<CompletionResponse>>>;
24011
24012    fn resolve_completions(
24013        &self,
24014        _buffer: Entity<Buffer>,
24015        _completion_indices: Vec<usize>,
24016        _completions: Rc<RefCell<Box<[Completion]>>>,
24017        _cx: &mut Context<Editor>,
24018    ) -> Task<Result<bool>> {
24019        Task::ready(Ok(false))
24020    }
24021
24022    fn apply_additional_edits_for_completion(
24023        &self,
24024        _buffer: Entity<Buffer>,
24025        _completions: Rc<RefCell<Box<[Completion]>>>,
24026        _completion_index: usize,
24027        _push_to_history: bool,
24028        _cx: &mut Context<Editor>,
24029    ) -> Task<Result<Option<language::Transaction>>> {
24030        Task::ready(Ok(None))
24031    }
24032
24033    fn is_completion_trigger(
24034        &self,
24035        buffer: &Entity<Buffer>,
24036        position: language::Anchor,
24037        text: &str,
24038        trigger_in_words: bool,
24039        cx: &mut Context<Editor>,
24040    ) -> bool;
24041
24042    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
24043
24044    fn sort_completions(&self) -> bool {
24045        true
24046    }
24047
24048    fn filter_completions(&self) -> bool {
24049        true
24050    }
24051
24052    fn show_snippets(&self) -> bool {
24053        false
24054    }
24055}
24056
24057pub trait CodeActionProvider {
24058    fn id(&self) -> Arc<str>;
24059
24060    fn code_actions(
24061        &self,
24062        buffer: &Entity<Buffer>,
24063        range: Range<text::Anchor>,
24064        window: &mut Window,
24065        cx: &mut App,
24066    ) -> Task<Result<Vec<CodeAction>>>;
24067
24068    fn apply_code_action(
24069        &self,
24070        buffer_handle: Entity<Buffer>,
24071        action: CodeAction,
24072        excerpt_id: ExcerptId,
24073        push_to_history: bool,
24074        window: &mut Window,
24075        cx: &mut App,
24076    ) -> Task<Result<ProjectTransaction>>;
24077}
24078
24079impl CodeActionProvider for Entity<Project> {
24080    fn id(&self) -> Arc<str> {
24081        "project".into()
24082    }
24083
24084    fn code_actions(
24085        &self,
24086        buffer: &Entity<Buffer>,
24087        range: Range<text::Anchor>,
24088        _window: &mut Window,
24089        cx: &mut App,
24090    ) -> Task<Result<Vec<CodeAction>>> {
24091        self.update(cx, |project, cx| {
24092            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
24093            let code_actions = project.code_actions(buffer, range, None, cx);
24094            cx.background_spawn(async move {
24095                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
24096                Ok(code_lens_actions
24097                    .context("code lens fetch")?
24098                    .into_iter()
24099                    .flatten()
24100                    .chain(
24101                        code_actions
24102                            .context("code action fetch")?
24103                            .into_iter()
24104                            .flatten(),
24105                    )
24106                    .collect())
24107            })
24108        })
24109    }
24110
24111    fn apply_code_action(
24112        &self,
24113        buffer_handle: Entity<Buffer>,
24114        action: CodeAction,
24115        _excerpt_id: ExcerptId,
24116        push_to_history: bool,
24117        _window: &mut Window,
24118        cx: &mut App,
24119    ) -> Task<Result<ProjectTransaction>> {
24120        self.update(cx, |project, cx| {
24121            project.apply_code_action(buffer_handle, action, push_to_history, cx)
24122        })
24123    }
24124}
24125
24126fn snippet_completions(
24127    project: &Project,
24128    buffer: &Entity<Buffer>,
24129    buffer_anchor: text::Anchor,
24130    classifier: CharClassifier,
24131    cx: &mut App,
24132) -> Task<Result<CompletionResponse>> {
24133    let languages = buffer.read(cx).languages_at(buffer_anchor);
24134    let snippet_store = project.snippets().read(cx);
24135
24136    let scopes: Vec<_> = languages
24137        .iter()
24138        .filter_map(|language| {
24139            let language_name = language.lsp_id();
24140            let snippets = snippet_store.snippets_for(Some(language_name), cx);
24141
24142            if snippets.is_empty() {
24143                None
24144            } else {
24145                Some((language.default_scope(), snippets))
24146            }
24147        })
24148        .collect();
24149
24150    if scopes.is_empty() {
24151        return Task::ready(Ok(CompletionResponse {
24152            completions: vec![],
24153            display_options: CompletionDisplayOptions::default(),
24154            is_incomplete: false,
24155        }));
24156    }
24157
24158    let snapshot = buffer.read(cx).text_snapshot();
24159    let executor = cx.background_executor().clone();
24160
24161    cx.background_spawn(async move {
24162        let is_word_char = |c| classifier.is_word(c);
24163
24164        let mut is_incomplete = false;
24165        let mut completions: Vec<Completion> = Vec::new();
24166
24167        const MAX_PREFIX_LEN: usize = 128;
24168        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
24169        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
24170        let window_start = snapshot.clip_offset(window_start, Bias::Left);
24171
24172        let max_buffer_window: String = snapshot
24173            .text_for_range(window_start..buffer_offset)
24174            .collect();
24175
24176        if max_buffer_window.is_empty() {
24177            return Ok(CompletionResponse {
24178                completions: vec![],
24179                display_options: CompletionDisplayOptions::default(),
24180                is_incomplete: true,
24181            });
24182        }
24183
24184        for (_scope, snippets) in scopes.into_iter() {
24185            // Sort snippets by word count to match longer snippet prefixes first.
24186            let mut sorted_snippet_candidates = snippets
24187                .iter()
24188                .enumerate()
24189                .flat_map(|(snippet_ix, snippet)| {
24190                    snippet
24191                        .prefix
24192                        .iter()
24193                        .enumerate()
24194                        .map(move |(prefix_ix, prefix)| {
24195                            let word_count =
24196                                snippet_candidate_suffixes(prefix, is_word_char).count();
24197                            ((snippet_ix, prefix_ix), prefix, word_count)
24198                        })
24199                })
24200                .collect_vec();
24201            sorted_snippet_candidates
24202                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
24203
24204            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
24205
24206            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
24207                .take(
24208                    sorted_snippet_candidates
24209                        .first()
24210                        .map(|(_, _, word_count)| *word_count)
24211                        .unwrap_or_default(),
24212                )
24213                .collect_vec();
24214
24215            const MAX_RESULTS: usize = 100;
24216            // Each match also remembers how many characters from the buffer it consumed
24217            let mut matches: Vec<(StringMatch, usize)> = vec![];
24218
24219            let mut snippet_list_cutoff_index = 0;
24220            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
24221                let word_count = buffer_index + 1;
24222                // Increase `snippet_list_cutoff_index` until we have all of the
24223                // snippets with sufficiently many words.
24224                while sorted_snippet_candidates
24225                    .get(snippet_list_cutoff_index)
24226                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
24227                        *snippet_word_count >= word_count
24228                    })
24229                {
24230                    snippet_list_cutoff_index += 1;
24231                }
24232
24233                // Take only the candidates with at least `word_count` many words
24234                let snippet_candidates_at_word_len =
24235                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
24236
24237                let candidates = snippet_candidates_at_word_len
24238                    .iter()
24239                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
24240                    .enumerate() // index in `sorted_snippet_candidates`
24241                    // First char must match
24242                    .filter(|(_ix, prefix)| {
24243                        itertools::equal(
24244                            prefix
24245                                .chars()
24246                                .next()
24247                                .into_iter()
24248                                .flat_map(|c| c.to_lowercase()),
24249                            buffer_window
24250                                .chars()
24251                                .next()
24252                                .into_iter()
24253                                .flat_map(|c| c.to_lowercase()),
24254                        )
24255                    })
24256                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
24257                    .collect::<Vec<StringMatchCandidate>>();
24258
24259                matches.extend(
24260                    fuzzy::match_strings(
24261                        &candidates,
24262                        &buffer_window,
24263                        buffer_window.chars().any(|c| c.is_uppercase()),
24264                        true,
24265                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
24266                        &Default::default(),
24267                        executor.clone(),
24268                    )
24269                    .await
24270                    .into_iter()
24271                    .map(|string_match| (string_match, buffer_window.len())),
24272                );
24273
24274                if matches.len() >= MAX_RESULTS {
24275                    break;
24276                }
24277            }
24278
24279            let to_lsp = |point: &text::Anchor| {
24280                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
24281                point_to_lsp(end)
24282            };
24283            let lsp_end = to_lsp(&buffer_anchor);
24284
24285            if matches.len() >= MAX_RESULTS {
24286                is_incomplete = true;
24287            }
24288
24289            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
24290                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
24291                    sorted_snippet_candidates[string_match.candidate_id];
24292                let snippet = &snippets[snippet_index];
24293                let start = buffer_offset - buffer_window_len;
24294                let start = snapshot.anchor_before(start);
24295                let range = start..buffer_anchor;
24296                let lsp_start = to_lsp(&start);
24297                let lsp_range = lsp::Range {
24298                    start: lsp_start,
24299                    end: lsp_end,
24300                };
24301                Completion {
24302                    replace_range: range,
24303                    new_text: snippet.body.clone(),
24304                    source: CompletionSource::Lsp {
24305                        insert_range: None,
24306                        server_id: LanguageServerId(usize::MAX),
24307                        resolved: true,
24308                        lsp_completion: Box::new(lsp::CompletionItem {
24309                            label: snippet.prefix.first().unwrap().clone(),
24310                            kind: Some(CompletionItemKind::SNIPPET),
24311                            label_details: snippet.description.as_ref().map(|description| {
24312                                lsp::CompletionItemLabelDetails {
24313                                    detail: Some(description.clone()),
24314                                    description: None,
24315                                }
24316                            }),
24317                            insert_text_format: Some(InsertTextFormat::SNIPPET),
24318                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
24319                                lsp::InsertReplaceEdit {
24320                                    new_text: snippet.body.clone(),
24321                                    insert: lsp_range,
24322                                    replace: lsp_range,
24323                                },
24324                            )),
24325                            filter_text: Some(snippet.body.clone()),
24326                            sort_text: Some(char::MAX.to_string()),
24327                            ..lsp::CompletionItem::default()
24328                        }),
24329                        lsp_defaults: None,
24330                    },
24331                    label: CodeLabel {
24332                        text: matching_prefix.clone(),
24333                        runs: Vec::new(),
24334                        filter_range: 0..matching_prefix.len(),
24335                    },
24336                    icon_path: None,
24337                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
24338                        single_line: snippet.name.clone().into(),
24339                        plain_text: snippet
24340                            .description
24341                            .clone()
24342                            .map(|description| description.into()),
24343                    }),
24344                    insert_text_mode: None,
24345                    confirm: None,
24346                    match_start: Some(start),
24347                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
24348                }
24349            }));
24350        }
24351
24352        Ok(CompletionResponse {
24353            completions,
24354            display_options: CompletionDisplayOptions::default(),
24355            is_incomplete,
24356        })
24357    })
24358}
24359
24360impl CompletionProvider for Entity<Project> {
24361    fn completions(
24362        &self,
24363        _excerpt_id: ExcerptId,
24364        buffer: &Entity<Buffer>,
24365        buffer_position: text::Anchor,
24366        options: CompletionContext,
24367        _window: &mut Window,
24368        cx: &mut Context<Editor>,
24369    ) -> Task<Result<Vec<CompletionResponse>>> {
24370        self.update(cx, |project, cx| {
24371            let task = project.completions(buffer, buffer_position, options, cx);
24372            cx.background_spawn(task)
24373        })
24374    }
24375
24376    fn resolve_completions(
24377        &self,
24378        buffer: Entity<Buffer>,
24379        completion_indices: Vec<usize>,
24380        completions: Rc<RefCell<Box<[Completion]>>>,
24381        cx: &mut Context<Editor>,
24382    ) -> Task<Result<bool>> {
24383        self.update(cx, |project, cx| {
24384            project.lsp_store().update(cx, |lsp_store, cx| {
24385                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
24386            })
24387        })
24388    }
24389
24390    fn apply_additional_edits_for_completion(
24391        &self,
24392        buffer: Entity<Buffer>,
24393        completions: Rc<RefCell<Box<[Completion]>>>,
24394        completion_index: usize,
24395        push_to_history: bool,
24396        cx: &mut Context<Editor>,
24397    ) -> Task<Result<Option<language::Transaction>>> {
24398        self.update(cx, |project, cx| {
24399            project.lsp_store().update(cx, |lsp_store, cx| {
24400                lsp_store.apply_additional_edits_for_completion(
24401                    buffer,
24402                    completions,
24403                    completion_index,
24404                    push_to_history,
24405                    cx,
24406                )
24407            })
24408        })
24409    }
24410
24411    fn is_completion_trigger(
24412        &self,
24413        buffer: &Entity<Buffer>,
24414        position: language::Anchor,
24415        text: &str,
24416        trigger_in_words: bool,
24417        cx: &mut Context<Editor>,
24418    ) -> bool {
24419        let mut chars = text.chars();
24420        let char = if let Some(char) = chars.next() {
24421            char
24422        } else {
24423            return false;
24424        };
24425        if chars.next().is_some() {
24426            return false;
24427        }
24428
24429        let buffer = buffer.read(cx);
24430        let snapshot = buffer.snapshot();
24431        let classifier = snapshot
24432            .char_classifier_at(position)
24433            .scope_context(Some(CharScopeContext::Completion));
24434        if trigger_in_words && classifier.is_word(char) {
24435            return true;
24436        }
24437
24438        buffer.completion_triggers().contains(text)
24439    }
24440
24441    fn show_snippets(&self) -> bool {
24442        true
24443    }
24444}
24445
24446impl SemanticsProvider for Entity<Project> {
24447    fn hover(
24448        &self,
24449        buffer: &Entity<Buffer>,
24450        position: text::Anchor,
24451        cx: &mut App,
24452    ) -> Option<Task<Option<Vec<project::Hover>>>> {
24453        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
24454    }
24455
24456    fn document_highlights(
24457        &self,
24458        buffer: &Entity<Buffer>,
24459        position: text::Anchor,
24460        cx: &mut App,
24461    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
24462        Some(self.update(cx, |project, cx| {
24463            project.document_highlights(buffer, position, cx)
24464        }))
24465    }
24466
24467    fn definitions(
24468        &self,
24469        buffer: &Entity<Buffer>,
24470        position: text::Anchor,
24471        kind: GotoDefinitionKind,
24472        cx: &mut App,
24473    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
24474        Some(self.update(cx, |project, cx| match kind {
24475            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
24476            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
24477            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
24478            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
24479        }))
24480    }
24481
24482    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
24483        self.update(cx, |project, cx| {
24484            if project
24485                .active_debug_session(cx)
24486                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
24487            {
24488                return true;
24489            }
24490
24491            buffer.update(cx, |buffer, cx| {
24492                project.any_language_server_supports_inlay_hints(buffer, cx)
24493            })
24494        })
24495    }
24496
24497    fn inline_values(
24498        &self,
24499        buffer_handle: Entity<Buffer>,
24500        range: Range<text::Anchor>,
24501        cx: &mut App,
24502    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
24503        self.update(cx, |project, cx| {
24504            let (session, active_stack_frame) = project.active_debug_session(cx)?;
24505
24506            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
24507        })
24508    }
24509
24510    fn applicable_inlay_chunks(
24511        &self,
24512        buffer: &Entity<Buffer>,
24513        ranges: &[Range<text::Anchor>],
24514        cx: &mut App,
24515    ) -> Vec<Range<BufferRow>> {
24516        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24517            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
24518        })
24519    }
24520
24521    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
24522        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
24523            lsp_store.invalidate_inlay_hints(for_buffers)
24524        });
24525    }
24526
24527    fn inlay_hints(
24528        &self,
24529        invalidate: InvalidationStrategy,
24530        buffer: Entity<Buffer>,
24531        ranges: Vec<Range<text::Anchor>>,
24532        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24533        cx: &mut App,
24534    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
24535        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24536            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
24537        }))
24538    }
24539
24540    fn range_for_rename(
24541        &self,
24542        buffer: &Entity<Buffer>,
24543        position: text::Anchor,
24544        cx: &mut App,
24545    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
24546        Some(self.update(cx, |project, cx| {
24547            let buffer = buffer.clone();
24548            let task = project.prepare_rename(buffer.clone(), position, cx);
24549            cx.spawn(async move |_, cx| {
24550                Ok(match task.await? {
24551                    PrepareRenameResponse::Success(range) => Some(range),
24552                    PrepareRenameResponse::InvalidPosition => None,
24553                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
24554                        // Fallback on using TreeSitter info to determine identifier range
24555                        buffer.read_with(cx, |buffer, _| {
24556                            let snapshot = buffer.snapshot();
24557                            let (range, kind) = snapshot.surrounding_word(position, None);
24558                            if kind != Some(CharKind::Word) {
24559                                return None;
24560                            }
24561                            Some(
24562                                snapshot.anchor_before(range.start)
24563                                    ..snapshot.anchor_after(range.end),
24564                            )
24565                        })?
24566                    }
24567                })
24568            })
24569        }))
24570    }
24571
24572    fn perform_rename(
24573        &self,
24574        buffer: &Entity<Buffer>,
24575        position: text::Anchor,
24576        new_name: String,
24577        cx: &mut App,
24578    ) -> Option<Task<Result<ProjectTransaction>>> {
24579        Some(self.update(cx, |project, cx| {
24580            project.perform_rename(buffer.clone(), position, new_name, cx)
24581        }))
24582    }
24583}
24584
24585fn consume_contiguous_rows(
24586    contiguous_row_selections: &mut Vec<Selection<Point>>,
24587    selection: &Selection<Point>,
24588    display_map: &DisplaySnapshot,
24589    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
24590) -> (MultiBufferRow, MultiBufferRow) {
24591    contiguous_row_selections.push(selection.clone());
24592    let start_row = starting_row(selection, display_map);
24593    let mut end_row = ending_row(selection, display_map);
24594
24595    while let Some(next_selection) = selections.peek() {
24596        if next_selection.start.row <= end_row.0 {
24597            end_row = ending_row(next_selection, display_map);
24598            contiguous_row_selections.push(selections.next().unwrap().clone());
24599        } else {
24600            break;
24601        }
24602    }
24603    (start_row, end_row)
24604}
24605
24606fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24607    if selection.start.column > 0 {
24608        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
24609    } else {
24610        MultiBufferRow(selection.start.row)
24611    }
24612}
24613
24614fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24615    if next_selection.end.column > 0 || next_selection.is_empty() {
24616        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
24617    } else {
24618        MultiBufferRow(next_selection.end.row)
24619    }
24620}
24621
24622impl EditorSnapshot {
24623    pub fn remote_selections_in_range<'a>(
24624        &'a self,
24625        range: &'a Range<Anchor>,
24626        collaboration_hub: &dyn CollaborationHub,
24627        cx: &'a App,
24628    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24629        let participant_names = collaboration_hub.user_names(cx);
24630        let participant_indices = collaboration_hub.user_participant_indices(cx);
24631        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24632        let collaborators_by_replica_id = collaborators_by_peer_id
24633            .values()
24634            .map(|collaborator| (collaborator.replica_id, collaborator))
24635            .collect::<HashMap<_, _>>();
24636        self.buffer_snapshot()
24637            .selections_in_range(range, false)
24638            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24639                if replica_id == ReplicaId::AGENT {
24640                    Some(RemoteSelection {
24641                        replica_id,
24642                        selection,
24643                        cursor_shape,
24644                        line_mode,
24645                        collaborator_id: CollaboratorId::Agent,
24646                        user_name: Some("Agent".into()),
24647                        color: cx.theme().players().agent(),
24648                    })
24649                } else {
24650                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24651                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24652                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24653                    Some(RemoteSelection {
24654                        replica_id,
24655                        selection,
24656                        cursor_shape,
24657                        line_mode,
24658                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24659                        user_name,
24660                        color: if let Some(index) = participant_index {
24661                            cx.theme().players().color_for_participant(index.0)
24662                        } else {
24663                            cx.theme().players().absent()
24664                        },
24665                    })
24666                }
24667            })
24668    }
24669
24670    pub fn hunks_for_ranges(
24671        &self,
24672        ranges: impl IntoIterator<Item = Range<Point>>,
24673    ) -> Vec<MultiBufferDiffHunk> {
24674        let mut hunks = Vec::new();
24675        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24676            HashMap::default();
24677        for query_range in ranges {
24678            let query_rows =
24679                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24680            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24681                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24682            ) {
24683                // Include deleted hunks that are adjacent to the query range, because
24684                // otherwise they would be missed.
24685                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24686                if hunk.status().is_deleted() {
24687                    intersects_range |= hunk.row_range.start == query_rows.end;
24688                    intersects_range |= hunk.row_range.end == query_rows.start;
24689                }
24690                if intersects_range {
24691                    if !processed_buffer_rows
24692                        .entry(hunk.buffer_id)
24693                        .or_default()
24694                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24695                    {
24696                        continue;
24697                    }
24698                    hunks.push(hunk);
24699                }
24700            }
24701        }
24702
24703        hunks
24704    }
24705
24706    fn display_diff_hunks_for_rows<'a>(
24707        &'a self,
24708        display_rows: Range<DisplayRow>,
24709        folded_buffers: &'a HashSet<BufferId>,
24710    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24711        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24712        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24713
24714        self.buffer_snapshot()
24715            .diff_hunks_in_range(buffer_start..buffer_end)
24716            .filter_map(|hunk| {
24717                if folded_buffers.contains(&hunk.buffer_id) {
24718                    return None;
24719                }
24720
24721                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24722                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24723
24724                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24725                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24726
24727                let display_hunk = if hunk_display_start.column() != 0 {
24728                    DisplayDiffHunk::Folded {
24729                        display_row: hunk_display_start.row(),
24730                    }
24731                } else {
24732                    let mut end_row = hunk_display_end.row();
24733                    if hunk_display_end.column() > 0 {
24734                        end_row.0 += 1;
24735                    }
24736                    let is_created_file = hunk.is_created_file();
24737
24738                    DisplayDiffHunk::Unfolded {
24739                        status: hunk.status(),
24740                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24741                            ..hunk.diff_base_byte_range.end.0,
24742                        word_diffs: hunk.word_diffs,
24743                        display_row_range: hunk_display_start.row()..end_row,
24744                        multi_buffer_range: Anchor::range_in_buffer(
24745                            hunk.excerpt_id,
24746                            hunk.buffer_range,
24747                        ),
24748                        is_created_file,
24749                    }
24750                };
24751
24752                Some(display_hunk)
24753            })
24754    }
24755
24756    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24757        self.display_snapshot
24758            .buffer_snapshot()
24759            .language_at(position)
24760    }
24761
24762    pub fn is_focused(&self) -> bool {
24763        self.is_focused
24764    }
24765
24766    pub fn placeholder_text(&self) -> Option<String> {
24767        self.placeholder_display_snapshot
24768            .as_ref()
24769            .map(|display_map| display_map.text())
24770    }
24771
24772    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24773        self.scroll_anchor.scroll_position(&self.display_snapshot)
24774    }
24775
24776    pub fn gutter_dimensions(
24777        &self,
24778        font_id: FontId,
24779        font_size: Pixels,
24780        style: &EditorStyle,
24781        window: &mut Window,
24782        cx: &App,
24783    ) -> GutterDimensions {
24784        if self.show_gutter
24785            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
24786            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
24787        {
24788            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24789                matches!(
24790                    ProjectSettings::get_global(cx).git.git_gutter,
24791                    GitGutterSetting::TrackedFiles
24792                )
24793            });
24794            let gutter_settings = EditorSettings::get_global(cx).gutter;
24795            let show_line_numbers = self
24796                .show_line_numbers
24797                .unwrap_or(gutter_settings.line_numbers);
24798            let line_gutter_width = if show_line_numbers {
24799                // Avoid flicker-like gutter resizes when the line number gains another digit by
24800                // only resizing the gutter on files with > 10**min_line_number_digits lines.
24801                let min_width_for_number_on_gutter =
24802                    ch_advance * gutter_settings.min_line_number_digits as f32;
24803                self.max_line_number_width(style, window)
24804                    .max(min_width_for_number_on_gutter)
24805            } else {
24806                0.0.into()
24807            };
24808
24809            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24810            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24811
24812            let git_blame_entries_width =
24813                self.git_blame_gutter_max_author_length
24814                    .map(|max_author_length| {
24815                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24816                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24817
24818                        /// The number of characters to dedicate to gaps and margins.
24819                        const SPACING_WIDTH: usize = 4;
24820
24821                        let max_char_count = max_author_length.min(renderer.max_author_length())
24822                            + ::git::SHORT_SHA_LENGTH
24823                            + MAX_RELATIVE_TIMESTAMP.len()
24824                            + SPACING_WIDTH;
24825
24826                        ch_advance * max_char_count
24827                    });
24828
24829            let is_singleton = self.buffer_snapshot().is_singleton();
24830
24831            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24832            left_padding += if !is_singleton {
24833                ch_width * 4.0
24834            } else if show_runnables || show_breakpoints {
24835                ch_width * 3.0
24836            } else if show_git_gutter && show_line_numbers {
24837                ch_width * 2.0
24838            } else if show_git_gutter || show_line_numbers {
24839                ch_width
24840            } else {
24841                px(0.)
24842            };
24843
24844            let shows_folds = is_singleton && gutter_settings.folds;
24845
24846            let right_padding = if shows_folds && show_line_numbers {
24847                ch_width * 4.0
24848            } else if shows_folds || (!is_singleton && show_line_numbers) {
24849                ch_width * 3.0
24850            } else if show_line_numbers {
24851                ch_width
24852            } else {
24853                px(0.)
24854            };
24855
24856            GutterDimensions {
24857                left_padding,
24858                right_padding,
24859                width: line_gutter_width + left_padding + right_padding,
24860                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24861                git_blame_entries_width,
24862            }
24863        } else if self.offset_content {
24864            GutterDimensions::default_with_margin(font_id, font_size, cx)
24865        } else {
24866            GutterDimensions::default()
24867        }
24868    }
24869
24870    pub fn render_crease_toggle(
24871        &self,
24872        buffer_row: MultiBufferRow,
24873        row_contains_cursor: bool,
24874        editor: Entity<Editor>,
24875        window: &mut Window,
24876        cx: &mut App,
24877    ) -> Option<AnyElement> {
24878        let folded = self.is_line_folded(buffer_row);
24879        let mut is_foldable = false;
24880
24881        if let Some(crease) = self
24882            .crease_snapshot
24883            .query_row(buffer_row, self.buffer_snapshot())
24884        {
24885            is_foldable = true;
24886            match crease {
24887                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24888                    if let Some(render_toggle) = render_toggle {
24889                        let toggle_callback =
24890                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24891                                if folded {
24892                                    editor.update(cx, |editor, cx| {
24893                                        editor.fold_at(buffer_row, window, cx)
24894                                    });
24895                                } else {
24896                                    editor.update(cx, |editor, cx| {
24897                                        editor.unfold_at(buffer_row, window, cx)
24898                                    });
24899                                }
24900                            });
24901                        return Some((render_toggle)(
24902                            buffer_row,
24903                            folded,
24904                            toggle_callback,
24905                            window,
24906                            cx,
24907                        ));
24908                    }
24909                }
24910            }
24911        }
24912
24913        is_foldable |= self.starts_indent(buffer_row);
24914
24915        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24916            Some(
24917                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24918                    .toggle_state(folded)
24919                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24920                        if folded {
24921                            this.unfold_at(buffer_row, window, cx);
24922                        } else {
24923                            this.fold_at(buffer_row, window, cx);
24924                        }
24925                    }))
24926                    .into_any_element(),
24927            )
24928        } else {
24929            None
24930        }
24931    }
24932
24933    pub fn render_crease_trailer(
24934        &self,
24935        buffer_row: MultiBufferRow,
24936        window: &mut Window,
24937        cx: &mut App,
24938    ) -> Option<AnyElement> {
24939        let folded = self.is_line_folded(buffer_row);
24940        if let Crease::Inline { render_trailer, .. } = self
24941            .crease_snapshot
24942            .query_row(buffer_row, self.buffer_snapshot())?
24943        {
24944            let render_trailer = render_trailer.as_ref()?;
24945            Some(render_trailer(buffer_row, folded, window, cx))
24946        } else {
24947            None
24948        }
24949    }
24950
24951    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
24952        let digit_count = self.widest_line_number().ilog10() + 1;
24953        column_pixels(style, digit_count as usize, window)
24954    }
24955}
24956
24957pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
24958    let font_size = style.text.font_size.to_pixels(window.rem_size());
24959    let layout = window.text_system().shape_line(
24960        SharedString::from(" ".repeat(column)),
24961        font_size,
24962        &[TextRun {
24963            len: column,
24964            font: style.text.font(),
24965            color: Hsla::default(),
24966            ..Default::default()
24967        }],
24968        None,
24969    );
24970
24971    layout.width
24972}
24973
24974impl Deref for EditorSnapshot {
24975    type Target = DisplaySnapshot;
24976
24977    fn deref(&self) -> &Self::Target {
24978        &self.display_snapshot
24979    }
24980}
24981
24982#[derive(Clone, Debug, PartialEq, Eq)]
24983pub enum EditorEvent {
24984    InputIgnored {
24985        text: Arc<str>,
24986    },
24987    InputHandled {
24988        utf16_range_to_replace: Option<Range<isize>>,
24989        text: Arc<str>,
24990    },
24991    ExcerptsAdded {
24992        buffer: Entity<Buffer>,
24993        predecessor: ExcerptId,
24994        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24995    },
24996    ExcerptsRemoved {
24997        ids: Vec<ExcerptId>,
24998        removed_buffer_ids: Vec<BufferId>,
24999    },
25000    BufferFoldToggled {
25001        ids: Vec<ExcerptId>,
25002        folded: bool,
25003    },
25004    ExcerptsEdited {
25005        ids: Vec<ExcerptId>,
25006    },
25007    ExcerptsExpanded {
25008        ids: Vec<ExcerptId>,
25009    },
25010    BufferEdited,
25011    Edited {
25012        transaction_id: clock::Lamport,
25013    },
25014    Reparsed(BufferId),
25015    Focused,
25016    FocusedIn,
25017    Blurred,
25018    DirtyChanged,
25019    Saved,
25020    TitleChanged,
25021    SelectionsChanged {
25022        local: bool,
25023    },
25024    ScrollPositionChanged {
25025        local: bool,
25026        autoscroll: bool,
25027    },
25028    TransactionUndone {
25029        transaction_id: clock::Lamport,
25030    },
25031    TransactionBegun {
25032        transaction_id: clock::Lamport,
25033    },
25034    CursorShapeChanged,
25035    BreadcrumbsChanged,
25036    PushedToNavHistory {
25037        anchor: Anchor,
25038        is_deactivate: bool,
25039    },
25040}
25041
25042impl EventEmitter<EditorEvent> for Editor {}
25043
25044impl Focusable for Editor {
25045    fn focus_handle(&self, _cx: &App) -> FocusHandle {
25046        self.focus_handle.clone()
25047    }
25048}
25049
25050impl Render for Editor {
25051    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25052        EditorElement::new(&cx.entity(), self.create_style(cx))
25053    }
25054}
25055
25056impl EntityInputHandler for Editor {
25057    fn text_for_range(
25058        &mut self,
25059        range_utf16: Range<usize>,
25060        adjusted_range: &mut Option<Range<usize>>,
25061        _: &mut Window,
25062        cx: &mut Context<Self>,
25063    ) -> Option<String> {
25064        let snapshot = self.buffer.read(cx).read(cx);
25065        let start = snapshot.clip_offset_utf16(
25066            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
25067            Bias::Left,
25068        );
25069        let end = snapshot.clip_offset_utf16(
25070            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
25071            Bias::Right,
25072        );
25073        if (start.0.0..end.0.0) != range_utf16 {
25074            adjusted_range.replace(start.0.0..end.0.0);
25075        }
25076        Some(snapshot.text_for_range(start..end).collect())
25077    }
25078
25079    fn selected_text_range(
25080        &mut self,
25081        ignore_disabled_input: bool,
25082        _: &mut Window,
25083        cx: &mut Context<Self>,
25084    ) -> Option<UTF16Selection> {
25085        // Prevent the IME menu from appearing when holding down an alphabetic key
25086        // while input is disabled.
25087        if !ignore_disabled_input && !self.input_enabled {
25088            return None;
25089        }
25090
25091        let selection = self
25092            .selections
25093            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25094        let range = selection.range();
25095
25096        Some(UTF16Selection {
25097            range: range.start.0.0..range.end.0.0,
25098            reversed: selection.reversed,
25099        })
25100    }
25101
25102    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
25103        let snapshot = self.buffer.read(cx).read(cx);
25104        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
25105        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
25106    }
25107
25108    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25109        self.clear_highlights::<InputComposition>(cx);
25110        self.ime_transaction.take();
25111    }
25112
25113    fn replace_text_in_range(
25114        &mut self,
25115        range_utf16: Option<Range<usize>>,
25116        text: &str,
25117        window: &mut Window,
25118        cx: &mut Context<Self>,
25119    ) {
25120        if !self.input_enabled {
25121            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25122            return;
25123        }
25124
25125        self.transact(window, cx, |this, window, cx| {
25126            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
25127                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25128                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25129                Some(this.selection_replacement_ranges(range_utf16, cx))
25130            } else {
25131                this.marked_text_ranges(cx)
25132            };
25133
25134            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
25135                let newest_selection_id = this.selections.newest_anchor().id;
25136                this.selections
25137                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25138                    .iter()
25139                    .zip(ranges_to_replace.iter())
25140                    .find_map(|(selection, range)| {
25141                        if selection.id == newest_selection_id {
25142                            Some(
25143                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25144                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25145                            )
25146                        } else {
25147                            None
25148                        }
25149                    })
25150            });
25151
25152            cx.emit(EditorEvent::InputHandled {
25153                utf16_range_to_replace: range_to_replace,
25154                text: text.into(),
25155            });
25156
25157            if let Some(new_selected_ranges) = new_selected_ranges {
25158                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25159                    selections.select_ranges(new_selected_ranges)
25160                });
25161                this.backspace(&Default::default(), window, cx);
25162            }
25163
25164            this.handle_input(text, window, cx);
25165        });
25166
25167        if let Some(transaction) = self.ime_transaction {
25168            self.buffer.update(cx, |buffer, cx| {
25169                buffer.group_until_transaction(transaction, cx);
25170            });
25171        }
25172
25173        self.unmark_text(window, cx);
25174    }
25175
25176    fn replace_and_mark_text_in_range(
25177        &mut self,
25178        range_utf16: Option<Range<usize>>,
25179        text: &str,
25180        new_selected_range_utf16: Option<Range<usize>>,
25181        window: &mut Window,
25182        cx: &mut Context<Self>,
25183    ) {
25184        if !self.input_enabled {
25185            return;
25186        }
25187
25188        let transaction = self.transact(window, cx, |this, window, cx| {
25189            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
25190                let snapshot = this.buffer.read(cx).read(cx);
25191                if let Some(relative_range_utf16) = range_utf16.as_ref() {
25192                    for marked_range in &mut marked_ranges {
25193                        marked_range.end = marked_range.start + relative_range_utf16.end;
25194                        marked_range.start += relative_range_utf16.start;
25195                        marked_range.start =
25196                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
25197                        marked_range.end =
25198                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
25199                    }
25200                }
25201                Some(marked_ranges)
25202            } else if let Some(range_utf16) = range_utf16 {
25203                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25204                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25205                Some(this.selection_replacement_ranges(range_utf16, cx))
25206            } else {
25207                None
25208            };
25209
25210            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
25211                let newest_selection_id = this.selections.newest_anchor().id;
25212                this.selections
25213                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25214                    .iter()
25215                    .zip(ranges_to_replace.iter())
25216                    .find_map(|(selection, range)| {
25217                        if selection.id == newest_selection_id {
25218                            Some(
25219                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25220                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25221                            )
25222                        } else {
25223                            None
25224                        }
25225                    })
25226            });
25227
25228            cx.emit(EditorEvent::InputHandled {
25229                utf16_range_to_replace: range_to_replace,
25230                text: text.into(),
25231            });
25232
25233            if let Some(ranges) = ranges_to_replace {
25234                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25235                    s.select_ranges(ranges)
25236                });
25237            }
25238
25239            let marked_ranges = {
25240                let snapshot = this.buffer.read(cx).read(cx);
25241                this.selections
25242                    .disjoint_anchors_arc()
25243                    .iter()
25244                    .map(|selection| {
25245                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
25246                    })
25247                    .collect::<Vec<_>>()
25248            };
25249
25250            if text.is_empty() {
25251                this.unmark_text(window, cx);
25252            } else {
25253                this.highlight_text::<InputComposition>(
25254                    marked_ranges.clone(),
25255                    HighlightStyle {
25256                        underline: Some(UnderlineStyle {
25257                            thickness: px(1.),
25258                            color: None,
25259                            wavy: false,
25260                        }),
25261                        ..Default::default()
25262                    },
25263                    cx,
25264                );
25265            }
25266
25267            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
25268            let use_autoclose = this.use_autoclose;
25269            let use_auto_surround = this.use_auto_surround;
25270            this.set_use_autoclose(false);
25271            this.set_use_auto_surround(false);
25272            this.handle_input(text, window, cx);
25273            this.set_use_autoclose(use_autoclose);
25274            this.set_use_auto_surround(use_auto_surround);
25275
25276            if let Some(new_selected_range) = new_selected_range_utf16 {
25277                let snapshot = this.buffer.read(cx).read(cx);
25278                let new_selected_ranges = marked_ranges
25279                    .into_iter()
25280                    .map(|marked_range| {
25281                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
25282                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
25283                            insertion_start.0 + new_selected_range.start,
25284                        ));
25285                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
25286                            insertion_start.0 + new_selected_range.end,
25287                        ));
25288                        snapshot.clip_offset_utf16(new_start, Bias::Left)
25289                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
25290                    })
25291                    .collect::<Vec<_>>();
25292
25293                drop(snapshot);
25294                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25295                    selections.select_ranges(new_selected_ranges)
25296                });
25297            }
25298        });
25299
25300        self.ime_transaction = self.ime_transaction.or(transaction);
25301        if let Some(transaction) = self.ime_transaction {
25302            self.buffer.update(cx, |buffer, cx| {
25303                buffer.group_until_transaction(transaction, cx);
25304            });
25305        }
25306
25307        if self.text_highlights::<InputComposition>(cx).is_none() {
25308            self.ime_transaction.take();
25309        }
25310    }
25311
25312    fn bounds_for_range(
25313        &mut self,
25314        range_utf16: Range<usize>,
25315        element_bounds: gpui::Bounds<Pixels>,
25316        window: &mut Window,
25317        cx: &mut Context<Self>,
25318    ) -> Option<gpui::Bounds<Pixels>> {
25319        let text_layout_details = self.text_layout_details(window);
25320        let CharacterDimensions {
25321            em_width,
25322            em_advance,
25323            line_height,
25324        } = self.character_dimensions(window);
25325
25326        let snapshot = self.snapshot(window, cx);
25327        let scroll_position = snapshot.scroll_position();
25328        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
25329
25330        let start =
25331            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
25332        let x = Pixels::from(
25333            ScrollOffset::from(
25334                snapshot.x_for_display_point(start, &text_layout_details)
25335                    + self.gutter_dimensions.full_width(),
25336            ) - scroll_left,
25337        );
25338        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
25339
25340        Some(Bounds {
25341            origin: element_bounds.origin + point(x, y),
25342            size: size(em_width, line_height),
25343        })
25344    }
25345
25346    fn character_index_for_point(
25347        &mut self,
25348        point: gpui::Point<Pixels>,
25349        _window: &mut Window,
25350        _cx: &mut Context<Self>,
25351    ) -> Option<usize> {
25352        let position_map = self.last_position_map.as_ref()?;
25353        if !position_map.text_hitbox.contains(&point) {
25354            return None;
25355        }
25356        let display_point = position_map.point_for_position(point).previous_valid;
25357        let anchor = position_map
25358            .snapshot
25359            .display_point_to_anchor(display_point, Bias::Left);
25360        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
25361        Some(utf16_offset.0.0)
25362    }
25363
25364    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
25365        self.input_enabled
25366    }
25367}
25368
25369trait SelectionExt {
25370    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
25371    fn spanned_rows(
25372        &self,
25373        include_end_if_at_line_start: bool,
25374        map: &DisplaySnapshot,
25375    ) -> Range<MultiBufferRow>;
25376}
25377
25378impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
25379    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
25380        let start = self
25381            .start
25382            .to_point(map.buffer_snapshot())
25383            .to_display_point(map);
25384        let end = self
25385            .end
25386            .to_point(map.buffer_snapshot())
25387            .to_display_point(map);
25388        if self.reversed {
25389            end..start
25390        } else {
25391            start..end
25392        }
25393    }
25394
25395    fn spanned_rows(
25396        &self,
25397        include_end_if_at_line_start: bool,
25398        map: &DisplaySnapshot,
25399    ) -> Range<MultiBufferRow> {
25400        let start = self.start.to_point(map.buffer_snapshot());
25401        let mut end = self.end.to_point(map.buffer_snapshot());
25402        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
25403            end.row -= 1;
25404        }
25405
25406        let buffer_start = map.prev_line_boundary(start).0;
25407        let buffer_end = map.next_line_boundary(end).0;
25408        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
25409    }
25410}
25411
25412impl<T: InvalidationRegion> InvalidationStack<T> {
25413    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
25414    where
25415        S: Clone + ToOffset,
25416    {
25417        while let Some(region) = self.last() {
25418            let all_selections_inside_invalidation_ranges =
25419                if selections.len() == region.ranges().len() {
25420                    selections
25421                        .iter()
25422                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
25423                        .all(|(selection, invalidation_range)| {
25424                            let head = selection.head().to_offset(buffer);
25425                            invalidation_range.start <= head && invalidation_range.end >= head
25426                        })
25427                } else {
25428                    false
25429                };
25430
25431            if all_selections_inside_invalidation_ranges {
25432                break;
25433            } else {
25434                self.pop();
25435            }
25436        }
25437    }
25438}
25439
25440impl<T> Default for InvalidationStack<T> {
25441    fn default() -> Self {
25442        Self(Default::default())
25443    }
25444}
25445
25446impl<T> Deref for InvalidationStack<T> {
25447    type Target = Vec<T>;
25448
25449    fn deref(&self) -> &Self::Target {
25450        &self.0
25451    }
25452}
25453
25454impl<T> DerefMut for InvalidationStack<T> {
25455    fn deref_mut(&mut self) -> &mut Self::Target {
25456        &mut self.0
25457    }
25458}
25459
25460impl InvalidationRegion for SnippetState {
25461    fn ranges(&self) -> &[Range<Anchor>] {
25462        &self.ranges[self.active_index]
25463    }
25464}
25465
25466fn edit_prediction_edit_text(
25467    current_snapshot: &BufferSnapshot,
25468    edits: &[(Range<Anchor>, impl AsRef<str>)],
25469    edit_preview: &EditPreview,
25470    include_deletions: bool,
25471    cx: &App,
25472) -> HighlightedText {
25473    let edits = edits
25474        .iter()
25475        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
25476        .collect::<Vec<_>>();
25477
25478    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
25479}
25480
25481fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
25482    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
25483    // Just show the raw edit text with basic styling
25484    let mut text = String::new();
25485    let mut highlights = Vec::new();
25486
25487    let insertion_highlight_style = HighlightStyle {
25488        color: Some(cx.theme().colors().text),
25489        ..Default::default()
25490    };
25491
25492    for (_, edit_text) in edits {
25493        let start_offset = text.len();
25494        text.push_str(edit_text);
25495        let end_offset = text.len();
25496
25497        if start_offset < end_offset {
25498            highlights.push((start_offset..end_offset, insertion_highlight_style));
25499        }
25500    }
25501
25502    HighlightedText {
25503        text: text.into(),
25504        highlights,
25505    }
25506}
25507
25508pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
25509    match severity {
25510        lsp::DiagnosticSeverity::ERROR => colors.error,
25511        lsp::DiagnosticSeverity::WARNING => colors.warning,
25512        lsp::DiagnosticSeverity::INFORMATION => colors.info,
25513        lsp::DiagnosticSeverity::HINT => colors.info,
25514        _ => colors.ignored,
25515    }
25516}
25517
25518pub fn styled_runs_for_code_label<'a>(
25519    label: &'a CodeLabel,
25520    syntax_theme: &'a theme::SyntaxTheme,
25521    local_player: &'a theme::PlayerColor,
25522) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
25523    let fade_out = HighlightStyle {
25524        fade_out: Some(0.35),
25525        ..Default::default()
25526    };
25527
25528    let mut prev_end = label.filter_range.end;
25529    label
25530        .runs
25531        .iter()
25532        .enumerate()
25533        .flat_map(move |(ix, (range, highlight_id))| {
25534            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
25535                HighlightStyle {
25536                    color: Some(local_player.cursor),
25537                    ..Default::default()
25538                }
25539            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
25540                HighlightStyle {
25541                    background_color: Some(local_player.selection),
25542                    ..Default::default()
25543                }
25544            } else if let Some(style) = highlight_id.style(syntax_theme) {
25545                style
25546            } else {
25547                return Default::default();
25548            };
25549            let muted_style = style.highlight(fade_out);
25550
25551            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
25552            if range.start >= label.filter_range.end {
25553                if range.start > prev_end {
25554                    runs.push((prev_end..range.start, fade_out));
25555                }
25556                runs.push((range.clone(), muted_style));
25557            } else if range.end <= label.filter_range.end {
25558                runs.push((range.clone(), style));
25559            } else {
25560                runs.push((range.start..label.filter_range.end, style));
25561                runs.push((label.filter_range.end..range.end, muted_style));
25562            }
25563            prev_end = cmp::max(prev_end, range.end);
25564
25565            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
25566                runs.push((prev_end..label.text.len(), fade_out));
25567            }
25568
25569            runs
25570        })
25571}
25572
25573pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
25574    let mut prev_index = 0;
25575    let mut prev_codepoint: Option<char> = None;
25576    text.char_indices()
25577        .chain([(text.len(), '\0')])
25578        .filter_map(move |(index, codepoint)| {
25579            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25580            let is_boundary = index == text.len()
25581                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
25582                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
25583            if is_boundary {
25584                let chunk = &text[prev_index..index];
25585                prev_index = index;
25586                Some(chunk)
25587            } else {
25588                None
25589            }
25590        })
25591}
25592
25593/// Given a string of text immediately before the cursor, iterates over possible
25594/// strings a snippet could match to. More precisely: returns an iterator over
25595/// suffixes of `text` created by splitting at word boundaries (before & after
25596/// every non-word character).
25597///
25598/// Shorter suffixes are returned first.
25599pub(crate) fn snippet_candidate_suffixes(
25600    text: &str,
25601    is_word_char: impl Fn(char) -> bool,
25602) -> impl std::iter::Iterator<Item = &str> {
25603    let mut prev_index = text.len();
25604    let mut prev_codepoint = None;
25605    text.char_indices()
25606        .rev()
25607        .chain([(0, '\0')])
25608        .filter_map(move |(index, codepoint)| {
25609            let prev_index = std::mem::replace(&mut prev_index, index);
25610            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25611            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
25612                None
25613            } else {
25614                let chunk = &text[prev_index..]; // go to end of string
25615                Some(chunk)
25616            }
25617        })
25618}
25619
25620pub trait RangeToAnchorExt: Sized {
25621    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25622
25623    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25624        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25625        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25626    }
25627}
25628
25629impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25630    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25631        let start_offset = self.start.to_offset(snapshot);
25632        let end_offset = self.end.to_offset(snapshot);
25633        if start_offset == end_offset {
25634            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25635        } else {
25636            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25637        }
25638    }
25639}
25640
25641pub trait RowExt {
25642    fn as_f64(&self) -> f64;
25643
25644    fn next_row(&self) -> Self;
25645
25646    fn previous_row(&self) -> Self;
25647
25648    fn minus(&self, other: Self) -> u32;
25649}
25650
25651impl RowExt for DisplayRow {
25652    fn as_f64(&self) -> f64 {
25653        self.0 as _
25654    }
25655
25656    fn next_row(&self) -> Self {
25657        Self(self.0 + 1)
25658    }
25659
25660    fn previous_row(&self) -> Self {
25661        Self(self.0.saturating_sub(1))
25662    }
25663
25664    fn minus(&self, other: Self) -> u32 {
25665        self.0 - other.0
25666    }
25667}
25668
25669impl RowExt for MultiBufferRow {
25670    fn as_f64(&self) -> f64 {
25671        self.0 as _
25672    }
25673
25674    fn next_row(&self) -> Self {
25675        Self(self.0 + 1)
25676    }
25677
25678    fn previous_row(&self) -> Self {
25679        Self(self.0.saturating_sub(1))
25680    }
25681
25682    fn minus(&self, other: Self) -> u32 {
25683        self.0 - other.0
25684    }
25685}
25686
25687trait RowRangeExt {
25688    type Row;
25689
25690    fn len(&self) -> usize;
25691
25692    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25693}
25694
25695impl RowRangeExt for Range<MultiBufferRow> {
25696    type Row = MultiBufferRow;
25697
25698    fn len(&self) -> usize {
25699        (self.end.0 - self.start.0) as usize
25700    }
25701
25702    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25703        (self.start.0..self.end.0).map(MultiBufferRow)
25704    }
25705}
25706
25707impl RowRangeExt for Range<DisplayRow> {
25708    type Row = DisplayRow;
25709
25710    fn len(&self) -> usize {
25711        (self.end.0 - self.start.0) as usize
25712    }
25713
25714    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25715        (self.start.0..self.end.0).map(DisplayRow)
25716    }
25717}
25718
25719/// If select range has more than one line, we
25720/// just point the cursor to range.start.
25721fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25722    if range.start.row == range.end.row {
25723        range
25724    } else {
25725        range.start..range.start
25726    }
25727}
25728pub struct KillRing(ClipboardItem);
25729impl Global for KillRing {}
25730
25731const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25732
25733enum BreakpointPromptEditAction {
25734    Log,
25735    Condition,
25736    HitCondition,
25737}
25738
25739struct BreakpointPromptEditor {
25740    pub(crate) prompt: Entity<Editor>,
25741    editor: WeakEntity<Editor>,
25742    breakpoint_anchor: Anchor,
25743    breakpoint: Breakpoint,
25744    edit_action: BreakpointPromptEditAction,
25745    block_ids: HashSet<CustomBlockId>,
25746    editor_margins: Arc<Mutex<EditorMargins>>,
25747    _subscriptions: Vec<Subscription>,
25748}
25749
25750impl BreakpointPromptEditor {
25751    const MAX_LINES: u8 = 4;
25752
25753    fn new(
25754        editor: WeakEntity<Editor>,
25755        breakpoint_anchor: Anchor,
25756        breakpoint: Breakpoint,
25757        edit_action: BreakpointPromptEditAction,
25758        window: &mut Window,
25759        cx: &mut Context<Self>,
25760    ) -> Self {
25761        let base_text = match edit_action {
25762            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25763            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25764            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25765        }
25766        .map(|msg| msg.to_string())
25767        .unwrap_or_default();
25768
25769        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25770        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25771
25772        let prompt = cx.new(|cx| {
25773            let mut prompt = Editor::new(
25774                EditorMode::AutoHeight {
25775                    min_lines: 1,
25776                    max_lines: Some(Self::MAX_LINES as usize),
25777                },
25778                buffer,
25779                None,
25780                window,
25781                cx,
25782            );
25783            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25784            prompt.set_show_cursor_when_unfocused(false, cx);
25785            prompt.set_placeholder_text(
25786                match edit_action {
25787                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25788                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25789                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25790                },
25791                window,
25792                cx,
25793            );
25794
25795            prompt
25796        });
25797
25798        Self {
25799            prompt,
25800            editor,
25801            breakpoint_anchor,
25802            breakpoint,
25803            edit_action,
25804            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25805            block_ids: Default::default(),
25806            _subscriptions: vec![],
25807        }
25808    }
25809
25810    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25811        self.block_ids.extend(block_ids)
25812    }
25813
25814    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25815        if let Some(editor) = self.editor.upgrade() {
25816            let message = self
25817                .prompt
25818                .read(cx)
25819                .buffer
25820                .read(cx)
25821                .as_singleton()
25822                .expect("A multi buffer in breakpoint prompt isn't possible")
25823                .read(cx)
25824                .as_rope()
25825                .to_string();
25826
25827            editor.update(cx, |editor, cx| {
25828                editor.edit_breakpoint_at_anchor(
25829                    self.breakpoint_anchor,
25830                    self.breakpoint.clone(),
25831                    match self.edit_action {
25832                        BreakpointPromptEditAction::Log => {
25833                            BreakpointEditAction::EditLogMessage(message.into())
25834                        }
25835                        BreakpointPromptEditAction::Condition => {
25836                            BreakpointEditAction::EditCondition(message.into())
25837                        }
25838                        BreakpointPromptEditAction::HitCondition => {
25839                            BreakpointEditAction::EditHitCondition(message.into())
25840                        }
25841                    },
25842                    cx,
25843                );
25844
25845                editor.remove_blocks(self.block_ids.clone(), None, cx);
25846                cx.focus_self(window);
25847            });
25848        }
25849    }
25850
25851    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25852        self.editor
25853            .update(cx, |editor, cx| {
25854                editor.remove_blocks(self.block_ids.clone(), None, cx);
25855                window.focus(&editor.focus_handle);
25856            })
25857            .log_err();
25858    }
25859
25860    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25861        let settings = ThemeSettings::get_global(cx);
25862        let text_style = TextStyle {
25863            color: if self.prompt.read(cx).read_only(cx) {
25864                cx.theme().colors().text_disabled
25865            } else {
25866                cx.theme().colors().text
25867            },
25868            font_family: settings.buffer_font.family.clone(),
25869            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25870            font_size: settings.buffer_font_size(cx).into(),
25871            font_weight: settings.buffer_font.weight,
25872            line_height: relative(settings.buffer_line_height.value()),
25873            ..Default::default()
25874        };
25875        EditorElement::new(
25876            &self.prompt,
25877            EditorStyle {
25878                background: cx.theme().colors().editor_background,
25879                local_player: cx.theme().players().local(),
25880                text: text_style,
25881                ..Default::default()
25882            },
25883        )
25884    }
25885}
25886
25887impl Render for BreakpointPromptEditor {
25888    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25889        let editor_margins = *self.editor_margins.lock();
25890        let gutter_dimensions = editor_margins.gutter;
25891        h_flex()
25892            .key_context("Editor")
25893            .bg(cx.theme().colors().editor_background)
25894            .border_y_1()
25895            .border_color(cx.theme().status().info_border)
25896            .size_full()
25897            .py(window.line_height() / 2.5)
25898            .on_action(cx.listener(Self::confirm))
25899            .on_action(cx.listener(Self::cancel))
25900            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25901            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25902    }
25903}
25904
25905impl Focusable for BreakpointPromptEditor {
25906    fn focus_handle(&self, cx: &App) -> FocusHandle {
25907        self.prompt.focus_handle(cx)
25908    }
25909}
25910
25911fn all_edits_insertions_or_deletions(
25912    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25913    snapshot: &MultiBufferSnapshot,
25914) -> bool {
25915    let mut all_insertions = true;
25916    let mut all_deletions = true;
25917
25918    for (range, new_text) in edits.iter() {
25919        let range_is_empty = range.to_offset(snapshot).is_empty();
25920        let text_is_empty = new_text.is_empty();
25921
25922        if range_is_empty != text_is_empty {
25923            if range_is_empty {
25924                all_deletions = false;
25925            } else {
25926                all_insertions = false;
25927            }
25928        } else {
25929            return false;
25930        }
25931
25932        if !all_insertions && !all_deletions {
25933            return false;
25934        }
25935    }
25936    all_insertions || all_deletions
25937}
25938
25939struct MissingEditPredictionKeybindingTooltip;
25940
25941impl Render for MissingEditPredictionKeybindingTooltip {
25942    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25943        ui::tooltip_container(cx, |container, cx| {
25944            container
25945                .flex_shrink_0()
25946                .max_w_80()
25947                .min_h(rems_from_px(124.))
25948                .justify_between()
25949                .child(
25950                    v_flex()
25951                        .flex_1()
25952                        .text_ui_sm(cx)
25953                        .child(Label::new("Conflict with Accept Keybinding"))
25954                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25955                )
25956                .child(
25957                    h_flex()
25958                        .pb_1()
25959                        .gap_1()
25960                        .items_end()
25961                        .w_full()
25962                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25963                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25964                        }))
25965                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25966                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25967                        })),
25968                )
25969        })
25970    }
25971}
25972
25973#[derive(Debug, Clone, Copy, PartialEq)]
25974pub struct LineHighlight {
25975    pub background: Background,
25976    pub border: Option<gpui::Hsla>,
25977    pub include_gutter: bool,
25978    pub type_id: Option<TypeId>,
25979}
25980
25981struct LineManipulationResult {
25982    pub new_text: String,
25983    pub line_count_before: usize,
25984    pub line_count_after: usize,
25985}
25986
25987fn render_diff_hunk_controls(
25988    row: u32,
25989    status: &DiffHunkStatus,
25990    hunk_range: Range<Anchor>,
25991    is_created_file: bool,
25992    line_height: Pixels,
25993    editor: &Entity<Editor>,
25994    _window: &mut Window,
25995    cx: &mut App,
25996) -> AnyElement {
25997    h_flex()
25998        .h(line_height)
25999        .mr_1()
26000        .gap_1()
26001        .px_0p5()
26002        .pb_1()
26003        .border_x_1()
26004        .border_b_1()
26005        .border_color(cx.theme().colors().border_variant)
26006        .rounded_b_lg()
26007        .bg(cx.theme().colors().editor_background)
26008        .gap_1()
26009        .block_mouse_except_scroll()
26010        .shadow_md()
26011        .child(if status.has_secondary_hunk() {
26012            Button::new(("stage", row as u64), "Stage")
26013                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26014                .tooltip({
26015                    let focus_handle = editor.focus_handle(cx);
26016                    move |_window, cx| {
26017                        Tooltip::for_action_in(
26018                            "Stage Hunk",
26019                            &::git::ToggleStaged,
26020                            &focus_handle,
26021                            cx,
26022                        )
26023                    }
26024                })
26025                .on_click({
26026                    let editor = editor.clone();
26027                    move |_event, _window, cx| {
26028                        editor.update(cx, |editor, cx| {
26029                            editor.stage_or_unstage_diff_hunks(
26030                                true,
26031                                vec![hunk_range.start..hunk_range.start],
26032                                cx,
26033                            );
26034                        });
26035                    }
26036                })
26037        } else {
26038            Button::new(("unstage", row as u64), "Unstage")
26039                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26040                .tooltip({
26041                    let focus_handle = editor.focus_handle(cx);
26042                    move |_window, cx| {
26043                        Tooltip::for_action_in(
26044                            "Unstage Hunk",
26045                            &::git::ToggleStaged,
26046                            &focus_handle,
26047                            cx,
26048                        )
26049                    }
26050                })
26051                .on_click({
26052                    let editor = editor.clone();
26053                    move |_event, _window, cx| {
26054                        editor.update(cx, |editor, cx| {
26055                            editor.stage_or_unstage_diff_hunks(
26056                                false,
26057                                vec![hunk_range.start..hunk_range.start],
26058                                cx,
26059                            );
26060                        });
26061                    }
26062                })
26063        })
26064        .child(
26065            Button::new(("restore", row as u64), "Restore")
26066                .tooltip({
26067                    let focus_handle = editor.focus_handle(cx);
26068                    move |_window, cx| {
26069                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
26070                    }
26071                })
26072                .on_click({
26073                    let editor = editor.clone();
26074                    move |_event, window, cx| {
26075                        editor.update(cx, |editor, cx| {
26076                            let snapshot = editor.snapshot(window, cx);
26077                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
26078                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
26079                        });
26080                    }
26081                })
26082                .disabled(is_created_file),
26083        )
26084        .when(
26085            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
26086            |el| {
26087                el.child(
26088                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
26089                        .shape(IconButtonShape::Square)
26090                        .icon_size(IconSize::Small)
26091                        // .disabled(!has_multiple_hunks)
26092                        .tooltip({
26093                            let focus_handle = editor.focus_handle(cx);
26094                            move |_window, cx| {
26095                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
26096                            }
26097                        })
26098                        .on_click({
26099                            let editor = editor.clone();
26100                            move |_event, window, cx| {
26101                                editor.update(cx, |editor, cx| {
26102                                    let snapshot = editor.snapshot(window, cx);
26103                                    let position =
26104                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
26105                                    editor.go_to_hunk_before_or_after_position(
26106                                        &snapshot,
26107                                        position,
26108                                        Direction::Next,
26109                                        window,
26110                                        cx,
26111                                    );
26112                                    editor.expand_selected_diff_hunks(cx);
26113                                });
26114                            }
26115                        }),
26116                )
26117                .child(
26118                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
26119                        .shape(IconButtonShape::Square)
26120                        .icon_size(IconSize::Small)
26121                        // .disabled(!has_multiple_hunks)
26122                        .tooltip({
26123                            let focus_handle = editor.focus_handle(cx);
26124                            move |_window, cx| {
26125                                Tooltip::for_action_in(
26126                                    "Previous Hunk",
26127                                    &GoToPreviousHunk,
26128                                    &focus_handle,
26129                                    cx,
26130                                )
26131                            }
26132                        })
26133                        .on_click({
26134                            let editor = editor.clone();
26135                            move |_event, window, cx| {
26136                                editor.update(cx, |editor, cx| {
26137                                    let snapshot = editor.snapshot(window, cx);
26138                                    let point =
26139                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
26140                                    editor.go_to_hunk_before_or_after_position(
26141                                        &snapshot,
26142                                        point,
26143                                        Direction::Prev,
26144                                        window,
26145                                        cx,
26146                                    );
26147                                    editor.expand_selected_diff_hunks(cx);
26148                                });
26149                            }
26150                        }),
26151                )
26152            },
26153        )
26154        .into_any_element()
26155}
26156
26157pub fn multibuffer_context_lines(cx: &App) -> u32 {
26158    EditorSettings::try_get(cx)
26159        .map(|settings| settings.excerpt_context_lines)
26160        .unwrap_or(2)
26161        .min(32)
26162}