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::{Restore, blame::BlameEntry, commit::ParsedCommitMessage, status::FileStatus};
   77use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   78use anyhow::{Context as _, Result, anyhow, bail};
   79use blink_manager::BlinkManager;
   80use buffer_diff::DiffHunkStatus;
   81use client::{Collaborator, ParticipantIndex, parse_zed_link};
   82use clock::ReplicaId;
   83use code_context_menus::{
   84    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   85    CompletionsMenu, ContextMenuOrigin,
   86};
   87use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   88use convert_case::{Case, Casing};
   89use dap::TelemetrySpawnLocation;
   90use display_map::*;
   91use edit_prediction_types::{
   92    EditPredictionDelegate, EditPredictionDelegateHandle, EditPredictionGranularity,
   93};
   94use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   95use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   96use futures::{
   97    FutureExt, StreamExt as _,
   98    future::{self, Shared, join},
   99    stream::FuturesUnordered,
  100};
  101use fuzzy::{StringMatch, StringMatchCandidate};
  102use git::blame::{GitBlame, GlobalBlameRenderer};
  103use gpui::{
  104    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  105    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  106    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  107    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  108    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, PressureStage,
  109    Render, ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, TextRun,
  110    TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle,
  111    WeakEntity, WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative,
  112    size,
  113};
  114use hover_links::{HoverLink, HoveredLinkState, find_file};
  115use hover_popover::{HoverState, hide_hover};
  116use indent_guides::ActiveIndentGuidesState;
  117use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  118use itertools::{Either, Itertools};
  119use language::{
  120    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  121    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  122    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  123    IndentSize, Language, LanguageName, LanguageRegistry, LanguageScope, OffsetRangeExt,
  124    OutlineItem, Point, Runnable, Selection, SelectionGoal, TextObject, TransactionId,
  125    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 regex::Regex;
  167use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  168use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  169use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  170use serde::{Deserialize, Serialize};
  171use settings::{
  172    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  173    update_settings_file,
  174};
  175use smallvec::{SmallVec, smallvec};
  176use snippet::Snippet;
  177use std::{
  178    any::{Any, TypeId},
  179    borrow::Cow,
  180    cell::{OnceCell, RefCell},
  181    cmp::{self, Ordering, Reverse},
  182    collections::hash_map,
  183    iter::{self, Peekable},
  184    mem,
  185    num::NonZeroU32,
  186    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  187    path::{Path, PathBuf},
  188    rc::Rc,
  189    sync::Arc,
  190    time::{Duration, Instant},
  191};
  192use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  193use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  194use theme::{
  195    AccentColors, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  196    observe_buffer_font_size_adjustment,
  197};
  198use ui::{
  199    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  200    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  201};
  202use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  203use workspace::{
  204    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  205    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  206    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  207    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  208    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  209    searchable::SearchEvent,
  210};
  211
  212use crate::{
  213    code_context_menus::CompletionsMenuSource,
  214    editor_settings::MultiCursorModifier,
  215    hover_links::{find_url, find_url_from_range},
  216    inlays::{
  217        InlineValueCache,
  218        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  219    },
  220    scroll::{ScrollOffset, ScrollPixelOffset},
  221    selections_collection::resolve_selections_wrapping_blocks,
  222    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  223};
  224
  225pub const FILE_HEADER_HEIGHT: u32 = 2;
  226pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  227const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  228const MAX_LINE_LEN: usize = 1024;
  229const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  230const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  231pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  232#[doc(hidden)]
  233pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  234pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  235
  236pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  237pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  238pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  239pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  240
  241pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  242pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  243pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  244
  245pub type RenderDiffHunkControlsFn = Arc<
  246    dyn Fn(
  247        u32,
  248        &DiffHunkStatus,
  249        Range<Anchor>,
  250        bool,
  251        Pixels,
  252        &Entity<Editor>,
  253        &mut Window,
  254        &mut App,
  255    ) -> AnyElement,
  256>;
  257
  258enum ReportEditorEvent {
  259    Saved { auto_saved: bool },
  260    EditorOpened,
  261    Closed,
  262}
  263
  264impl ReportEditorEvent {
  265    pub fn event_type(&self) -> &'static str {
  266        match self {
  267            Self::Saved { .. } => "Editor Saved",
  268            Self::EditorOpened => "Editor Opened",
  269            Self::Closed => "Editor Closed",
  270        }
  271    }
  272}
  273
  274pub enum ActiveDebugLine {}
  275pub enum DebugStackFrameLine {}
  276enum DocumentHighlightRead {}
  277enum DocumentHighlightWrite {}
  278enum InputComposition {}
  279pub enum PendingInput {}
  280enum SelectedTextHighlight {}
  281
  282pub enum ConflictsOuter {}
  283pub enum ConflictsOurs {}
  284pub enum ConflictsTheirs {}
  285pub enum ConflictsOursMarker {}
  286pub enum ConflictsTheirsMarker {}
  287
  288pub struct HunkAddedColor;
  289pub struct HunkRemovedColor;
  290
  291#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  292pub enum Navigated {
  293    Yes,
  294    No,
  295}
  296
  297impl Navigated {
  298    pub fn from_bool(yes: bool) -> Navigated {
  299        if yes { Navigated::Yes } else { Navigated::No }
  300    }
  301}
  302
  303#[derive(Debug, Clone, PartialEq, Eq)]
  304enum DisplayDiffHunk {
  305    Folded {
  306        display_row: DisplayRow,
  307    },
  308    Unfolded {
  309        is_created_file: bool,
  310        diff_base_byte_range: Range<usize>,
  311        display_row_range: Range<DisplayRow>,
  312        multi_buffer_range: Range<Anchor>,
  313        status: DiffHunkStatus,
  314        word_diffs: Vec<Range<MultiBufferOffset>>,
  315    },
  316}
  317
  318pub enum HideMouseCursorOrigin {
  319    TypingAction,
  320    MovementAction,
  321}
  322
  323pub fn init(cx: &mut App) {
  324    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  325
  326    workspace::register_project_item::<Editor>(cx);
  327    workspace::FollowableViewRegistry::register::<Editor>(cx);
  328    workspace::register_serializable_item::<Editor>(cx);
  329
  330    cx.observe_new(
  331        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  332            workspace.register_action(Editor::new_file);
  333            workspace.register_action(Editor::new_file_split);
  334            workspace.register_action(Editor::new_file_vertical);
  335            workspace.register_action(Editor::new_file_horizontal);
  336            workspace.register_action(Editor::cancel_language_server_work);
  337            workspace.register_action(Editor::toggle_focus);
  338        },
  339    )
  340    .detach();
  341
  342    cx.on_action(move |_: &workspace::NewFile, cx| {
  343        let app_state = workspace::AppState::global(cx);
  344        if let Some(app_state) = app_state.upgrade() {
  345            workspace::open_new(
  346                Default::default(),
  347                app_state,
  348                cx,
  349                |workspace, window, cx| {
  350                    Editor::new_file(workspace, &Default::default(), window, cx)
  351                },
  352            )
  353            .detach();
  354        }
  355    })
  356    .on_action(move |_: &workspace::NewWindow, cx| {
  357        let app_state = workspace::AppState::global(cx);
  358        if let Some(app_state) = app_state.upgrade() {
  359            workspace::open_new(
  360                Default::default(),
  361                app_state,
  362                cx,
  363                |workspace, window, cx| {
  364                    cx.activate(true);
  365                    Editor::new_file(workspace, &Default::default(), window, cx)
  366                },
  367            )
  368            .detach();
  369        }
  370    });
  371}
  372
  373pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  374    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  375}
  376
  377pub trait DiagnosticRenderer {
  378    fn render_group(
  379        &self,
  380        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  381        buffer_id: BufferId,
  382        snapshot: EditorSnapshot,
  383        editor: WeakEntity<Editor>,
  384        language_registry: Option<Arc<LanguageRegistry>>,
  385        cx: &mut App,
  386    ) -> Vec<BlockProperties<Anchor>>;
  387
  388    fn render_hover(
  389        &self,
  390        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  391        range: Range<Point>,
  392        buffer_id: BufferId,
  393        language_registry: Option<Arc<LanguageRegistry>>,
  394        cx: &mut App,
  395    ) -> Option<Entity<markdown::Markdown>>;
  396
  397    fn open_link(
  398        &self,
  399        editor: &mut Editor,
  400        link: SharedString,
  401        window: &mut Window,
  402        cx: &mut Context<Editor>,
  403    );
  404}
  405
  406pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  407
  408impl GlobalDiagnosticRenderer {
  409    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  410        cx.try_global::<Self>().map(|g| g.0.clone())
  411    }
  412}
  413
  414impl gpui::Global for GlobalDiagnosticRenderer {}
  415pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  416    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  417}
  418
  419pub struct SearchWithinRange;
  420
  421trait InvalidationRegion {
  422    fn ranges(&self) -> &[Range<Anchor>];
  423}
  424
  425#[derive(Clone, Debug, PartialEq)]
  426pub enum SelectPhase {
  427    Begin {
  428        position: DisplayPoint,
  429        add: bool,
  430        click_count: usize,
  431    },
  432    BeginColumnar {
  433        position: DisplayPoint,
  434        reset: bool,
  435        mode: ColumnarMode,
  436        goal_column: u32,
  437    },
  438    Extend {
  439        position: DisplayPoint,
  440        click_count: usize,
  441    },
  442    Update {
  443        position: DisplayPoint,
  444        goal_column: u32,
  445        scroll_delta: gpui::Point<f32>,
  446    },
  447    End,
  448}
  449
  450#[derive(Clone, Debug, PartialEq)]
  451pub enum ColumnarMode {
  452    FromMouse,
  453    FromSelection,
  454}
  455
  456#[derive(Clone, Debug)]
  457pub enum SelectMode {
  458    Character,
  459    Word(Range<Anchor>),
  460    Line(Range<Anchor>),
  461    All,
  462}
  463
  464#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  465pub enum SizingBehavior {
  466    /// The editor will layout itself using `size_full` and will include the vertical
  467    /// scroll margin as requested by user settings.
  468    #[default]
  469    Default,
  470    /// The editor will layout itself using `size_full`, but will not have any
  471    /// vertical overscroll.
  472    ExcludeOverscrollMargin,
  473    /// The editor will request a vertical size according to its content and will be
  474    /// layouted without a vertical scroll margin.
  475    SizeByContent,
  476}
  477
  478#[derive(Clone, PartialEq, Eq, Debug)]
  479pub enum EditorMode {
  480    SingleLine,
  481    AutoHeight {
  482        min_lines: usize,
  483        max_lines: Option<usize>,
  484    },
  485    Full {
  486        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  487        scale_ui_elements_with_buffer_font_size: bool,
  488        /// When set to `true`, the editor will render a background for the active line.
  489        show_active_line_background: bool,
  490        /// Determines the sizing behavior for this editor
  491        sizing_behavior: SizingBehavior,
  492    },
  493    Minimap {
  494        parent: WeakEntity<Editor>,
  495    },
  496}
  497
  498impl EditorMode {
  499    pub fn full() -> Self {
  500        Self::Full {
  501            scale_ui_elements_with_buffer_font_size: true,
  502            show_active_line_background: true,
  503            sizing_behavior: SizingBehavior::Default,
  504        }
  505    }
  506
  507    #[inline]
  508    pub fn is_full(&self) -> bool {
  509        matches!(self, Self::Full { .. })
  510    }
  511
  512    #[inline]
  513    pub fn is_single_line(&self) -> bool {
  514        matches!(self, Self::SingleLine { .. })
  515    }
  516
  517    #[inline]
  518    fn is_minimap(&self) -> bool {
  519        matches!(self, Self::Minimap { .. })
  520    }
  521}
  522
  523#[derive(Copy, Clone, Debug)]
  524pub enum SoftWrap {
  525    /// Prefer not to wrap at all.
  526    ///
  527    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  528    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  529    GitDiff,
  530    /// Prefer a single line generally, unless an overly long line is encountered.
  531    None,
  532    /// Soft wrap lines that exceed the editor width.
  533    EditorWidth,
  534    /// Soft wrap lines at the preferred line length.
  535    Column(u32),
  536    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  537    Bounded(u32),
  538}
  539
  540#[derive(Clone)]
  541pub struct EditorStyle {
  542    pub background: Hsla,
  543    pub border: Hsla,
  544    pub local_player: PlayerColor,
  545    pub text: TextStyle,
  546    pub scrollbar_width: Pixels,
  547    pub syntax: Arc<SyntaxTheme>,
  548    pub status: StatusColors,
  549    pub inlay_hints_style: HighlightStyle,
  550    pub edit_prediction_styles: EditPredictionStyles,
  551    pub unnecessary_code_fade: f32,
  552    pub show_underlines: bool,
  553}
  554
  555impl Default for EditorStyle {
  556    fn default() -> Self {
  557        Self {
  558            background: Hsla::default(),
  559            border: Hsla::default(),
  560            local_player: PlayerColor::default(),
  561            text: TextStyle::default(),
  562            scrollbar_width: Pixels::default(),
  563            syntax: Default::default(),
  564            // HACK: Status colors don't have a real default.
  565            // We should look into removing the status colors from the editor
  566            // style and retrieve them directly from the theme.
  567            status: StatusColors::dark(),
  568            inlay_hints_style: HighlightStyle::default(),
  569            edit_prediction_styles: EditPredictionStyles {
  570                insertion: HighlightStyle::default(),
  571                whitespace: HighlightStyle::default(),
  572            },
  573            unnecessary_code_fade: Default::default(),
  574            show_underlines: true,
  575        }
  576    }
  577}
  578
  579pub fn make_inlay_hints_style(cx: &App) -> HighlightStyle {
  580    let show_background = language_settings::language_settings(None, None, cx)
  581        .inlay_hints
  582        .show_background;
  583
  584    let mut style = cx.theme().syntax().get("hint");
  585
  586    if style.color.is_none() {
  587        style.color = Some(cx.theme().status().hint);
  588    }
  589
  590    if !show_background {
  591        style.background_color = None;
  592        return style;
  593    }
  594
  595    if style.background_color.is_none() {
  596        style.background_color = Some(cx.theme().status().hint_background);
  597    }
  598
  599    style
  600}
  601
  602pub fn make_suggestion_styles(cx: &App) -> EditPredictionStyles {
  603    EditPredictionStyles {
  604        insertion: HighlightStyle {
  605            color: Some(cx.theme().status().predictive),
  606            ..HighlightStyle::default()
  607        },
  608        whitespace: HighlightStyle {
  609            background_color: Some(cx.theme().status().created_background),
  610            ..HighlightStyle::default()
  611        },
  612    }
  613}
  614
  615type CompletionId = usize;
  616
  617pub(crate) enum EditDisplayMode {
  618    TabAccept,
  619    DiffPopover,
  620    Inline,
  621}
  622
  623enum EditPrediction {
  624    Edit {
  625        edits: Vec<(Range<Anchor>, Arc<str>)>,
  626        edit_preview: Option<EditPreview>,
  627        display_mode: EditDisplayMode,
  628        snapshot: BufferSnapshot,
  629    },
  630    /// Move to a specific location in the active editor
  631    MoveWithin {
  632        target: Anchor,
  633        snapshot: BufferSnapshot,
  634    },
  635    /// Move to a specific location in a different editor (not the active one)
  636    MoveOutside {
  637        target: language::Anchor,
  638        snapshot: BufferSnapshot,
  639    },
  640}
  641
  642struct EditPredictionState {
  643    inlay_ids: Vec<InlayId>,
  644    completion: EditPrediction,
  645    completion_id: Option<SharedString>,
  646    invalidation_range: Option<Range<Anchor>>,
  647}
  648
  649enum EditPredictionSettings {
  650    Disabled,
  651    Enabled {
  652        show_in_menu: bool,
  653        preview_requires_modifier: bool,
  654    },
  655}
  656
  657enum EditPredictionHighlight {}
  658
  659#[derive(Debug, Clone)]
  660struct InlineDiagnostic {
  661    message: SharedString,
  662    group_id: usize,
  663    is_primary: bool,
  664    start: Point,
  665    severity: lsp::DiagnosticSeverity,
  666}
  667
  668pub enum MenuEditPredictionsPolicy {
  669    Never,
  670    ByProvider,
  671}
  672
  673pub enum EditPredictionPreview {
  674    /// Modifier is not pressed
  675    Inactive { released_too_fast: bool },
  676    /// Modifier pressed
  677    Active {
  678        since: Instant,
  679        previous_scroll_position: Option<ScrollAnchor>,
  680    },
  681}
  682
  683impl EditPredictionPreview {
  684    pub fn released_too_fast(&self) -> bool {
  685        match self {
  686            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  687            EditPredictionPreview::Active { .. } => false,
  688        }
  689    }
  690
  691    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  692        if let EditPredictionPreview::Active {
  693            previous_scroll_position,
  694            ..
  695        } = self
  696        {
  697            *previous_scroll_position = scroll_position;
  698        }
  699    }
  700}
  701
  702pub struct ContextMenuOptions {
  703    pub min_entries_visible: usize,
  704    pub max_entries_visible: usize,
  705    pub placement: Option<ContextMenuPlacement>,
  706}
  707
  708#[derive(Debug, Clone, PartialEq, Eq)]
  709pub enum ContextMenuPlacement {
  710    Above,
  711    Below,
  712}
  713
  714#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  715struct EditorActionId(usize);
  716
  717impl EditorActionId {
  718    pub fn post_inc(&mut self) -> Self {
  719        let answer = self.0;
  720
  721        *self = Self(answer + 1);
  722
  723        Self(answer)
  724    }
  725}
  726
  727// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  728// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  729
  730type BackgroundHighlight = (
  731    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  732    Arc<[Range<Anchor>]>,
  733);
  734type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  735
  736#[derive(Default)]
  737struct ScrollbarMarkerState {
  738    scrollbar_size: Size<Pixels>,
  739    dirty: bool,
  740    markers: Arc<[PaintQuad]>,
  741    pending_refresh: Option<Task<Result<()>>>,
  742}
  743
  744impl ScrollbarMarkerState {
  745    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  746        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  747    }
  748}
  749
  750#[derive(Clone, Copy, PartialEq, Eq)]
  751pub enum MinimapVisibility {
  752    Disabled,
  753    Enabled {
  754        /// The configuration currently present in the users settings.
  755        setting_configuration: bool,
  756        /// Whether to override the currently set visibility from the users setting.
  757        toggle_override: bool,
  758    },
  759}
  760
  761impl MinimapVisibility {
  762    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  763        if mode.is_full() {
  764            Self::Enabled {
  765                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  766                toggle_override: false,
  767            }
  768        } else {
  769            Self::Disabled
  770        }
  771    }
  772
  773    fn hidden(&self) -> Self {
  774        match *self {
  775            Self::Enabled {
  776                setting_configuration,
  777                ..
  778            } => Self::Enabled {
  779                setting_configuration,
  780                toggle_override: setting_configuration,
  781            },
  782            Self::Disabled => Self::Disabled,
  783        }
  784    }
  785
  786    fn disabled(&self) -> bool {
  787        matches!(*self, Self::Disabled)
  788    }
  789
  790    fn settings_visibility(&self) -> bool {
  791        match *self {
  792            Self::Enabled {
  793                setting_configuration,
  794                ..
  795            } => setting_configuration,
  796            _ => false,
  797        }
  798    }
  799
  800    fn visible(&self) -> bool {
  801        match *self {
  802            Self::Enabled {
  803                setting_configuration,
  804                toggle_override,
  805            } => setting_configuration ^ toggle_override,
  806            _ => false,
  807        }
  808    }
  809
  810    fn toggle_visibility(&self) -> Self {
  811        match *self {
  812            Self::Enabled {
  813                toggle_override,
  814                setting_configuration,
  815            } => Self::Enabled {
  816                setting_configuration,
  817                toggle_override: !toggle_override,
  818            },
  819            Self::Disabled => Self::Disabled,
  820        }
  821    }
  822}
  823
  824#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  825pub enum BufferSerialization {
  826    All,
  827    NonDirtyBuffers,
  828}
  829
  830impl BufferSerialization {
  831    fn new(restore_unsaved_buffers: bool) -> Self {
  832        if restore_unsaved_buffers {
  833            Self::All
  834        } else {
  835            Self::NonDirtyBuffers
  836        }
  837    }
  838}
  839
  840#[derive(Clone, Debug)]
  841struct RunnableTasks {
  842    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  843    offset: multi_buffer::Anchor,
  844    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  845    column: u32,
  846    // Values of all named captures, including those starting with '_'
  847    extra_variables: HashMap<String, String>,
  848    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  849    context_range: Range<BufferOffset>,
  850}
  851
  852impl RunnableTasks {
  853    fn resolve<'a>(
  854        &'a self,
  855        cx: &'a task::TaskContext,
  856    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  857        self.templates.iter().filter_map(|(kind, template)| {
  858            template
  859                .resolve_task(&kind.to_id_base(), cx)
  860                .map(|task| (kind.clone(), task))
  861        })
  862    }
  863}
  864
  865#[derive(Clone)]
  866pub struct ResolvedTasks {
  867    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  868    position: Anchor,
  869}
  870
  871/// Addons allow storing per-editor state in other crates (e.g. Vim)
  872pub trait Addon: 'static {
  873    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  874
  875    fn render_buffer_header_controls(
  876        &self,
  877        _: &ExcerptInfo,
  878        _: &Window,
  879        _: &App,
  880    ) -> Option<AnyElement> {
  881        None
  882    }
  883
  884    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  885        None
  886    }
  887
  888    fn to_any(&self) -> &dyn std::any::Any;
  889
  890    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  891        None
  892    }
  893}
  894
  895struct ChangeLocation {
  896    current: Option<Vec<Anchor>>,
  897    original: Vec<Anchor>,
  898}
  899impl ChangeLocation {
  900    fn locations(&self) -> &[Anchor] {
  901        self.current.as_ref().unwrap_or(&self.original)
  902    }
  903}
  904
  905/// A set of caret positions, registered when the editor was edited.
  906pub struct ChangeList {
  907    changes: Vec<ChangeLocation>,
  908    /// Currently "selected" change.
  909    position: Option<usize>,
  910}
  911
  912impl ChangeList {
  913    pub fn new() -> Self {
  914        Self {
  915            changes: Vec::new(),
  916            position: None,
  917        }
  918    }
  919
  920    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  921    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  922    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  923        if self.changes.is_empty() {
  924            return None;
  925        }
  926
  927        let prev = self.position.unwrap_or(self.changes.len());
  928        let next = if direction == Direction::Prev {
  929            prev.saturating_sub(count)
  930        } else {
  931            (prev + count).min(self.changes.len() - 1)
  932        };
  933        self.position = Some(next);
  934        self.changes.get(next).map(|change| change.locations())
  935    }
  936
  937    /// Adds a new change to the list, resetting the change list position.
  938    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  939        self.position.take();
  940        if let Some(last) = self.changes.last_mut()
  941            && group
  942        {
  943            last.current = Some(new_positions)
  944        } else {
  945            self.changes.push(ChangeLocation {
  946                original: new_positions,
  947                current: None,
  948            });
  949        }
  950    }
  951
  952    pub fn last(&self) -> Option<&[Anchor]> {
  953        self.changes.last().map(|change| change.locations())
  954    }
  955
  956    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  957        self.changes.last().map(|change| change.original.as_slice())
  958    }
  959
  960    pub fn invert_last_group(&mut self) {
  961        if let Some(last) = self.changes.last_mut()
  962            && let Some(current) = last.current.as_mut()
  963        {
  964            mem::swap(&mut last.original, current);
  965        }
  966    }
  967}
  968
  969#[derive(Clone)]
  970struct InlineBlamePopoverState {
  971    scroll_handle: ScrollHandle,
  972    commit_message: Option<ParsedCommitMessage>,
  973    markdown: Entity<Markdown>,
  974}
  975
  976struct InlineBlamePopover {
  977    position: gpui::Point<Pixels>,
  978    hide_task: Option<Task<()>>,
  979    popover_bounds: Option<Bounds<Pixels>>,
  980    popover_state: InlineBlamePopoverState,
  981    keyboard_grace: bool,
  982}
  983
  984enum SelectionDragState {
  985    /// State when no drag related activity is detected.
  986    None,
  987    /// State when the mouse is down on a selection that is about to be dragged.
  988    ReadyToDrag {
  989        selection: Selection<Anchor>,
  990        click_position: gpui::Point<Pixels>,
  991        mouse_down_time: Instant,
  992    },
  993    /// State when the mouse is dragging the selection in the editor.
  994    Dragging {
  995        selection: Selection<Anchor>,
  996        drop_cursor: Selection<Anchor>,
  997        hide_drop_cursor: bool,
  998    },
  999}
 1000
 1001enum ColumnarSelectionState {
 1002    FromMouse {
 1003        selection_tail: Anchor,
 1004        display_point: Option<DisplayPoint>,
 1005    },
 1006    FromSelection {
 1007        selection_tail: Anchor,
 1008    },
 1009}
 1010
 1011/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1012/// a breakpoint on them.
 1013#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1014struct PhantomBreakpointIndicator {
 1015    display_row: DisplayRow,
 1016    /// There's a small debounce between hovering over the line and showing the indicator.
 1017    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1018    is_active: bool,
 1019    collides_with_existing_breakpoint: bool,
 1020}
 1021
 1022/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1023///
 1024/// See the [module level documentation](self) for more information.
 1025pub struct Editor {
 1026    focus_handle: FocusHandle,
 1027    last_focused_descendant: Option<WeakFocusHandle>,
 1028    /// The text buffer being edited
 1029    buffer: Entity<MultiBuffer>,
 1030    /// Map of how text in the buffer should be displayed.
 1031    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1032    pub display_map: Entity<DisplayMap>,
 1033    placeholder_display_map: Option<Entity<DisplayMap>>,
 1034    pub selections: SelectionsCollection,
 1035    pub scroll_manager: ScrollManager,
 1036    /// When inline assist editors are linked, they all render cursors because
 1037    /// typing enters text into each of them, even the ones that aren't focused.
 1038    pub(crate) show_cursor_when_unfocused: bool,
 1039    columnar_selection_state: Option<ColumnarSelectionState>,
 1040    add_selections_state: Option<AddSelectionsState>,
 1041    select_next_state: Option<SelectNextState>,
 1042    select_prev_state: Option<SelectNextState>,
 1043    selection_history: SelectionHistory,
 1044    defer_selection_effects: bool,
 1045    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1046    autoclose_regions: Vec<AutocloseRegion>,
 1047    snippet_stack: InvalidationStack<SnippetState>,
 1048    select_syntax_node_history: SelectSyntaxNodeHistory,
 1049    ime_transaction: Option<TransactionId>,
 1050    pub diagnostics_max_severity: DiagnosticSeverity,
 1051    active_diagnostics: ActiveDiagnostic,
 1052    show_inline_diagnostics: bool,
 1053    inline_diagnostics_update: Task<()>,
 1054    inline_diagnostics_enabled: bool,
 1055    diagnostics_enabled: bool,
 1056    word_completions_enabled: bool,
 1057    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1058    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1059    hard_wrap: Option<usize>,
 1060    project: Option<Entity<Project>>,
 1061    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1062    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1063    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1064    blink_manager: Entity<BlinkManager>,
 1065    show_cursor_names: bool,
 1066    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1067    pub show_local_selections: bool,
 1068    mode: EditorMode,
 1069    show_breadcrumbs: bool,
 1070    show_gutter: bool,
 1071    show_scrollbars: ScrollbarAxes,
 1072    minimap_visibility: MinimapVisibility,
 1073    offset_content: bool,
 1074    disable_expand_excerpt_buttons: bool,
 1075    show_line_numbers: Option<bool>,
 1076    use_relative_line_numbers: Option<bool>,
 1077    show_git_diff_gutter: Option<bool>,
 1078    show_code_actions: Option<bool>,
 1079    show_runnables: Option<bool>,
 1080    show_breakpoints: Option<bool>,
 1081    show_wrap_guides: Option<bool>,
 1082    show_indent_guides: Option<bool>,
 1083    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1084    highlight_order: usize,
 1085    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1086    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1087    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1088    scrollbar_marker_state: ScrollbarMarkerState,
 1089    active_indent_guides_state: ActiveIndentGuidesState,
 1090    nav_history: Option<ItemNavHistory>,
 1091    context_menu: RefCell<Option<CodeContextMenu>>,
 1092    context_menu_options: Option<ContextMenuOptions>,
 1093    mouse_context_menu: Option<MouseContextMenu>,
 1094    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1095    inline_blame_popover: Option<InlineBlamePopover>,
 1096    inline_blame_popover_show_task: Option<Task<()>>,
 1097    signature_help_state: SignatureHelpState,
 1098    auto_signature_help: Option<bool>,
 1099    find_all_references_task_sources: Vec<Anchor>,
 1100    next_completion_id: CompletionId,
 1101    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1102    code_actions_task: Option<Task<Result<()>>>,
 1103    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1104    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1105    document_highlights_task: Option<Task<()>>,
 1106    linked_editing_range_task: Option<Task<Option<()>>>,
 1107    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1108    pending_rename: Option<RenameState>,
 1109    searchable: bool,
 1110    cursor_shape: CursorShape,
 1111    /// Whether the cursor is offset one character to the left when something is
 1112    /// selected (needed for vim visual mode)
 1113    cursor_offset_on_selection: bool,
 1114    current_line_highlight: Option<CurrentLineHighlight>,
 1115    pub collapse_matches: bool,
 1116    autoindent_mode: Option<AutoindentMode>,
 1117    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1118    input_enabled: bool,
 1119    use_modal_editing: bool,
 1120    read_only: bool,
 1121    leader_id: Option<CollaboratorId>,
 1122    remote_id: Option<ViewId>,
 1123    pub hover_state: HoverState,
 1124    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1125    prev_pressure_stage: Option<PressureStage>,
 1126    gutter_hovered: bool,
 1127    hovered_link_state: Option<HoveredLinkState>,
 1128    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1129    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1130    active_edit_prediction: Option<EditPredictionState>,
 1131    /// Used to prevent flickering as the user types while the menu is open
 1132    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1133    edit_prediction_settings: EditPredictionSettings,
 1134    edit_predictions_hidden_for_vim_mode: bool,
 1135    show_edit_predictions_override: Option<bool>,
 1136    show_completions_on_input_override: Option<bool>,
 1137    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1138    edit_prediction_preview: EditPredictionPreview,
 1139    edit_prediction_indent_conflict: bool,
 1140    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1141    next_inlay_id: usize,
 1142    next_color_inlay_id: usize,
 1143    _subscriptions: Vec<Subscription>,
 1144    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1145    gutter_dimensions: GutterDimensions,
 1146    style: Option<EditorStyle>,
 1147    text_style_refinement: Option<TextStyleRefinement>,
 1148    next_editor_action_id: EditorActionId,
 1149    editor_actions: Rc<
 1150        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1151    >,
 1152    use_autoclose: bool,
 1153    use_auto_surround: bool,
 1154    auto_replace_emoji_shortcode: bool,
 1155    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1156    show_git_blame_gutter: bool,
 1157    show_git_blame_inline: bool,
 1158    show_git_blame_inline_delay_task: Option<Task<()>>,
 1159    git_blame_inline_enabled: bool,
 1160    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1161    buffer_serialization: Option<BufferSerialization>,
 1162    show_selection_menu: Option<bool>,
 1163    blame: Option<Entity<GitBlame>>,
 1164    blame_subscription: Option<Subscription>,
 1165    custom_context_menu: Option<
 1166        Box<
 1167            dyn 'static
 1168                + Fn(
 1169                    &mut Self,
 1170                    DisplayPoint,
 1171                    &mut Window,
 1172                    &mut Context<Self>,
 1173                ) -> Option<Entity<ui::ContextMenu>>,
 1174        >,
 1175    >,
 1176    last_bounds: Option<Bounds<Pixels>>,
 1177    last_position_map: Option<Rc<PositionMap>>,
 1178    expect_bounds_change: Option<Bounds<Pixels>>,
 1179    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1180    tasks_update_task: Option<Task<()>>,
 1181    breakpoint_store: Option<Entity<BreakpointStore>>,
 1182    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1183    hovered_diff_hunk_row: Option<DisplayRow>,
 1184    pull_diagnostics_task: Task<()>,
 1185    pull_diagnostics_background_task: Task<()>,
 1186    in_project_search: bool,
 1187    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1188    breadcrumb_header: Option<String>,
 1189    focused_block: Option<FocusedBlock>,
 1190    next_scroll_position: NextScrollCursorCenterTopBottom,
 1191    addons: HashMap<TypeId, Box<dyn Addon>>,
 1192    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1193    load_diff_task: Option<Shared<Task<()>>>,
 1194    /// Whether we are temporarily displaying a diff other than git's
 1195    temporary_diff_override: bool,
 1196    selection_mark_mode: bool,
 1197    toggle_fold_multiple_buffers: Task<()>,
 1198    _scroll_cursor_center_top_bottom_task: Task<()>,
 1199    serialize_selections: Task<()>,
 1200    serialize_folds: Task<()>,
 1201    mouse_cursor_hidden: bool,
 1202    minimap: Option<Entity<Self>>,
 1203    hide_mouse_mode: HideMouseMode,
 1204    pub change_list: ChangeList,
 1205    inline_value_cache: InlineValueCache,
 1206
 1207    selection_drag_state: SelectionDragState,
 1208    colors: Option<LspColorData>,
 1209    post_scroll_update: Task<()>,
 1210    refresh_colors_task: Task<()>,
 1211    inlay_hints: Option<LspInlayHintData>,
 1212    folding_newlines: Task<()>,
 1213    select_next_is_case_sensitive: Option<bool>,
 1214    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1215    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1216    accent_data: Option<AccentData>,
 1217    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1218    use_base_text_line_numbers: bool,
 1219}
 1220
 1221#[derive(Debug, PartialEq)]
 1222struct AccentData {
 1223    colors: AccentColors,
 1224    overrides: Vec<SharedString>,
 1225}
 1226
 1227fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1228    if debounce_ms > 0 {
 1229        Some(Duration::from_millis(debounce_ms))
 1230    } else {
 1231        None
 1232    }
 1233}
 1234
 1235#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1236enum NextScrollCursorCenterTopBottom {
 1237    #[default]
 1238    Center,
 1239    Top,
 1240    Bottom,
 1241}
 1242
 1243impl NextScrollCursorCenterTopBottom {
 1244    fn next(&self) -> Self {
 1245        match self {
 1246            Self::Center => Self::Top,
 1247            Self::Top => Self::Bottom,
 1248            Self::Bottom => Self::Center,
 1249        }
 1250    }
 1251}
 1252
 1253#[derive(Clone)]
 1254pub struct EditorSnapshot {
 1255    pub mode: EditorMode,
 1256    show_gutter: bool,
 1257    offset_content: bool,
 1258    show_line_numbers: Option<bool>,
 1259    show_git_diff_gutter: Option<bool>,
 1260    show_code_actions: Option<bool>,
 1261    show_runnables: Option<bool>,
 1262    show_breakpoints: Option<bool>,
 1263    git_blame_gutter_max_author_length: Option<usize>,
 1264    pub display_snapshot: DisplaySnapshot,
 1265    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1266    is_focused: bool,
 1267    scroll_anchor: ScrollAnchor,
 1268    ongoing_scroll: OngoingScroll,
 1269    current_line_highlight: CurrentLineHighlight,
 1270    gutter_hovered: bool,
 1271}
 1272
 1273#[derive(Default, Debug, Clone, Copy)]
 1274pub struct GutterDimensions {
 1275    pub left_padding: Pixels,
 1276    pub right_padding: Pixels,
 1277    pub width: Pixels,
 1278    pub margin: Pixels,
 1279    pub git_blame_entries_width: Option<Pixels>,
 1280}
 1281
 1282impl GutterDimensions {
 1283    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1284        Self {
 1285            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1286            ..Default::default()
 1287        }
 1288    }
 1289
 1290    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1291        -cx.text_system().descent(font_id, font_size)
 1292    }
 1293    /// The full width of the space taken up by the gutter.
 1294    pub fn full_width(&self) -> Pixels {
 1295        self.margin + self.width
 1296    }
 1297
 1298    /// The width of the space reserved for the fold indicators,
 1299    /// use alongside 'justify_end' and `gutter_width` to
 1300    /// right align content with the line numbers
 1301    pub fn fold_area_width(&self) -> Pixels {
 1302        self.margin + self.right_padding
 1303    }
 1304}
 1305
 1306struct CharacterDimensions {
 1307    em_width: Pixels,
 1308    em_advance: Pixels,
 1309    line_height: Pixels,
 1310}
 1311
 1312#[derive(Debug)]
 1313pub struct RemoteSelection {
 1314    pub replica_id: ReplicaId,
 1315    pub selection: Selection<Anchor>,
 1316    pub cursor_shape: CursorShape,
 1317    pub collaborator_id: CollaboratorId,
 1318    pub line_mode: bool,
 1319    pub user_name: Option<SharedString>,
 1320    pub color: PlayerColor,
 1321}
 1322
 1323#[derive(Clone, Debug)]
 1324struct SelectionHistoryEntry {
 1325    selections: Arc<[Selection<Anchor>]>,
 1326    select_next_state: Option<SelectNextState>,
 1327    select_prev_state: Option<SelectNextState>,
 1328    add_selections_state: Option<AddSelectionsState>,
 1329}
 1330
 1331#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1332enum SelectionHistoryMode {
 1333    #[default]
 1334    Normal,
 1335    Undoing,
 1336    Redoing,
 1337    Skipping,
 1338}
 1339
 1340#[derive(Clone, PartialEq, Eq, Hash)]
 1341struct HoveredCursor {
 1342    replica_id: ReplicaId,
 1343    selection_id: usize,
 1344}
 1345
 1346#[derive(Debug)]
 1347/// SelectionEffects controls the side-effects of updating the selection.
 1348///
 1349/// The default behaviour does "what you mostly want":
 1350/// - it pushes to the nav history if the cursor moved by >10 lines
 1351/// - it re-triggers completion requests
 1352/// - it scrolls to fit
 1353///
 1354/// You might want to modify these behaviours. For example when doing a "jump"
 1355/// like go to definition, we always want to add to nav history; but when scrolling
 1356/// in vim mode we never do.
 1357///
 1358/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1359/// move.
 1360#[derive(Clone)]
 1361pub struct SelectionEffects {
 1362    nav_history: Option<bool>,
 1363    completions: bool,
 1364    scroll: Option<Autoscroll>,
 1365}
 1366
 1367impl Default for SelectionEffects {
 1368    fn default() -> Self {
 1369        Self {
 1370            nav_history: None,
 1371            completions: true,
 1372            scroll: Some(Autoscroll::fit()),
 1373        }
 1374    }
 1375}
 1376impl SelectionEffects {
 1377    pub fn scroll(scroll: Autoscroll) -> Self {
 1378        Self {
 1379            scroll: Some(scroll),
 1380            ..Default::default()
 1381        }
 1382    }
 1383
 1384    pub fn no_scroll() -> Self {
 1385        Self {
 1386            scroll: None,
 1387            ..Default::default()
 1388        }
 1389    }
 1390
 1391    pub fn completions(self, completions: bool) -> Self {
 1392        Self {
 1393            completions,
 1394            ..self
 1395        }
 1396    }
 1397
 1398    pub fn nav_history(self, nav_history: bool) -> Self {
 1399        Self {
 1400            nav_history: Some(nav_history),
 1401            ..self
 1402        }
 1403    }
 1404}
 1405
 1406struct DeferredSelectionEffectsState {
 1407    changed: bool,
 1408    effects: SelectionEffects,
 1409    old_cursor_position: Anchor,
 1410    history_entry: SelectionHistoryEntry,
 1411}
 1412
 1413#[derive(Default)]
 1414struct SelectionHistory {
 1415    #[allow(clippy::type_complexity)]
 1416    selections_by_transaction:
 1417        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1418    mode: SelectionHistoryMode,
 1419    undo_stack: VecDeque<SelectionHistoryEntry>,
 1420    redo_stack: VecDeque<SelectionHistoryEntry>,
 1421}
 1422
 1423impl SelectionHistory {
 1424    #[track_caller]
 1425    fn insert_transaction(
 1426        &mut self,
 1427        transaction_id: TransactionId,
 1428        selections: Arc<[Selection<Anchor>]>,
 1429    ) {
 1430        if selections.is_empty() {
 1431            log::error!(
 1432                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1433                std::panic::Location::caller()
 1434            );
 1435            return;
 1436        }
 1437        self.selections_by_transaction
 1438            .insert(transaction_id, (selections, None));
 1439    }
 1440
 1441    #[allow(clippy::type_complexity)]
 1442    fn transaction(
 1443        &self,
 1444        transaction_id: TransactionId,
 1445    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1446        self.selections_by_transaction.get(&transaction_id)
 1447    }
 1448
 1449    #[allow(clippy::type_complexity)]
 1450    fn transaction_mut(
 1451        &mut self,
 1452        transaction_id: TransactionId,
 1453    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1454        self.selections_by_transaction.get_mut(&transaction_id)
 1455    }
 1456
 1457    fn push(&mut self, entry: SelectionHistoryEntry) {
 1458        if !entry.selections.is_empty() {
 1459            match self.mode {
 1460                SelectionHistoryMode::Normal => {
 1461                    self.push_undo(entry);
 1462                    self.redo_stack.clear();
 1463                }
 1464                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1465                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1466                SelectionHistoryMode::Skipping => {}
 1467            }
 1468        }
 1469    }
 1470
 1471    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1472        if self
 1473            .undo_stack
 1474            .back()
 1475            .is_none_or(|e| e.selections != entry.selections)
 1476        {
 1477            self.undo_stack.push_back(entry);
 1478            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1479                self.undo_stack.pop_front();
 1480            }
 1481        }
 1482    }
 1483
 1484    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1485        if self
 1486            .redo_stack
 1487            .back()
 1488            .is_none_or(|e| e.selections != entry.selections)
 1489        {
 1490            self.redo_stack.push_back(entry);
 1491            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1492                self.redo_stack.pop_front();
 1493            }
 1494        }
 1495    }
 1496}
 1497
 1498#[derive(Clone, Copy)]
 1499pub struct RowHighlightOptions {
 1500    pub autoscroll: bool,
 1501    pub include_gutter: bool,
 1502}
 1503
 1504impl Default for RowHighlightOptions {
 1505    fn default() -> Self {
 1506        Self {
 1507            autoscroll: Default::default(),
 1508            include_gutter: true,
 1509        }
 1510    }
 1511}
 1512
 1513struct RowHighlight {
 1514    index: usize,
 1515    range: Range<Anchor>,
 1516    color: Hsla,
 1517    options: RowHighlightOptions,
 1518    type_id: TypeId,
 1519}
 1520
 1521#[derive(Clone, Debug)]
 1522struct AddSelectionsState {
 1523    groups: Vec<AddSelectionsGroup>,
 1524}
 1525
 1526#[derive(Clone, Debug)]
 1527struct AddSelectionsGroup {
 1528    above: bool,
 1529    stack: Vec<usize>,
 1530}
 1531
 1532#[derive(Clone)]
 1533struct SelectNextState {
 1534    query: AhoCorasick,
 1535    wordwise: bool,
 1536    done: bool,
 1537}
 1538
 1539impl std::fmt::Debug for SelectNextState {
 1540    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1541        f.debug_struct(std::any::type_name::<Self>())
 1542            .field("wordwise", &self.wordwise)
 1543            .field("done", &self.done)
 1544            .finish()
 1545    }
 1546}
 1547
 1548#[derive(Debug)]
 1549struct AutocloseRegion {
 1550    selection_id: usize,
 1551    range: Range<Anchor>,
 1552    pair: BracketPair,
 1553}
 1554
 1555#[derive(Debug)]
 1556struct SnippetState {
 1557    ranges: Vec<Vec<Range<Anchor>>>,
 1558    active_index: usize,
 1559    choices: Vec<Option<Vec<String>>>,
 1560}
 1561
 1562#[doc(hidden)]
 1563pub struct RenameState {
 1564    pub range: Range<Anchor>,
 1565    pub old_name: Arc<str>,
 1566    pub editor: Entity<Editor>,
 1567    block_id: CustomBlockId,
 1568}
 1569
 1570struct InvalidationStack<T>(Vec<T>);
 1571
 1572struct RegisteredEditPredictionDelegate {
 1573    provider: Arc<dyn EditPredictionDelegateHandle>,
 1574    _subscription: Subscription,
 1575}
 1576
 1577#[derive(Debug, PartialEq, Eq)]
 1578pub struct ActiveDiagnosticGroup {
 1579    pub active_range: Range<Anchor>,
 1580    pub active_message: String,
 1581    pub group_id: usize,
 1582    pub blocks: HashSet<CustomBlockId>,
 1583}
 1584
 1585#[derive(Debug, PartialEq, Eq)]
 1586
 1587pub(crate) enum ActiveDiagnostic {
 1588    None,
 1589    All,
 1590    Group(ActiveDiagnosticGroup),
 1591}
 1592
 1593#[derive(Serialize, Deserialize, Clone, Debug)]
 1594pub struct ClipboardSelection {
 1595    /// The number of bytes in this selection.
 1596    pub len: usize,
 1597    /// Whether this was a full-line selection.
 1598    pub is_entire_line: bool,
 1599    /// The indentation of the first line when this content was originally copied.
 1600    pub first_line_indent: u32,
 1601    #[serde(default)]
 1602    pub file_path: Option<PathBuf>,
 1603    #[serde(default)]
 1604    pub line_range: Option<RangeInclusive<u32>>,
 1605}
 1606
 1607impl ClipboardSelection {
 1608    pub fn for_buffer(
 1609        len: usize,
 1610        is_entire_line: bool,
 1611        range: Range<Point>,
 1612        buffer: &MultiBufferSnapshot,
 1613        project: Option<&Entity<Project>>,
 1614        cx: &App,
 1615    ) -> Self {
 1616        let first_line_indent = buffer
 1617            .indent_size_for_line(MultiBufferRow(range.start.row))
 1618            .len;
 1619
 1620        let file_path = util::maybe!({
 1621            let project = project?.read(cx);
 1622            let file = buffer.file_at(range.start)?;
 1623            let project_path = ProjectPath {
 1624                worktree_id: file.worktree_id(cx),
 1625                path: file.path().clone(),
 1626            };
 1627            project.absolute_path(&project_path, cx)
 1628        });
 1629
 1630        let line_range = file_path.as_ref().map(|_| range.start.row..=range.end.row);
 1631
 1632        Self {
 1633            len,
 1634            is_entire_line,
 1635            first_line_indent,
 1636            file_path,
 1637            line_range,
 1638        }
 1639    }
 1640}
 1641
 1642// selections, scroll behavior, was newest selection reversed
 1643type SelectSyntaxNodeHistoryState = (
 1644    Box<[Selection<MultiBufferOffset>]>,
 1645    SelectSyntaxNodeScrollBehavior,
 1646    bool,
 1647);
 1648
 1649#[derive(Default)]
 1650struct SelectSyntaxNodeHistory {
 1651    stack: Vec<SelectSyntaxNodeHistoryState>,
 1652    // disable temporarily to allow changing selections without losing the stack
 1653    pub disable_clearing: bool,
 1654}
 1655
 1656impl SelectSyntaxNodeHistory {
 1657    pub fn try_clear(&mut self) {
 1658        if !self.disable_clearing {
 1659            self.stack.clear();
 1660        }
 1661    }
 1662
 1663    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1664        self.stack.push(selection);
 1665    }
 1666
 1667    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1668        self.stack.pop()
 1669    }
 1670}
 1671
 1672enum SelectSyntaxNodeScrollBehavior {
 1673    CursorTop,
 1674    FitSelection,
 1675    CursorBottom,
 1676}
 1677
 1678#[derive(Debug)]
 1679pub(crate) struct NavigationData {
 1680    cursor_anchor: Anchor,
 1681    cursor_position: Point,
 1682    scroll_anchor: ScrollAnchor,
 1683    scroll_top_row: u32,
 1684}
 1685
 1686#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1687pub enum GotoDefinitionKind {
 1688    Symbol,
 1689    Declaration,
 1690    Type,
 1691    Implementation,
 1692}
 1693
 1694pub enum FormatTarget {
 1695    Buffers(HashSet<Entity<Buffer>>),
 1696    Ranges(Vec<Range<MultiBufferPoint>>),
 1697}
 1698
 1699pub(crate) struct FocusedBlock {
 1700    id: BlockId,
 1701    focus_handle: WeakFocusHandle,
 1702}
 1703
 1704#[derive(Clone, Debug)]
 1705enum JumpData {
 1706    MultiBufferRow {
 1707        row: MultiBufferRow,
 1708        line_offset_from_top: u32,
 1709    },
 1710    MultiBufferPoint {
 1711        excerpt_id: ExcerptId,
 1712        position: Point,
 1713        anchor: text::Anchor,
 1714        line_offset_from_top: u32,
 1715    },
 1716}
 1717
 1718pub enum MultibufferSelectionMode {
 1719    First,
 1720    All,
 1721}
 1722
 1723#[derive(Clone, Copy, Debug, Default)]
 1724pub struct RewrapOptions {
 1725    pub override_language_settings: bool,
 1726    pub preserve_existing_whitespace: bool,
 1727}
 1728
 1729impl Editor {
 1730    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1731        let buffer = cx.new(|cx| Buffer::local("", cx));
 1732        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1733        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1734    }
 1735
 1736    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1737        let buffer = cx.new(|cx| Buffer::local("", cx));
 1738        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1739        Self::new(EditorMode::full(), buffer, None, window, cx)
 1740    }
 1741
 1742    pub fn auto_height(
 1743        min_lines: usize,
 1744        max_lines: usize,
 1745        window: &mut Window,
 1746        cx: &mut Context<Self>,
 1747    ) -> Self {
 1748        let buffer = cx.new(|cx| Buffer::local("", cx));
 1749        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1750        Self::new(
 1751            EditorMode::AutoHeight {
 1752                min_lines,
 1753                max_lines: Some(max_lines),
 1754            },
 1755            buffer,
 1756            None,
 1757            window,
 1758            cx,
 1759        )
 1760    }
 1761
 1762    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1763    /// The editor grows as tall as needed to fit its content.
 1764    pub fn auto_height_unbounded(
 1765        min_lines: usize,
 1766        window: &mut Window,
 1767        cx: &mut Context<Self>,
 1768    ) -> Self {
 1769        let buffer = cx.new(|cx| Buffer::local("", cx));
 1770        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1771        Self::new(
 1772            EditorMode::AutoHeight {
 1773                min_lines,
 1774                max_lines: None,
 1775            },
 1776            buffer,
 1777            None,
 1778            window,
 1779            cx,
 1780        )
 1781    }
 1782
 1783    pub fn for_buffer(
 1784        buffer: Entity<Buffer>,
 1785        project: Option<Entity<Project>>,
 1786        window: &mut Window,
 1787        cx: &mut Context<Self>,
 1788    ) -> Self {
 1789        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1790        Self::new(EditorMode::full(), buffer, project, window, cx)
 1791    }
 1792
 1793    pub fn for_multibuffer(
 1794        buffer: Entity<MultiBuffer>,
 1795        project: Option<Entity<Project>>,
 1796        window: &mut Window,
 1797        cx: &mut Context<Self>,
 1798    ) -> Self {
 1799        Self::new(EditorMode::full(), buffer, project, window, cx)
 1800    }
 1801
 1802    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1803        let mut clone = Self::new(
 1804            self.mode.clone(),
 1805            self.buffer.clone(),
 1806            self.project.clone(),
 1807            window,
 1808            cx,
 1809        );
 1810        self.display_map.update(cx, |display_map, cx| {
 1811            let snapshot = display_map.snapshot(cx);
 1812            clone.display_map.update(cx, |display_map, cx| {
 1813                display_map.set_state(&snapshot, cx);
 1814            });
 1815        });
 1816        clone.folds_did_change(cx);
 1817        clone.selections.clone_state(&self.selections);
 1818        clone.scroll_manager.clone_state(&self.scroll_manager);
 1819        clone.searchable = self.searchable;
 1820        clone.read_only = self.read_only;
 1821        clone
 1822    }
 1823
 1824    pub fn new(
 1825        mode: EditorMode,
 1826        buffer: Entity<MultiBuffer>,
 1827        project: Option<Entity<Project>>,
 1828        window: &mut Window,
 1829        cx: &mut Context<Self>,
 1830    ) -> Self {
 1831        Editor::new_internal(mode, buffer, project, None, window, cx)
 1832    }
 1833
 1834    pub fn sticky_headers(
 1835        &self,
 1836        style: &EditorStyle,
 1837        cx: &App,
 1838    ) -> Option<Vec<OutlineItem<Anchor>>> {
 1839        let multi_buffer = self.buffer().read(cx);
 1840        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1841        let multi_buffer_visible_start = self
 1842            .scroll_manager
 1843            .anchor()
 1844            .anchor
 1845            .to_point(&multi_buffer_snapshot);
 1846        let max_row = multi_buffer_snapshot.max_point().row;
 1847
 1848        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1849        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1850
 1851        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1852            let outline_items = buffer
 1853                .outline_items_containing(
 1854                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1855                    true,
 1856                    Some(style.syntax.as_ref()),
 1857                )
 1858                .into_iter()
 1859                .map(|outline_item| OutlineItem {
 1860                    depth: outline_item.depth,
 1861                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1862                    source_range_for_text: Anchor::range_in_buffer(
 1863                        *excerpt_id,
 1864                        outline_item.source_range_for_text,
 1865                    ),
 1866                    text: outline_item.text,
 1867                    highlight_ranges: outline_item.highlight_ranges,
 1868                    name_ranges: outline_item.name_ranges,
 1869                    body_range: outline_item
 1870                        .body_range
 1871                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1872                    annotation_range: outline_item
 1873                        .annotation_range
 1874                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1875                });
 1876            return Some(outline_items.collect());
 1877        }
 1878
 1879        None
 1880    }
 1881
 1882    fn new_internal(
 1883        mode: EditorMode,
 1884        multi_buffer: Entity<MultiBuffer>,
 1885        project: Option<Entity<Project>>,
 1886        display_map: Option<Entity<DisplayMap>>,
 1887        window: &mut Window,
 1888        cx: &mut Context<Self>,
 1889    ) -> Self {
 1890        debug_assert!(
 1891            display_map.is_none() || mode.is_minimap(),
 1892            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1893        );
 1894
 1895        let full_mode = mode.is_full();
 1896        let is_minimap = mode.is_minimap();
 1897        let diagnostics_max_severity = if full_mode {
 1898            EditorSettings::get_global(cx)
 1899                .diagnostics_max_severity
 1900                .unwrap_or(DiagnosticSeverity::Hint)
 1901        } else {
 1902            DiagnosticSeverity::Off
 1903        };
 1904        let style = window.text_style();
 1905        let font_size = style.font_size.to_pixels(window.rem_size());
 1906        let editor = cx.entity().downgrade();
 1907        let fold_placeholder = FoldPlaceholder {
 1908            constrain_width: false,
 1909            render: Arc::new(move |fold_id, fold_range, cx| {
 1910                let editor = editor.clone();
 1911                div()
 1912                    .id(fold_id)
 1913                    .bg(cx.theme().colors().ghost_element_background)
 1914                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1915                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1916                    .rounded_xs()
 1917                    .size_full()
 1918                    .cursor_pointer()
 1919                    .child("")
 1920                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1921                    .on_click(move |_, _window, cx| {
 1922                        editor
 1923                            .update(cx, |editor, cx| {
 1924                                editor.unfold_ranges(
 1925                                    &[fold_range.start..fold_range.end],
 1926                                    true,
 1927                                    false,
 1928                                    cx,
 1929                                );
 1930                                cx.stop_propagation();
 1931                            })
 1932                            .ok();
 1933                    })
 1934                    .into_any()
 1935            }),
 1936            merge_adjacent: true,
 1937            ..FoldPlaceholder::default()
 1938        };
 1939        let display_map = display_map.unwrap_or_else(|| {
 1940            cx.new(|cx| {
 1941                DisplayMap::new(
 1942                    multi_buffer.clone(),
 1943                    style.font(),
 1944                    font_size,
 1945                    None,
 1946                    FILE_HEADER_HEIGHT,
 1947                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1948                    fold_placeholder,
 1949                    diagnostics_max_severity,
 1950                    cx,
 1951                )
 1952            })
 1953        });
 1954
 1955        let selections = SelectionsCollection::new();
 1956
 1957        let blink_manager = cx.new(|cx| {
 1958            let mut blink_manager = BlinkManager::new(
 1959                CURSOR_BLINK_INTERVAL,
 1960                |cx| EditorSettings::get_global(cx).cursor_blink,
 1961                cx,
 1962            );
 1963            if is_minimap {
 1964                blink_manager.disable(cx);
 1965            }
 1966            blink_manager
 1967        });
 1968
 1969        let soft_wrap_mode_override =
 1970            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1971
 1972        let mut project_subscriptions = Vec::new();
 1973        if full_mode && let Some(project) = project.as_ref() {
 1974            project_subscriptions.push(cx.subscribe_in(
 1975                project,
 1976                window,
 1977                |editor, _, event, window, cx| match event {
 1978                    project::Event::RefreshCodeLens => {
 1979                        // we always query lens with actions, without storing them, always refreshing them
 1980                    }
 1981                    project::Event::RefreshInlayHints {
 1982                        server_id,
 1983                        request_id,
 1984                    } => {
 1985                        editor.refresh_inlay_hints(
 1986                            InlayHintRefreshReason::RefreshRequested {
 1987                                server_id: *server_id,
 1988                                request_id: *request_id,
 1989                            },
 1990                            cx,
 1991                        );
 1992                    }
 1993                    project::Event::LanguageServerRemoved(..) => {
 1994                        if editor.tasks_update_task.is_none() {
 1995                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1996                        }
 1997                        editor.registered_buffers.clear();
 1998                        editor.register_visible_buffers(cx);
 1999                    }
 2000                    project::Event::LanguageServerAdded(..) => {
 2001                        if editor.tasks_update_task.is_none() {
 2002                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2003                        }
 2004                    }
 2005                    project::Event::SnippetEdit(id, snippet_edits) => {
 2006                        // todo(lw): Non singletons
 2007                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2008                            let snapshot = buffer.read(cx).snapshot();
 2009                            let focus_handle = editor.focus_handle(cx);
 2010                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2011                                for (range, snippet) in snippet_edits {
 2012                                    let buffer_range =
 2013                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2014                                    editor
 2015                                        .insert_snippet(
 2016                                            &[MultiBufferOffset(buffer_range.start)
 2017                                                ..MultiBufferOffset(buffer_range.end)],
 2018                                            snippet.clone(),
 2019                                            window,
 2020                                            cx,
 2021                                        )
 2022                                        .ok();
 2023                                }
 2024                            }
 2025                        }
 2026                    }
 2027                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2028                        let buffer_id = *buffer_id;
 2029                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2030                            editor.register_buffer(buffer_id, cx);
 2031                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2032                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2033                            refresh_linked_ranges(editor, window, cx);
 2034                            editor.refresh_code_actions(window, cx);
 2035                            editor.refresh_document_highlights(cx);
 2036                        }
 2037                    }
 2038
 2039                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2040                        let Some(workspace) = editor.workspace() else {
 2041                            return;
 2042                        };
 2043                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2044                        else {
 2045                            return;
 2046                        };
 2047
 2048                        if active_editor.entity_id() == cx.entity_id() {
 2049                            let entity_id = cx.entity_id();
 2050                            workspace.update(cx, |this, cx| {
 2051                                this.panes_mut()
 2052                                    .iter_mut()
 2053                                    .filter(|pane| pane.entity_id() != entity_id)
 2054                                    .for_each(|p| {
 2055                                        p.update(cx, |pane, _| {
 2056                                            pane.nav_history_mut().rename_item(
 2057                                                entity_id,
 2058                                                project_path.clone(),
 2059                                                abs_path.clone().into(),
 2060                                            );
 2061                                        })
 2062                                    });
 2063                            });
 2064
 2065                            Self::open_transaction_for_hidden_buffers(
 2066                                workspace,
 2067                                transaction.clone(),
 2068                                "Rename".to_string(),
 2069                                window,
 2070                                cx,
 2071                            );
 2072                        }
 2073                    }
 2074
 2075                    project::Event::WorkspaceEditApplied(transaction) => {
 2076                        let Some(workspace) = editor.workspace() else {
 2077                            return;
 2078                        };
 2079                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2080                        else {
 2081                            return;
 2082                        };
 2083
 2084                        if active_editor.entity_id() == cx.entity_id() {
 2085                            Self::open_transaction_for_hidden_buffers(
 2086                                workspace,
 2087                                transaction.clone(),
 2088                                "LSP Edit".to_string(),
 2089                                window,
 2090                                cx,
 2091                            );
 2092                        }
 2093                    }
 2094
 2095                    _ => {}
 2096                },
 2097            ));
 2098            if let Some(task_inventory) = project
 2099                .read(cx)
 2100                .task_store()
 2101                .read(cx)
 2102                .task_inventory()
 2103                .cloned()
 2104            {
 2105                project_subscriptions.push(cx.observe_in(
 2106                    &task_inventory,
 2107                    window,
 2108                    |editor, _, window, cx| {
 2109                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2110                    },
 2111                ));
 2112            };
 2113
 2114            project_subscriptions.push(cx.subscribe_in(
 2115                &project.read(cx).breakpoint_store(),
 2116                window,
 2117                |editor, _, event, window, cx| match event {
 2118                    BreakpointStoreEvent::ClearDebugLines => {
 2119                        editor.clear_row_highlights::<ActiveDebugLine>();
 2120                        editor.refresh_inline_values(cx);
 2121                    }
 2122                    BreakpointStoreEvent::SetDebugLine => {
 2123                        if editor.go_to_active_debug_line(window, cx) {
 2124                            cx.stop_propagation();
 2125                        }
 2126
 2127                        editor.refresh_inline_values(cx);
 2128                    }
 2129                    _ => {}
 2130                },
 2131            ));
 2132            let git_store = project.read(cx).git_store().clone();
 2133            let project = project.clone();
 2134            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2135                if let GitStoreEvent::RepositoryAdded = event {
 2136                    this.load_diff_task = Some(
 2137                        update_uncommitted_diff_for_buffer(
 2138                            cx.entity(),
 2139                            &project,
 2140                            this.buffer.read(cx).all_buffers(),
 2141                            this.buffer.clone(),
 2142                            cx,
 2143                        )
 2144                        .shared(),
 2145                    );
 2146                }
 2147            }));
 2148        }
 2149
 2150        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2151
 2152        let inlay_hint_settings =
 2153            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2154        let focus_handle = cx.focus_handle();
 2155        if !is_minimap {
 2156            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2157                .detach();
 2158            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2159                .detach();
 2160            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2161                .detach();
 2162            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2163                .detach();
 2164            cx.observe_pending_input(window, Self::observe_pending_input)
 2165                .detach();
 2166        }
 2167
 2168        let show_indent_guides =
 2169            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2170                Some(false)
 2171            } else {
 2172                None
 2173            };
 2174
 2175        let breakpoint_store = match (&mode, project.as_ref()) {
 2176            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2177            _ => None,
 2178        };
 2179
 2180        let mut code_action_providers = Vec::new();
 2181        let mut load_uncommitted_diff = None;
 2182        if let Some(project) = project.clone() {
 2183            load_uncommitted_diff = Some(
 2184                update_uncommitted_diff_for_buffer(
 2185                    cx.entity(),
 2186                    &project,
 2187                    multi_buffer.read(cx).all_buffers(),
 2188                    multi_buffer.clone(),
 2189                    cx,
 2190                )
 2191                .shared(),
 2192            );
 2193            code_action_providers.push(Rc::new(project) as Rc<_>);
 2194        }
 2195
 2196        let mut editor = Self {
 2197            focus_handle,
 2198            show_cursor_when_unfocused: false,
 2199            last_focused_descendant: None,
 2200            buffer: multi_buffer.clone(),
 2201            display_map: display_map.clone(),
 2202            placeholder_display_map: None,
 2203            selections,
 2204            scroll_manager: ScrollManager::new(cx),
 2205            columnar_selection_state: None,
 2206            add_selections_state: None,
 2207            select_next_state: None,
 2208            select_prev_state: None,
 2209            selection_history: SelectionHistory::default(),
 2210            defer_selection_effects: false,
 2211            deferred_selection_effects_state: None,
 2212            autoclose_regions: Vec::new(),
 2213            snippet_stack: InvalidationStack::default(),
 2214            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2215            ime_transaction: None,
 2216            active_diagnostics: ActiveDiagnostic::None,
 2217            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2218            inline_diagnostics_update: Task::ready(()),
 2219            inline_diagnostics: Vec::new(),
 2220            soft_wrap_mode_override,
 2221            diagnostics_max_severity,
 2222            hard_wrap: None,
 2223            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2224            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2225            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2226            project,
 2227            blink_manager: blink_manager.clone(),
 2228            show_local_selections: true,
 2229            show_scrollbars: ScrollbarAxes {
 2230                horizontal: full_mode,
 2231                vertical: full_mode,
 2232            },
 2233            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2234            offset_content: !matches!(mode, EditorMode::SingleLine),
 2235            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2236            show_gutter: full_mode,
 2237            show_line_numbers: (!full_mode).then_some(false),
 2238            use_relative_line_numbers: None,
 2239            disable_expand_excerpt_buttons: !full_mode,
 2240            show_git_diff_gutter: None,
 2241            show_code_actions: None,
 2242            show_runnables: None,
 2243            show_breakpoints: None,
 2244            show_wrap_guides: None,
 2245            show_indent_guides,
 2246            buffers_with_disabled_indent_guides: HashSet::default(),
 2247            highlight_order: 0,
 2248            highlighted_rows: HashMap::default(),
 2249            background_highlights: HashMap::default(),
 2250            gutter_highlights: HashMap::default(),
 2251            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2252            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2253            nav_history: None,
 2254            context_menu: RefCell::new(None),
 2255            context_menu_options: None,
 2256            mouse_context_menu: None,
 2257            completion_tasks: Vec::new(),
 2258            inline_blame_popover: None,
 2259            inline_blame_popover_show_task: None,
 2260            signature_help_state: SignatureHelpState::default(),
 2261            auto_signature_help: None,
 2262            find_all_references_task_sources: Vec::new(),
 2263            next_completion_id: 0,
 2264            next_inlay_id: 0,
 2265            code_action_providers,
 2266            available_code_actions: None,
 2267            code_actions_task: None,
 2268            quick_selection_highlight_task: None,
 2269            debounced_selection_highlight_task: None,
 2270            document_highlights_task: None,
 2271            linked_editing_range_task: None,
 2272            pending_rename: None,
 2273            searchable: !is_minimap,
 2274            cursor_shape: EditorSettings::get_global(cx)
 2275                .cursor_shape
 2276                .unwrap_or_default(),
 2277            cursor_offset_on_selection: false,
 2278            current_line_highlight: None,
 2279            autoindent_mode: Some(AutoindentMode::EachLine),
 2280            collapse_matches: false,
 2281            workspace: None,
 2282            input_enabled: !is_minimap,
 2283            use_modal_editing: full_mode,
 2284            read_only: is_minimap,
 2285            use_autoclose: true,
 2286            use_auto_surround: true,
 2287            auto_replace_emoji_shortcode: false,
 2288            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2289            leader_id: None,
 2290            remote_id: None,
 2291            hover_state: HoverState::default(),
 2292            pending_mouse_down: None,
 2293            prev_pressure_stage: None,
 2294            hovered_link_state: None,
 2295            edit_prediction_provider: None,
 2296            active_edit_prediction: None,
 2297            stale_edit_prediction_in_menu: None,
 2298            edit_prediction_preview: EditPredictionPreview::Inactive {
 2299                released_too_fast: false,
 2300            },
 2301            inline_diagnostics_enabled: full_mode,
 2302            diagnostics_enabled: full_mode,
 2303            word_completions_enabled: full_mode,
 2304            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2305            gutter_hovered: false,
 2306            pixel_position_of_newest_cursor: None,
 2307            last_bounds: None,
 2308            last_position_map: None,
 2309            expect_bounds_change: None,
 2310            gutter_dimensions: GutterDimensions::default(),
 2311            style: None,
 2312            show_cursor_names: false,
 2313            hovered_cursors: HashMap::default(),
 2314            next_editor_action_id: EditorActionId::default(),
 2315            editor_actions: Rc::default(),
 2316            edit_predictions_hidden_for_vim_mode: false,
 2317            show_edit_predictions_override: None,
 2318            show_completions_on_input_override: None,
 2319            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2320            edit_prediction_settings: EditPredictionSettings::Disabled,
 2321            edit_prediction_indent_conflict: false,
 2322            edit_prediction_requires_modifier_in_indent_conflict: true,
 2323            custom_context_menu: None,
 2324            show_git_blame_gutter: false,
 2325            show_git_blame_inline: false,
 2326            show_selection_menu: None,
 2327            show_git_blame_inline_delay_task: None,
 2328            git_blame_inline_enabled: full_mode
 2329                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2330            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2331            buffer_serialization: is_minimap.not().then(|| {
 2332                BufferSerialization::new(
 2333                    ProjectSettings::get_global(cx)
 2334                        .session
 2335                        .restore_unsaved_buffers,
 2336                )
 2337            }),
 2338            blame: None,
 2339            blame_subscription: None,
 2340            tasks: BTreeMap::default(),
 2341
 2342            breakpoint_store,
 2343            gutter_breakpoint_indicator: (None, None),
 2344            hovered_diff_hunk_row: None,
 2345            _subscriptions: (!is_minimap)
 2346                .then(|| {
 2347                    vec![
 2348                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2349                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2350                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2351                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2352                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2353                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2354                        cx.observe_window_activation(window, |editor, window, cx| {
 2355                            let active = window.is_window_active();
 2356                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2357                                if active {
 2358                                    blink_manager.enable(cx);
 2359                                } else {
 2360                                    blink_manager.disable(cx);
 2361                                }
 2362                            });
 2363                            if active {
 2364                                editor.show_mouse_cursor(cx);
 2365                            }
 2366                        }),
 2367                    ]
 2368                })
 2369                .unwrap_or_default(),
 2370            tasks_update_task: None,
 2371            pull_diagnostics_task: Task::ready(()),
 2372            pull_diagnostics_background_task: Task::ready(()),
 2373            colors: None,
 2374            refresh_colors_task: Task::ready(()),
 2375            inlay_hints: None,
 2376            next_color_inlay_id: 0,
 2377            post_scroll_update: Task::ready(()),
 2378            linked_edit_ranges: Default::default(),
 2379            in_project_search: false,
 2380            previous_search_ranges: None,
 2381            breadcrumb_header: None,
 2382            focused_block: None,
 2383            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2384            addons: HashMap::default(),
 2385            registered_buffers: HashMap::default(),
 2386            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2387            selection_mark_mode: false,
 2388            toggle_fold_multiple_buffers: Task::ready(()),
 2389            serialize_selections: Task::ready(()),
 2390            serialize_folds: Task::ready(()),
 2391            text_style_refinement: None,
 2392            load_diff_task: load_uncommitted_diff,
 2393            temporary_diff_override: false,
 2394            mouse_cursor_hidden: false,
 2395            minimap: None,
 2396            hide_mouse_mode: EditorSettings::get_global(cx)
 2397                .hide_mouse
 2398                .unwrap_or_default(),
 2399            change_list: ChangeList::new(),
 2400            mode,
 2401            selection_drag_state: SelectionDragState::None,
 2402            folding_newlines: Task::ready(()),
 2403            lookup_key: None,
 2404            select_next_is_case_sensitive: None,
 2405            applicable_language_settings: HashMap::default(),
 2406            accent_data: None,
 2407            fetched_tree_sitter_chunks: HashMap::default(),
 2408            use_base_text_line_numbers: false,
 2409        };
 2410
 2411        if is_minimap {
 2412            return editor;
 2413        }
 2414
 2415        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2416        editor.accent_data = editor.fetch_accent_data(cx);
 2417
 2418        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2419            editor
 2420                ._subscriptions
 2421                .push(cx.observe(breakpoints, |_, _, cx| {
 2422                    cx.notify();
 2423                }));
 2424        }
 2425        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2426        editor._subscriptions.extend(project_subscriptions);
 2427
 2428        editor._subscriptions.push(cx.subscribe_in(
 2429            &cx.entity(),
 2430            window,
 2431            |editor, _, e: &EditorEvent, window, cx| match e {
 2432                EditorEvent::ScrollPositionChanged { local, .. } => {
 2433                    if *local {
 2434                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2435                        editor.inline_blame_popover.take();
 2436                        let new_anchor = editor.scroll_manager.anchor();
 2437                        let snapshot = editor.snapshot(window, cx);
 2438                        editor.update_restoration_data(cx, move |data| {
 2439                            data.scroll_position = (
 2440                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2441                                new_anchor.offset,
 2442                            );
 2443                        });
 2444
 2445                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2446                            cx.background_executor()
 2447                                .timer(Duration::from_millis(50))
 2448                                .await;
 2449                            editor
 2450                                .update_in(cx, |editor, window, cx| {
 2451                                    editor.register_visible_buffers(cx);
 2452                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2453                                    editor.refresh_inlay_hints(
 2454                                        InlayHintRefreshReason::NewLinesShown,
 2455                                        cx,
 2456                                    );
 2457                                    editor.colorize_brackets(false, cx);
 2458                                })
 2459                                .ok();
 2460                        });
 2461                    }
 2462                }
 2463                EditorEvent::Edited { .. } => {
 2464                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2465                        .map(|vim_mode| vim_mode.0)
 2466                        .unwrap_or(false);
 2467                    if !vim_mode {
 2468                        let display_map = editor.display_snapshot(cx);
 2469                        let selections = editor.selections.all_adjusted_display(&display_map);
 2470                        let pop_state = editor
 2471                            .change_list
 2472                            .last()
 2473                            .map(|previous| {
 2474                                previous.len() == selections.len()
 2475                                    && previous.iter().enumerate().all(|(ix, p)| {
 2476                                        p.to_display_point(&display_map).row()
 2477                                            == selections[ix].head().row()
 2478                                    })
 2479                            })
 2480                            .unwrap_or(false);
 2481                        let new_positions = selections
 2482                            .into_iter()
 2483                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2484                            .collect();
 2485                        editor
 2486                            .change_list
 2487                            .push_to_change_list(pop_state, new_positions);
 2488                    }
 2489                }
 2490                _ => (),
 2491            },
 2492        ));
 2493
 2494        if let Some(dap_store) = editor
 2495            .project
 2496            .as_ref()
 2497            .map(|project| project.read(cx).dap_store())
 2498        {
 2499            let weak_editor = cx.weak_entity();
 2500
 2501            editor
 2502                ._subscriptions
 2503                .push(
 2504                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2505                        let session_entity = cx.entity();
 2506                        weak_editor
 2507                            .update(cx, |editor, cx| {
 2508                                editor._subscriptions.push(
 2509                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2510                                );
 2511                            })
 2512                            .ok();
 2513                    }),
 2514                );
 2515
 2516            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2517                editor
 2518                    ._subscriptions
 2519                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2520            }
 2521        }
 2522
 2523        // skip adding the initial selection to selection history
 2524        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2525        editor.end_selection(window, cx);
 2526        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2527
 2528        editor.scroll_manager.show_scrollbars(window, cx);
 2529        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2530
 2531        if full_mode {
 2532            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2533            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2534
 2535            if editor.git_blame_inline_enabled {
 2536                editor.start_git_blame_inline(false, window, cx);
 2537            }
 2538
 2539            editor.go_to_active_debug_line(window, cx);
 2540
 2541            editor.minimap =
 2542                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2543            editor.colors = Some(LspColorData::new(cx));
 2544            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2545
 2546            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2547                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2548            }
 2549            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2550        }
 2551
 2552        editor
 2553    }
 2554
 2555    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2556        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2557    }
 2558
 2559    pub fn deploy_mouse_context_menu(
 2560        &mut self,
 2561        position: gpui::Point<Pixels>,
 2562        context_menu: Entity<ContextMenu>,
 2563        window: &mut Window,
 2564        cx: &mut Context<Self>,
 2565    ) {
 2566        self.mouse_context_menu = Some(MouseContextMenu::new(
 2567            self,
 2568            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2569            context_menu,
 2570            window,
 2571            cx,
 2572        ));
 2573    }
 2574
 2575    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2576        self.mouse_context_menu
 2577            .as_ref()
 2578            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2579    }
 2580
 2581    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2582        if self
 2583            .selections
 2584            .pending_anchor()
 2585            .is_some_and(|pending_selection| {
 2586                let snapshot = self.buffer().read(cx).snapshot(cx);
 2587                pending_selection.range().includes(range, &snapshot)
 2588            })
 2589        {
 2590            return true;
 2591        }
 2592
 2593        self.selections
 2594            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2595            .into_iter()
 2596            .any(|selection| {
 2597                // This is needed to cover a corner case, if we just check for an existing
 2598                // selection in the fold range, having a cursor at the start of the fold
 2599                // marks it as selected. Non-empty selections don't cause this.
 2600                let length = selection.end - selection.start;
 2601                length > 0
 2602            })
 2603    }
 2604
 2605    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2606        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2607    }
 2608
 2609    fn key_context_internal(
 2610        &self,
 2611        has_active_edit_prediction: bool,
 2612        window: &mut Window,
 2613        cx: &mut App,
 2614    ) -> KeyContext {
 2615        let mut key_context = KeyContext::new_with_defaults();
 2616        key_context.add("Editor");
 2617        let mode = match self.mode {
 2618            EditorMode::SingleLine => "single_line",
 2619            EditorMode::AutoHeight { .. } => "auto_height",
 2620            EditorMode::Minimap { .. } => "minimap",
 2621            EditorMode::Full { .. } => "full",
 2622        };
 2623
 2624        if EditorSettings::jupyter_enabled(cx) {
 2625            key_context.add("jupyter");
 2626        }
 2627
 2628        key_context.set("mode", mode);
 2629        if self.pending_rename.is_some() {
 2630            key_context.add("renaming");
 2631        }
 2632
 2633        if let Some(snippet_stack) = self.snippet_stack.last() {
 2634            key_context.add("in_snippet");
 2635
 2636            if snippet_stack.active_index > 0 {
 2637                key_context.add("has_previous_tabstop");
 2638            }
 2639
 2640            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2641                key_context.add("has_next_tabstop");
 2642            }
 2643        }
 2644
 2645        match self.context_menu.borrow().as_ref() {
 2646            Some(CodeContextMenu::Completions(menu)) => {
 2647                if menu.visible() {
 2648                    key_context.add("menu");
 2649                    key_context.add("showing_completions");
 2650                }
 2651            }
 2652            Some(CodeContextMenu::CodeActions(menu)) => {
 2653                if menu.visible() {
 2654                    key_context.add("menu");
 2655                    key_context.add("showing_code_actions")
 2656                }
 2657            }
 2658            None => {}
 2659        }
 2660
 2661        if self.signature_help_state.has_multiple_signatures() {
 2662            key_context.add("showing_signature_help");
 2663        }
 2664
 2665        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2666        if !self.focus_handle(cx).contains_focused(window, cx)
 2667            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2668        {
 2669            for addon in self.addons.values() {
 2670                addon.extend_key_context(&mut key_context, cx)
 2671            }
 2672        }
 2673
 2674        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2675            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2676                Some(
 2677                    file.full_path(cx)
 2678                        .extension()?
 2679                        .to_string_lossy()
 2680                        .into_owned(),
 2681                )
 2682            }) {
 2683                key_context.set("extension", extension);
 2684            }
 2685        } else {
 2686            key_context.add("multibuffer");
 2687        }
 2688
 2689        if has_active_edit_prediction {
 2690            if self.edit_prediction_in_conflict() {
 2691                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2692            } else {
 2693                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2694                key_context.add("copilot_suggestion");
 2695            }
 2696        }
 2697
 2698        if self.selection_mark_mode {
 2699            key_context.add("selection_mode");
 2700        }
 2701
 2702        let disjoint = self.selections.disjoint_anchors();
 2703        let snapshot = self.snapshot(window, cx);
 2704        let snapshot = snapshot.buffer_snapshot();
 2705        if self.mode == EditorMode::SingleLine
 2706            && let [selection] = disjoint
 2707            && selection.start == selection.end
 2708            && selection.end.to_offset(snapshot) == snapshot.len()
 2709        {
 2710            key_context.add("end_of_input");
 2711        }
 2712
 2713        if self.has_any_expanded_diff_hunks(cx) {
 2714            key_context.add("diffs_expanded");
 2715        }
 2716
 2717        key_context
 2718    }
 2719
 2720    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2721        self.last_bounds.as_ref()
 2722    }
 2723
 2724    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2725        if self.mouse_cursor_hidden {
 2726            self.mouse_cursor_hidden = false;
 2727            cx.notify();
 2728        }
 2729    }
 2730
 2731    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2732        let hide_mouse_cursor = match origin {
 2733            HideMouseCursorOrigin::TypingAction => {
 2734                matches!(
 2735                    self.hide_mouse_mode,
 2736                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2737                )
 2738            }
 2739            HideMouseCursorOrigin::MovementAction => {
 2740                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2741            }
 2742        };
 2743        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2744            self.mouse_cursor_hidden = hide_mouse_cursor;
 2745            cx.notify();
 2746        }
 2747    }
 2748
 2749    pub fn edit_prediction_in_conflict(&self) -> bool {
 2750        if !self.show_edit_predictions_in_menu() {
 2751            return false;
 2752        }
 2753
 2754        let showing_completions = self
 2755            .context_menu
 2756            .borrow()
 2757            .as_ref()
 2758            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2759
 2760        showing_completions
 2761            || self.edit_prediction_requires_modifier()
 2762            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2763            // bindings to insert tab characters.
 2764            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2765    }
 2766
 2767    pub fn accept_edit_prediction_keybind(
 2768        &self,
 2769        granularity: EditPredictionGranularity,
 2770        window: &mut Window,
 2771        cx: &mut App,
 2772    ) -> AcceptEditPredictionBinding {
 2773        let key_context = self.key_context_internal(true, window, cx);
 2774        let in_conflict = self.edit_prediction_in_conflict();
 2775
 2776        let bindings =
 2777            match granularity {
 2778                EditPredictionGranularity::Word => window
 2779                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2780                EditPredictionGranularity::Line => window
 2781                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2782                EditPredictionGranularity::Full => {
 2783                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2784                }
 2785            };
 2786
 2787        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2788            !in_conflict
 2789                || binding
 2790                    .keystrokes()
 2791                    .first()
 2792                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2793        }))
 2794    }
 2795
 2796    pub fn new_file(
 2797        workspace: &mut Workspace,
 2798        _: &workspace::NewFile,
 2799        window: &mut Window,
 2800        cx: &mut Context<Workspace>,
 2801    ) {
 2802        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2803            "Failed to create buffer",
 2804            window,
 2805            cx,
 2806            |e, _, _| match e.error_code() {
 2807                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2808                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2809                e.error_tag("required").unwrap_or("the latest version")
 2810            )),
 2811                _ => None,
 2812            },
 2813        );
 2814    }
 2815
 2816    pub fn new_in_workspace(
 2817        workspace: &mut Workspace,
 2818        window: &mut Window,
 2819        cx: &mut Context<Workspace>,
 2820    ) -> Task<Result<Entity<Editor>>> {
 2821        let project = workspace.project().clone();
 2822        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2823
 2824        cx.spawn_in(window, async move |workspace, cx| {
 2825            let buffer = create.await?;
 2826            workspace.update_in(cx, |workspace, window, cx| {
 2827                let editor =
 2828                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2829                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2830                editor
 2831            })
 2832        })
 2833    }
 2834
 2835    fn new_file_vertical(
 2836        workspace: &mut Workspace,
 2837        _: &workspace::NewFileSplitVertical,
 2838        window: &mut Window,
 2839        cx: &mut Context<Workspace>,
 2840    ) {
 2841        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2842    }
 2843
 2844    fn new_file_horizontal(
 2845        workspace: &mut Workspace,
 2846        _: &workspace::NewFileSplitHorizontal,
 2847        window: &mut Window,
 2848        cx: &mut Context<Workspace>,
 2849    ) {
 2850        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2851    }
 2852
 2853    fn new_file_split(
 2854        workspace: &mut Workspace,
 2855        action: &workspace::NewFileSplit,
 2856        window: &mut Window,
 2857        cx: &mut Context<Workspace>,
 2858    ) {
 2859        Self::new_file_in_direction(workspace, action.0, window, cx)
 2860    }
 2861
 2862    fn new_file_in_direction(
 2863        workspace: &mut Workspace,
 2864        direction: SplitDirection,
 2865        window: &mut Window,
 2866        cx: &mut Context<Workspace>,
 2867    ) {
 2868        let project = workspace.project().clone();
 2869        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2870
 2871        cx.spawn_in(window, async move |workspace, cx| {
 2872            let buffer = create.await?;
 2873            workspace.update_in(cx, move |workspace, window, cx| {
 2874                workspace.split_item(
 2875                    direction,
 2876                    Box::new(
 2877                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2878                    ),
 2879                    window,
 2880                    cx,
 2881                )
 2882            })?;
 2883            anyhow::Ok(())
 2884        })
 2885        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2886            match e.error_code() {
 2887                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2888                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2889                e.error_tag("required").unwrap_or("the latest version")
 2890            )),
 2891                _ => None,
 2892            }
 2893        });
 2894    }
 2895
 2896    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2897        self.leader_id
 2898    }
 2899
 2900    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2901        &self.buffer
 2902    }
 2903
 2904    pub fn project(&self) -> Option<&Entity<Project>> {
 2905        self.project.as_ref()
 2906    }
 2907
 2908    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2909        self.workspace.as_ref()?.0.upgrade()
 2910    }
 2911
 2912    /// Returns the workspace serialization ID if this editor should be serialized.
 2913    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2914        self.workspace
 2915            .as_ref()
 2916            .filter(|_| self.should_serialize_buffer())
 2917            .and_then(|workspace| workspace.1)
 2918    }
 2919
 2920    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2921        self.buffer().read(cx).title(cx)
 2922    }
 2923
 2924    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2925        let git_blame_gutter_max_author_length = self
 2926            .render_git_blame_gutter(cx)
 2927            .then(|| {
 2928                if let Some(blame) = self.blame.as_ref() {
 2929                    let max_author_length =
 2930                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2931                    Some(max_author_length)
 2932                } else {
 2933                    None
 2934                }
 2935            })
 2936            .flatten();
 2937
 2938        EditorSnapshot {
 2939            mode: self.mode.clone(),
 2940            show_gutter: self.show_gutter,
 2941            offset_content: self.offset_content,
 2942            show_line_numbers: self.show_line_numbers,
 2943            show_git_diff_gutter: self.show_git_diff_gutter,
 2944            show_code_actions: self.show_code_actions,
 2945            show_runnables: self.show_runnables,
 2946            show_breakpoints: self.show_breakpoints,
 2947            git_blame_gutter_max_author_length,
 2948            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2949            placeholder_display_snapshot: self
 2950                .placeholder_display_map
 2951                .as_ref()
 2952                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2953            scroll_anchor: self.scroll_manager.anchor(),
 2954            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2955            is_focused: self.focus_handle.is_focused(window),
 2956            current_line_highlight: self
 2957                .current_line_highlight
 2958                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2959            gutter_hovered: self.gutter_hovered,
 2960        }
 2961    }
 2962
 2963    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2964        self.buffer.read(cx).language_at(point, cx)
 2965    }
 2966
 2967    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2968        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2969    }
 2970
 2971    pub fn active_excerpt(
 2972        &self,
 2973        cx: &App,
 2974    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2975        self.buffer
 2976            .read(cx)
 2977            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2978    }
 2979
 2980    pub fn mode(&self) -> &EditorMode {
 2981        &self.mode
 2982    }
 2983
 2984    pub fn set_mode(&mut self, mode: EditorMode) {
 2985        self.mode = mode;
 2986    }
 2987
 2988    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2989        self.collaboration_hub.as_deref()
 2990    }
 2991
 2992    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2993        self.collaboration_hub = Some(hub);
 2994    }
 2995
 2996    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2997        self.in_project_search = in_project_search;
 2998    }
 2999
 3000    pub fn set_custom_context_menu(
 3001        &mut self,
 3002        f: impl 'static
 3003        + Fn(
 3004            &mut Self,
 3005            DisplayPoint,
 3006            &mut Window,
 3007            &mut Context<Self>,
 3008        ) -> Option<Entity<ui::ContextMenu>>,
 3009    ) {
 3010        self.custom_context_menu = Some(Box::new(f))
 3011    }
 3012
 3013    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3014        self.completion_provider = provider;
 3015    }
 3016
 3017    #[cfg(any(test, feature = "test-support"))]
 3018    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3019        self.completion_provider.clone()
 3020    }
 3021
 3022    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3023        self.semantics_provider.clone()
 3024    }
 3025
 3026    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3027        self.semantics_provider = provider;
 3028    }
 3029
 3030    pub fn set_edit_prediction_provider<T>(
 3031        &mut self,
 3032        provider: Option<Entity<T>>,
 3033        window: &mut Window,
 3034        cx: &mut Context<Self>,
 3035    ) where
 3036        T: EditPredictionDelegate,
 3037    {
 3038        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3039            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3040                if this.focus_handle.is_focused(window) {
 3041                    this.update_visible_edit_prediction(window, cx);
 3042                }
 3043            }),
 3044            provider: Arc::new(provider),
 3045        });
 3046        self.update_edit_prediction_settings(cx);
 3047        self.refresh_edit_prediction(false, false, window, cx);
 3048    }
 3049
 3050    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3051        self.placeholder_display_map
 3052            .as_ref()
 3053            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3054    }
 3055
 3056    pub fn set_placeholder_text(
 3057        &mut self,
 3058        placeholder_text: &str,
 3059        window: &mut Window,
 3060        cx: &mut Context<Self>,
 3061    ) {
 3062        let multibuffer = cx
 3063            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3064
 3065        let style = window.text_style();
 3066
 3067        self.placeholder_display_map = Some(cx.new(|cx| {
 3068            DisplayMap::new(
 3069                multibuffer,
 3070                style.font(),
 3071                style.font_size.to_pixels(window.rem_size()),
 3072                None,
 3073                FILE_HEADER_HEIGHT,
 3074                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3075                Default::default(),
 3076                DiagnosticSeverity::Off,
 3077                cx,
 3078            )
 3079        }));
 3080        cx.notify();
 3081    }
 3082
 3083    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3084        self.cursor_shape = cursor_shape;
 3085
 3086        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3087        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3088
 3089        cx.notify();
 3090    }
 3091
 3092    pub fn cursor_shape(&self) -> CursorShape {
 3093        self.cursor_shape
 3094    }
 3095
 3096    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3097        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3098    }
 3099
 3100    pub fn set_current_line_highlight(
 3101        &mut self,
 3102        current_line_highlight: Option<CurrentLineHighlight>,
 3103    ) {
 3104        self.current_line_highlight = current_line_highlight;
 3105    }
 3106
 3107    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3108        self.collapse_matches = collapse_matches;
 3109    }
 3110
 3111    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3112        if self.collapse_matches {
 3113            return range.start..range.start;
 3114        }
 3115        range.clone()
 3116    }
 3117
 3118    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3119        self.display_map.read(cx).clip_at_line_ends
 3120    }
 3121
 3122    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3123        if self.display_map.read(cx).clip_at_line_ends != clip {
 3124            self.display_map
 3125                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3126        }
 3127    }
 3128
 3129    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3130        self.input_enabled = input_enabled;
 3131    }
 3132
 3133    pub fn set_edit_predictions_hidden_for_vim_mode(
 3134        &mut self,
 3135        hidden: bool,
 3136        window: &mut Window,
 3137        cx: &mut Context<Self>,
 3138    ) {
 3139        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3140            self.edit_predictions_hidden_for_vim_mode = hidden;
 3141            if hidden {
 3142                self.update_visible_edit_prediction(window, cx);
 3143            } else {
 3144                self.refresh_edit_prediction(true, false, window, cx);
 3145            }
 3146        }
 3147    }
 3148
 3149    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3150        self.menu_edit_predictions_policy = value;
 3151    }
 3152
 3153    pub fn set_autoindent(&mut self, autoindent: bool) {
 3154        if autoindent {
 3155            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3156        } else {
 3157            self.autoindent_mode = None;
 3158        }
 3159    }
 3160
 3161    pub fn read_only(&self, cx: &App) -> bool {
 3162        self.read_only || self.buffer.read(cx).read_only()
 3163    }
 3164
 3165    pub fn set_read_only(&mut self, read_only: bool) {
 3166        self.read_only = read_only;
 3167    }
 3168
 3169    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3170        self.use_autoclose = autoclose;
 3171    }
 3172
 3173    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3174        self.use_auto_surround = auto_surround;
 3175    }
 3176
 3177    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3178        self.auto_replace_emoji_shortcode = auto_replace;
 3179    }
 3180
 3181    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3182        self.buffer_serialization = should_serialize.then(|| {
 3183            BufferSerialization::new(
 3184                ProjectSettings::get_global(cx)
 3185                    .session
 3186                    .restore_unsaved_buffers,
 3187            )
 3188        })
 3189    }
 3190
 3191    fn should_serialize_buffer(&self) -> bool {
 3192        self.buffer_serialization.is_some()
 3193    }
 3194
 3195    pub fn toggle_edit_predictions(
 3196        &mut self,
 3197        _: &ToggleEditPrediction,
 3198        window: &mut Window,
 3199        cx: &mut Context<Self>,
 3200    ) {
 3201        if self.show_edit_predictions_override.is_some() {
 3202            self.set_show_edit_predictions(None, window, cx);
 3203        } else {
 3204            let show_edit_predictions = !self.edit_predictions_enabled();
 3205            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3206        }
 3207    }
 3208
 3209    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3210        self.show_completions_on_input_override = show_completions_on_input;
 3211    }
 3212
 3213    pub fn set_show_edit_predictions(
 3214        &mut self,
 3215        show_edit_predictions: Option<bool>,
 3216        window: &mut Window,
 3217        cx: &mut Context<Self>,
 3218    ) {
 3219        self.show_edit_predictions_override = show_edit_predictions;
 3220        self.update_edit_prediction_settings(cx);
 3221
 3222        if let Some(false) = show_edit_predictions {
 3223            self.discard_edit_prediction(false, cx);
 3224        } else {
 3225            self.refresh_edit_prediction(false, true, window, cx);
 3226        }
 3227    }
 3228
 3229    fn edit_predictions_disabled_in_scope(
 3230        &self,
 3231        buffer: &Entity<Buffer>,
 3232        buffer_position: language::Anchor,
 3233        cx: &App,
 3234    ) -> bool {
 3235        let snapshot = buffer.read(cx).snapshot();
 3236        let settings = snapshot.settings_at(buffer_position, cx);
 3237
 3238        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3239            return false;
 3240        };
 3241
 3242        scope.override_name().is_some_and(|scope_name| {
 3243            settings
 3244                .edit_predictions_disabled_in
 3245                .iter()
 3246                .any(|s| s == scope_name)
 3247        })
 3248    }
 3249
 3250    pub fn set_use_modal_editing(&mut self, to: bool) {
 3251        self.use_modal_editing = to;
 3252    }
 3253
 3254    pub fn use_modal_editing(&self) -> bool {
 3255        self.use_modal_editing
 3256    }
 3257
 3258    fn selections_did_change(
 3259        &mut self,
 3260        local: bool,
 3261        old_cursor_position: &Anchor,
 3262        effects: SelectionEffects,
 3263        window: &mut Window,
 3264        cx: &mut Context<Self>,
 3265    ) {
 3266        window.invalidate_character_coordinates();
 3267
 3268        // Copy selections to primary selection buffer
 3269        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3270        if local {
 3271            let selections = self
 3272                .selections
 3273                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3274            let buffer_handle = self.buffer.read(cx).read(cx);
 3275
 3276            let mut text = String::new();
 3277            for (index, selection) in selections.iter().enumerate() {
 3278                let text_for_selection = buffer_handle
 3279                    .text_for_range(selection.start..selection.end)
 3280                    .collect::<String>();
 3281
 3282                text.push_str(&text_for_selection);
 3283                if index != selections.len() - 1 {
 3284                    text.push('\n');
 3285                }
 3286            }
 3287
 3288            if !text.is_empty() {
 3289                cx.write_to_primary(ClipboardItem::new_string(text));
 3290            }
 3291        }
 3292
 3293        let selection_anchors = self.selections.disjoint_anchors_arc();
 3294
 3295        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3296            self.buffer.update(cx, |buffer, cx| {
 3297                buffer.set_active_selections(
 3298                    &selection_anchors,
 3299                    self.selections.line_mode(),
 3300                    self.cursor_shape,
 3301                    cx,
 3302                )
 3303            });
 3304        }
 3305        let display_map = self
 3306            .display_map
 3307            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3308        let buffer = display_map.buffer_snapshot();
 3309        if self.selections.count() == 1 {
 3310            self.add_selections_state = None;
 3311        }
 3312        self.select_next_state = None;
 3313        self.select_prev_state = None;
 3314        self.select_syntax_node_history.try_clear();
 3315        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3316        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3317        self.take_rename(false, window, cx);
 3318
 3319        let newest_selection = self.selections.newest_anchor();
 3320        let new_cursor_position = newest_selection.head();
 3321        let selection_start = newest_selection.start;
 3322
 3323        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3324            self.push_to_nav_history(
 3325                *old_cursor_position,
 3326                Some(new_cursor_position.to_point(buffer)),
 3327                false,
 3328                effects.nav_history == Some(true),
 3329                cx,
 3330            );
 3331        }
 3332
 3333        if local {
 3334            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3335                self.register_buffer(buffer_id, cx);
 3336            }
 3337
 3338            let mut context_menu = self.context_menu.borrow_mut();
 3339            let completion_menu = match context_menu.as_ref() {
 3340                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3341                Some(CodeContextMenu::CodeActions(_)) => {
 3342                    *context_menu = None;
 3343                    None
 3344                }
 3345                None => None,
 3346            };
 3347            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3348            drop(context_menu);
 3349
 3350            if effects.completions
 3351                && let Some(completion_position) = completion_position
 3352            {
 3353                let start_offset = selection_start.to_offset(buffer);
 3354                let position_matches = start_offset == completion_position.to_offset(buffer);
 3355                let continue_showing = if position_matches {
 3356                    if self.snippet_stack.is_empty() {
 3357                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3358                            == Some(CharKind::Word)
 3359                    } else {
 3360                        // Snippet choices can be shown even when the cursor is in whitespace.
 3361                        // Dismissing the menu with actions like backspace is handled by
 3362                        // invalidation regions.
 3363                        true
 3364                    }
 3365                } else {
 3366                    false
 3367                };
 3368
 3369                if continue_showing {
 3370                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3371                } else {
 3372                    self.hide_context_menu(window, cx);
 3373                }
 3374            }
 3375
 3376            hide_hover(self, cx);
 3377
 3378            if old_cursor_position.to_display_point(&display_map).row()
 3379                != new_cursor_position.to_display_point(&display_map).row()
 3380            {
 3381                self.available_code_actions.take();
 3382            }
 3383            self.refresh_code_actions(window, cx);
 3384            self.refresh_document_highlights(cx);
 3385            refresh_linked_ranges(self, window, cx);
 3386
 3387            self.refresh_selected_text_highlights(false, window, cx);
 3388            self.refresh_matching_bracket_highlights(window, cx);
 3389            self.update_visible_edit_prediction(window, cx);
 3390            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3391            self.inline_blame_popover.take();
 3392            if self.git_blame_inline_enabled {
 3393                self.start_inline_blame_timer(window, cx);
 3394            }
 3395        }
 3396
 3397        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3398        cx.emit(EditorEvent::SelectionsChanged { local });
 3399
 3400        let selections = &self.selections.disjoint_anchors_arc();
 3401        if selections.len() == 1 {
 3402            cx.emit(SearchEvent::ActiveMatchChanged)
 3403        }
 3404        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3405            let inmemory_selections = selections
 3406                .iter()
 3407                .map(|s| {
 3408                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3409                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3410                })
 3411                .collect();
 3412            self.update_restoration_data(cx, |data| {
 3413                data.selections = inmemory_selections;
 3414            });
 3415
 3416            if WorkspaceSettings::get(None, cx).restore_on_startup
 3417                != RestoreOnStartupBehavior::EmptyTab
 3418                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3419            {
 3420                let snapshot = self.buffer().read(cx).snapshot(cx);
 3421                let selections = selections.clone();
 3422                let background_executor = cx.background_executor().clone();
 3423                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3424                self.serialize_selections = cx.background_spawn(async move {
 3425                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3426                    let db_selections = selections
 3427                        .iter()
 3428                        .map(|selection| {
 3429                            (
 3430                                selection.start.to_offset(&snapshot).0,
 3431                                selection.end.to_offset(&snapshot).0,
 3432                            )
 3433                        })
 3434                        .collect();
 3435
 3436                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3437                        .await
 3438                        .with_context(|| {
 3439                            format!(
 3440                                "persisting editor selections for editor {editor_id}, \
 3441                                workspace {workspace_id:?}"
 3442                            )
 3443                        })
 3444                        .log_err();
 3445                });
 3446            }
 3447        }
 3448
 3449        cx.notify();
 3450    }
 3451
 3452    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3453        use text::ToOffset as _;
 3454        use text::ToPoint as _;
 3455
 3456        if self.mode.is_minimap()
 3457            || WorkspaceSettings::get(None, cx).restore_on_startup
 3458                == RestoreOnStartupBehavior::EmptyTab
 3459        {
 3460            return;
 3461        }
 3462
 3463        if !self.buffer().read(cx).is_singleton() {
 3464            return;
 3465        }
 3466
 3467        let display_snapshot = self
 3468            .display_map
 3469            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3470        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3471            return;
 3472        };
 3473        let inmemory_folds = display_snapshot
 3474            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3475            .map(|fold| {
 3476                fold.range.start.text_anchor.to_point(&snapshot)
 3477                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3478            })
 3479            .collect();
 3480        self.update_restoration_data(cx, |data| {
 3481            data.folds = inmemory_folds;
 3482        });
 3483
 3484        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3485            return;
 3486        };
 3487        let background_executor = cx.background_executor().clone();
 3488        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3489        let db_folds = display_snapshot
 3490            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3491            .map(|fold| {
 3492                (
 3493                    fold.range.start.text_anchor.to_offset(&snapshot),
 3494                    fold.range.end.text_anchor.to_offset(&snapshot),
 3495                )
 3496            })
 3497            .collect();
 3498        self.serialize_folds = cx.background_spawn(async move {
 3499            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3500            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3501                .await
 3502                .with_context(|| {
 3503                    format!(
 3504                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3505                    )
 3506                })
 3507                .log_err();
 3508        });
 3509    }
 3510
 3511    pub fn sync_selections(
 3512        &mut self,
 3513        other: Entity<Editor>,
 3514        cx: &mut Context<Self>,
 3515    ) -> gpui::Subscription {
 3516        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3517        if !other_selections.is_empty() {
 3518            self.selections
 3519                .change_with(&self.display_snapshot(cx), |selections| {
 3520                    selections.select_anchors(other_selections);
 3521                });
 3522        }
 3523
 3524        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3525            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3526                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3527                if other_selections.is_empty() {
 3528                    return;
 3529                }
 3530                let snapshot = this.display_snapshot(cx);
 3531                this.selections.change_with(&snapshot, |selections| {
 3532                    selections.select_anchors(other_selections);
 3533                });
 3534            }
 3535        });
 3536
 3537        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3538            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3539                let these_selections = this.selections.disjoint_anchors().to_vec();
 3540                if these_selections.is_empty() {
 3541                    return;
 3542                }
 3543                other.update(cx, |other_editor, cx| {
 3544                    let snapshot = other_editor.display_snapshot(cx);
 3545                    other_editor
 3546                        .selections
 3547                        .change_with(&snapshot, |selections| {
 3548                            selections.select_anchors(these_selections);
 3549                        })
 3550                });
 3551            }
 3552        });
 3553
 3554        Subscription::join(other_subscription, this_subscription)
 3555    }
 3556
 3557    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3558        if self.buffer().read(cx).is_singleton() {
 3559            return;
 3560        }
 3561        let snapshot = self.buffer.read(cx).snapshot(cx);
 3562        let buffer_ids: HashSet<BufferId> = self
 3563            .selections
 3564            .disjoint_anchor_ranges()
 3565            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3566            .collect();
 3567        for buffer_id in buffer_ids {
 3568            self.unfold_buffer(buffer_id, cx);
 3569        }
 3570    }
 3571
 3572    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3573    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3574    /// effects of selection change occur at the end of the transaction.
 3575    pub fn change_selections<R>(
 3576        &mut self,
 3577        effects: SelectionEffects,
 3578        window: &mut Window,
 3579        cx: &mut Context<Self>,
 3580        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3581    ) -> R {
 3582        let snapshot = self.display_snapshot(cx);
 3583        if let Some(state) = &mut self.deferred_selection_effects_state {
 3584            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3585            state.effects.completions = effects.completions;
 3586            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3587            let (changed, result) = self.selections.change_with(&snapshot, change);
 3588            state.changed |= changed;
 3589            return result;
 3590        }
 3591        let mut state = DeferredSelectionEffectsState {
 3592            changed: false,
 3593            effects,
 3594            old_cursor_position: self.selections.newest_anchor().head(),
 3595            history_entry: SelectionHistoryEntry {
 3596                selections: self.selections.disjoint_anchors_arc(),
 3597                select_next_state: self.select_next_state.clone(),
 3598                select_prev_state: self.select_prev_state.clone(),
 3599                add_selections_state: self.add_selections_state.clone(),
 3600            },
 3601        };
 3602        let (changed, result) = self.selections.change_with(&snapshot, change);
 3603        state.changed = state.changed || changed;
 3604        if self.defer_selection_effects {
 3605            self.deferred_selection_effects_state = Some(state);
 3606        } else {
 3607            self.apply_selection_effects(state, window, cx);
 3608        }
 3609        result
 3610    }
 3611
 3612    /// Defers the effects of selection change, so that the effects of multiple calls to
 3613    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3614    /// to selection history and the state of popovers based on selection position aren't
 3615    /// erroneously updated.
 3616    pub fn with_selection_effects_deferred<R>(
 3617        &mut self,
 3618        window: &mut Window,
 3619        cx: &mut Context<Self>,
 3620        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3621    ) -> R {
 3622        let already_deferred = self.defer_selection_effects;
 3623        self.defer_selection_effects = true;
 3624        let result = update(self, window, cx);
 3625        if !already_deferred {
 3626            self.defer_selection_effects = false;
 3627            if let Some(state) = self.deferred_selection_effects_state.take() {
 3628                self.apply_selection_effects(state, window, cx);
 3629            }
 3630        }
 3631        result
 3632    }
 3633
 3634    fn apply_selection_effects(
 3635        &mut self,
 3636        state: DeferredSelectionEffectsState,
 3637        window: &mut Window,
 3638        cx: &mut Context<Self>,
 3639    ) {
 3640        if state.changed {
 3641            self.selection_history.push(state.history_entry);
 3642
 3643            if let Some(autoscroll) = state.effects.scroll {
 3644                self.request_autoscroll(autoscroll, cx);
 3645            }
 3646
 3647            let old_cursor_position = &state.old_cursor_position;
 3648
 3649            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3650
 3651            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3652                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3653            }
 3654        }
 3655    }
 3656
 3657    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3658    where
 3659        I: IntoIterator<Item = (Range<S>, T)>,
 3660        S: ToOffset,
 3661        T: Into<Arc<str>>,
 3662    {
 3663        if self.read_only(cx) {
 3664            return;
 3665        }
 3666
 3667        self.buffer
 3668            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3669    }
 3670
 3671    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3672    where
 3673        I: IntoIterator<Item = (Range<S>, T)>,
 3674        S: ToOffset,
 3675        T: Into<Arc<str>>,
 3676    {
 3677        if self.read_only(cx) {
 3678            return;
 3679        }
 3680
 3681        self.buffer.update(cx, |buffer, cx| {
 3682            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3683        });
 3684    }
 3685
 3686    pub fn edit_with_block_indent<I, S, T>(
 3687        &mut self,
 3688        edits: I,
 3689        original_indent_columns: Vec<Option<u32>>,
 3690        cx: &mut Context<Self>,
 3691    ) where
 3692        I: IntoIterator<Item = (Range<S>, T)>,
 3693        S: ToOffset,
 3694        T: Into<Arc<str>>,
 3695    {
 3696        if self.read_only(cx) {
 3697            return;
 3698        }
 3699
 3700        self.buffer.update(cx, |buffer, cx| {
 3701            buffer.edit(
 3702                edits,
 3703                Some(AutoindentMode::Block {
 3704                    original_indent_columns,
 3705                }),
 3706                cx,
 3707            )
 3708        });
 3709    }
 3710
 3711    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3712        self.hide_context_menu(window, cx);
 3713
 3714        match phase {
 3715            SelectPhase::Begin {
 3716                position,
 3717                add,
 3718                click_count,
 3719            } => self.begin_selection(position, add, click_count, window, cx),
 3720            SelectPhase::BeginColumnar {
 3721                position,
 3722                goal_column,
 3723                reset,
 3724                mode,
 3725            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3726            SelectPhase::Extend {
 3727                position,
 3728                click_count,
 3729            } => self.extend_selection(position, click_count, window, cx),
 3730            SelectPhase::Update {
 3731                position,
 3732                goal_column,
 3733                scroll_delta,
 3734            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3735            SelectPhase::End => self.end_selection(window, cx),
 3736        }
 3737    }
 3738
 3739    fn extend_selection(
 3740        &mut self,
 3741        position: DisplayPoint,
 3742        click_count: usize,
 3743        window: &mut Window,
 3744        cx: &mut Context<Self>,
 3745    ) {
 3746        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3747        let tail = self
 3748            .selections
 3749            .newest::<MultiBufferOffset>(&display_map)
 3750            .tail();
 3751        let click_count = click_count.max(match self.selections.select_mode() {
 3752            SelectMode::Character => 1,
 3753            SelectMode::Word(_) => 2,
 3754            SelectMode::Line(_) => 3,
 3755            SelectMode::All => 4,
 3756        });
 3757        self.begin_selection(position, false, click_count, window, cx);
 3758
 3759        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3760
 3761        let current_selection = match self.selections.select_mode() {
 3762            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3763            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3764        };
 3765
 3766        let mut pending_selection = self
 3767            .selections
 3768            .pending_anchor()
 3769            .cloned()
 3770            .expect("extend_selection not called with pending selection");
 3771
 3772        if pending_selection
 3773            .start
 3774            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3775            == Ordering::Greater
 3776        {
 3777            pending_selection.start = current_selection.start;
 3778        }
 3779        if pending_selection
 3780            .end
 3781            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3782            == Ordering::Less
 3783        {
 3784            pending_selection.end = current_selection.end;
 3785            pending_selection.reversed = true;
 3786        }
 3787
 3788        let mut pending_mode = self.selections.pending_mode().unwrap();
 3789        match &mut pending_mode {
 3790            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3791            _ => {}
 3792        }
 3793
 3794        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3795            SelectionEffects::scroll(Autoscroll::fit())
 3796        } else {
 3797            SelectionEffects::no_scroll()
 3798        };
 3799
 3800        self.change_selections(effects, window, cx, |s| {
 3801            s.set_pending(pending_selection.clone(), pending_mode);
 3802            s.set_is_extending(true);
 3803        });
 3804    }
 3805
 3806    fn begin_selection(
 3807        &mut self,
 3808        position: DisplayPoint,
 3809        add: bool,
 3810        click_count: usize,
 3811        window: &mut Window,
 3812        cx: &mut Context<Self>,
 3813    ) {
 3814        if !self.focus_handle.is_focused(window) {
 3815            self.last_focused_descendant = None;
 3816            window.focus(&self.focus_handle, cx);
 3817        }
 3818
 3819        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3820        let buffer = display_map.buffer_snapshot();
 3821        let position = display_map.clip_point(position, Bias::Left);
 3822
 3823        let start;
 3824        let end;
 3825        let mode;
 3826        let mut auto_scroll;
 3827        match click_count {
 3828            1 => {
 3829                start = buffer.anchor_before(position.to_point(&display_map));
 3830                end = start;
 3831                mode = SelectMode::Character;
 3832                auto_scroll = true;
 3833            }
 3834            2 => {
 3835                let position = display_map
 3836                    .clip_point(position, Bias::Left)
 3837                    .to_offset(&display_map, Bias::Left);
 3838                let (range, _) = buffer.surrounding_word(position, None);
 3839                start = buffer.anchor_before(range.start);
 3840                end = buffer.anchor_before(range.end);
 3841                mode = SelectMode::Word(start..end);
 3842                auto_scroll = true;
 3843            }
 3844            3 => {
 3845                let position = display_map
 3846                    .clip_point(position, Bias::Left)
 3847                    .to_point(&display_map);
 3848                let line_start = display_map.prev_line_boundary(position).0;
 3849                let next_line_start = buffer.clip_point(
 3850                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3851                    Bias::Left,
 3852                );
 3853                start = buffer.anchor_before(line_start);
 3854                end = buffer.anchor_before(next_line_start);
 3855                mode = SelectMode::Line(start..end);
 3856                auto_scroll = true;
 3857            }
 3858            _ => {
 3859                start = buffer.anchor_before(MultiBufferOffset(0));
 3860                end = buffer.anchor_before(buffer.len());
 3861                mode = SelectMode::All;
 3862                auto_scroll = false;
 3863            }
 3864        }
 3865        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3866
 3867        let point_to_delete: Option<usize> = {
 3868            let selected_points: Vec<Selection<Point>> =
 3869                self.selections.disjoint_in_range(start..end, &display_map);
 3870
 3871            if !add || click_count > 1 {
 3872                None
 3873            } else if !selected_points.is_empty() {
 3874                Some(selected_points[0].id)
 3875            } else {
 3876                let clicked_point_already_selected =
 3877                    self.selections.disjoint_anchors().iter().find(|selection| {
 3878                        selection.start.to_point(buffer) == start.to_point(buffer)
 3879                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3880                    });
 3881
 3882                clicked_point_already_selected.map(|selection| selection.id)
 3883            }
 3884        };
 3885
 3886        let selections_count = self.selections.count();
 3887        let effects = if auto_scroll {
 3888            SelectionEffects::default()
 3889        } else {
 3890            SelectionEffects::no_scroll()
 3891        };
 3892
 3893        self.change_selections(effects, window, cx, |s| {
 3894            if let Some(point_to_delete) = point_to_delete {
 3895                s.delete(point_to_delete);
 3896
 3897                if selections_count == 1 {
 3898                    s.set_pending_anchor_range(start..end, mode);
 3899                }
 3900            } else {
 3901                if !add {
 3902                    s.clear_disjoint();
 3903                }
 3904
 3905                s.set_pending_anchor_range(start..end, mode);
 3906            }
 3907        });
 3908    }
 3909
 3910    fn begin_columnar_selection(
 3911        &mut self,
 3912        position: DisplayPoint,
 3913        goal_column: u32,
 3914        reset: bool,
 3915        mode: ColumnarMode,
 3916        window: &mut Window,
 3917        cx: &mut Context<Self>,
 3918    ) {
 3919        if !self.focus_handle.is_focused(window) {
 3920            self.last_focused_descendant = None;
 3921            window.focus(&self.focus_handle, cx);
 3922        }
 3923
 3924        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3925
 3926        if reset {
 3927            let pointer_position = display_map
 3928                .buffer_snapshot()
 3929                .anchor_before(position.to_point(&display_map));
 3930
 3931            self.change_selections(
 3932                SelectionEffects::scroll(Autoscroll::newest()),
 3933                window,
 3934                cx,
 3935                |s| {
 3936                    s.clear_disjoint();
 3937                    s.set_pending_anchor_range(
 3938                        pointer_position..pointer_position,
 3939                        SelectMode::Character,
 3940                    );
 3941                },
 3942            );
 3943        };
 3944
 3945        let tail = self.selections.newest::<Point>(&display_map).tail();
 3946        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3947        self.columnar_selection_state = match mode {
 3948            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3949                selection_tail: selection_anchor,
 3950                display_point: if reset {
 3951                    if position.column() != goal_column {
 3952                        Some(DisplayPoint::new(position.row(), goal_column))
 3953                    } else {
 3954                        None
 3955                    }
 3956                } else {
 3957                    None
 3958                },
 3959            }),
 3960            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3961                selection_tail: selection_anchor,
 3962            }),
 3963        };
 3964
 3965        if !reset {
 3966            self.select_columns(position, goal_column, &display_map, window, cx);
 3967        }
 3968    }
 3969
 3970    fn update_selection(
 3971        &mut self,
 3972        position: DisplayPoint,
 3973        goal_column: u32,
 3974        scroll_delta: gpui::Point<f32>,
 3975        window: &mut Window,
 3976        cx: &mut Context<Self>,
 3977    ) {
 3978        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3979
 3980        if self.columnar_selection_state.is_some() {
 3981            self.select_columns(position, goal_column, &display_map, window, cx);
 3982        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3983            let buffer = display_map.buffer_snapshot();
 3984            let head;
 3985            let tail;
 3986            let mode = self.selections.pending_mode().unwrap();
 3987            match &mode {
 3988                SelectMode::Character => {
 3989                    head = position.to_point(&display_map);
 3990                    tail = pending.tail().to_point(buffer);
 3991                }
 3992                SelectMode::Word(original_range) => {
 3993                    let offset = display_map
 3994                        .clip_point(position, Bias::Left)
 3995                        .to_offset(&display_map, Bias::Left);
 3996                    let original_range = original_range.to_offset(buffer);
 3997
 3998                    let head_offset = if buffer.is_inside_word(offset, None)
 3999                        || original_range.contains(&offset)
 4000                    {
 4001                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4002                        if word_range.start < original_range.start {
 4003                            word_range.start
 4004                        } else {
 4005                            word_range.end
 4006                        }
 4007                    } else {
 4008                        offset
 4009                    };
 4010
 4011                    head = head_offset.to_point(buffer);
 4012                    if head_offset <= original_range.start {
 4013                        tail = original_range.end.to_point(buffer);
 4014                    } else {
 4015                        tail = original_range.start.to_point(buffer);
 4016                    }
 4017                }
 4018                SelectMode::Line(original_range) => {
 4019                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4020
 4021                    let position = display_map
 4022                        .clip_point(position, Bias::Left)
 4023                        .to_point(&display_map);
 4024                    let line_start = display_map.prev_line_boundary(position).0;
 4025                    let next_line_start = buffer.clip_point(
 4026                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4027                        Bias::Left,
 4028                    );
 4029
 4030                    if line_start < original_range.start {
 4031                        head = line_start
 4032                    } else {
 4033                        head = next_line_start
 4034                    }
 4035
 4036                    if head <= original_range.start {
 4037                        tail = original_range.end;
 4038                    } else {
 4039                        tail = original_range.start;
 4040                    }
 4041                }
 4042                SelectMode::All => {
 4043                    return;
 4044                }
 4045            };
 4046
 4047            if head < tail {
 4048                pending.start = buffer.anchor_before(head);
 4049                pending.end = buffer.anchor_before(tail);
 4050                pending.reversed = true;
 4051            } else {
 4052                pending.start = buffer.anchor_before(tail);
 4053                pending.end = buffer.anchor_before(head);
 4054                pending.reversed = false;
 4055            }
 4056
 4057            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4058                s.set_pending(pending.clone(), mode);
 4059            });
 4060        } else {
 4061            log::error!("update_selection dispatched with no pending selection");
 4062            return;
 4063        }
 4064
 4065        self.apply_scroll_delta(scroll_delta, window, cx);
 4066        cx.notify();
 4067    }
 4068
 4069    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4070        self.columnar_selection_state.take();
 4071        if let Some(pending_mode) = self.selections.pending_mode() {
 4072            let selections = self
 4073                .selections
 4074                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4075            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4076                s.select(selections);
 4077                s.clear_pending();
 4078                if s.is_extending() {
 4079                    s.set_is_extending(false);
 4080                } else {
 4081                    s.set_select_mode(pending_mode);
 4082                }
 4083            });
 4084        }
 4085    }
 4086
 4087    fn select_columns(
 4088        &mut self,
 4089        head: DisplayPoint,
 4090        goal_column: u32,
 4091        display_map: &DisplaySnapshot,
 4092        window: &mut Window,
 4093        cx: &mut Context<Self>,
 4094    ) {
 4095        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4096            return;
 4097        };
 4098
 4099        let tail = match columnar_state {
 4100            ColumnarSelectionState::FromMouse {
 4101                selection_tail,
 4102                display_point,
 4103            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4104            ColumnarSelectionState::FromSelection { selection_tail } => {
 4105                selection_tail.to_display_point(display_map)
 4106            }
 4107        };
 4108
 4109        let start_row = cmp::min(tail.row(), head.row());
 4110        let end_row = cmp::max(tail.row(), head.row());
 4111        let start_column = cmp::min(tail.column(), goal_column);
 4112        let end_column = cmp::max(tail.column(), goal_column);
 4113        let reversed = start_column < tail.column();
 4114
 4115        let selection_ranges = (start_row.0..=end_row.0)
 4116            .map(DisplayRow)
 4117            .filter_map(|row| {
 4118                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4119                    || start_column <= display_map.line_len(row))
 4120                    && !display_map.is_block_line(row)
 4121                {
 4122                    let start = display_map
 4123                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4124                        .to_point(display_map);
 4125                    let end = display_map
 4126                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4127                        .to_point(display_map);
 4128                    if reversed {
 4129                        Some(end..start)
 4130                    } else {
 4131                        Some(start..end)
 4132                    }
 4133                } else {
 4134                    None
 4135                }
 4136            })
 4137            .collect::<Vec<_>>();
 4138        if selection_ranges.is_empty() {
 4139            return;
 4140        }
 4141
 4142        let ranges = match columnar_state {
 4143            ColumnarSelectionState::FromMouse { .. } => {
 4144                let mut non_empty_ranges = selection_ranges
 4145                    .iter()
 4146                    .filter(|selection_range| selection_range.start != selection_range.end)
 4147                    .peekable();
 4148                if non_empty_ranges.peek().is_some() {
 4149                    non_empty_ranges.cloned().collect()
 4150                } else {
 4151                    selection_ranges
 4152                }
 4153            }
 4154            _ => selection_ranges,
 4155        };
 4156
 4157        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4158            s.select_ranges(ranges);
 4159        });
 4160        cx.notify();
 4161    }
 4162
 4163    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4164        self.selections
 4165            .all_adjusted(snapshot)
 4166            .iter()
 4167            .any(|selection| !selection.is_empty())
 4168    }
 4169
 4170    pub fn has_pending_nonempty_selection(&self) -> bool {
 4171        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4172            Some(Selection { start, end, .. }) => start != end,
 4173            None => false,
 4174        };
 4175
 4176        pending_nonempty_selection
 4177            || (self.columnar_selection_state.is_some()
 4178                && self.selections.disjoint_anchors().len() > 1)
 4179    }
 4180
 4181    pub fn has_pending_selection(&self) -> bool {
 4182        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4183    }
 4184
 4185    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4186        self.selection_mark_mode = false;
 4187        self.selection_drag_state = SelectionDragState::None;
 4188
 4189        if self.dismiss_menus_and_popups(true, window, cx) {
 4190            cx.notify();
 4191            return;
 4192        }
 4193        if self.clear_expanded_diff_hunks(cx) {
 4194            cx.notify();
 4195            return;
 4196        }
 4197        if self.show_git_blame_gutter {
 4198            self.show_git_blame_gutter = false;
 4199            cx.notify();
 4200            return;
 4201        }
 4202
 4203        if self.mode.is_full()
 4204            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4205        {
 4206            cx.notify();
 4207            return;
 4208        }
 4209
 4210        cx.propagate();
 4211    }
 4212
 4213    pub fn dismiss_menus_and_popups(
 4214        &mut self,
 4215        is_user_requested: bool,
 4216        window: &mut Window,
 4217        cx: &mut Context<Self>,
 4218    ) -> bool {
 4219        let mut dismissed = false;
 4220
 4221        dismissed |= self.take_rename(false, window, cx).is_some();
 4222        dismissed |= self.hide_blame_popover(true, cx);
 4223        dismissed |= hide_hover(self, cx);
 4224        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4225        dismissed |= self.hide_context_menu(window, cx).is_some();
 4226        dismissed |= self.mouse_context_menu.take().is_some();
 4227        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4228        dismissed |= self.snippet_stack.pop().is_some();
 4229
 4230        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4231            self.dismiss_diagnostics(cx);
 4232            dismissed = true;
 4233        }
 4234
 4235        dismissed
 4236    }
 4237
 4238    fn linked_editing_ranges_for(
 4239        &self,
 4240        selection: Range<text::Anchor>,
 4241        cx: &App,
 4242    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4243        if self.linked_edit_ranges.is_empty() {
 4244            return None;
 4245        }
 4246        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4247            selection.end.buffer_id.and_then(|end_buffer_id| {
 4248                if selection.start.buffer_id != Some(end_buffer_id) {
 4249                    return None;
 4250                }
 4251                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4252                let snapshot = buffer.read(cx).snapshot();
 4253                self.linked_edit_ranges
 4254                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4255                    .map(|ranges| (ranges, snapshot, buffer))
 4256            })?;
 4257        use text::ToOffset as TO;
 4258        // find offset from the start of current range to current cursor position
 4259        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4260
 4261        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4262        let start_difference = start_offset - start_byte_offset;
 4263        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4264        let end_difference = end_offset - start_byte_offset;
 4265        // Current range has associated linked ranges.
 4266        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4267        for range in linked_ranges.iter() {
 4268            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4269            let end_offset = start_offset + end_difference;
 4270            let start_offset = start_offset + start_difference;
 4271            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4272                continue;
 4273            }
 4274            if self.selections.disjoint_anchor_ranges().any(|s| {
 4275                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4276                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4277                {
 4278                    return false;
 4279                }
 4280                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4281                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4282            }) {
 4283                continue;
 4284            }
 4285            let start = buffer_snapshot.anchor_after(start_offset);
 4286            let end = buffer_snapshot.anchor_after(end_offset);
 4287            linked_edits
 4288                .entry(buffer.clone())
 4289                .or_default()
 4290                .push(start..end);
 4291        }
 4292        Some(linked_edits)
 4293    }
 4294
 4295    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4296        let text: Arc<str> = text.into();
 4297
 4298        if self.read_only(cx) {
 4299            return;
 4300        }
 4301
 4302        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4303
 4304        self.unfold_buffers_with_selections(cx);
 4305
 4306        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4307        let mut bracket_inserted = false;
 4308        let mut edits = Vec::new();
 4309        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4310        let mut new_selections = Vec::with_capacity(selections.len());
 4311        let mut new_autoclose_regions = Vec::new();
 4312        let snapshot = self.buffer.read(cx).read(cx);
 4313        let mut clear_linked_edit_ranges = false;
 4314
 4315        for (selection, autoclose_region) in
 4316            self.selections_with_autoclose_regions(selections, &snapshot)
 4317        {
 4318            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4319                // Determine if the inserted text matches the opening or closing
 4320                // bracket of any of this language's bracket pairs.
 4321                let mut bracket_pair = None;
 4322                let mut is_bracket_pair_start = false;
 4323                let mut is_bracket_pair_end = false;
 4324                if !text.is_empty() {
 4325                    let mut bracket_pair_matching_end = None;
 4326                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4327                    //  and they are removing the character that triggered IME popup.
 4328                    for (pair, enabled) in scope.brackets() {
 4329                        if !pair.close && !pair.surround {
 4330                            continue;
 4331                        }
 4332
 4333                        if enabled && pair.start.ends_with(text.as_ref()) {
 4334                            let prefix_len = pair.start.len() - text.len();
 4335                            let preceding_text_matches_prefix = prefix_len == 0
 4336                                || (selection.start.column >= (prefix_len as u32)
 4337                                    && snapshot.contains_str_at(
 4338                                        Point::new(
 4339                                            selection.start.row,
 4340                                            selection.start.column - (prefix_len as u32),
 4341                                        ),
 4342                                        &pair.start[..prefix_len],
 4343                                    ));
 4344                            if preceding_text_matches_prefix {
 4345                                bracket_pair = Some(pair.clone());
 4346                                is_bracket_pair_start = true;
 4347                                break;
 4348                            }
 4349                        }
 4350                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4351                        {
 4352                            // take first bracket pair matching end, but don't break in case a later bracket
 4353                            // pair matches start
 4354                            bracket_pair_matching_end = Some(pair.clone());
 4355                        }
 4356                    }
 4357                    if let Some(end) = bracket_pair_matching_end
 4358                        && bracket_pair.is_none()
 4359                    {
 4360                        bracket_pair = Some(end);
 4361                        is_bracket_pair_end = true;
 4362                    }
 4363                }
 4364
 4365                if let Some(bracket_pair) = bracket_pair {
 4366                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4367                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4368                    let auto_surround =
 4369                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4370                    if selection.is_empty() {
 4371                        if is_bracket_pair_start {
 4372                            // If the inserted text is a suffix of an opening bracket and the
 4373                            // selection is preceded by the rest of the opening bracket, then
 4374                            // insert the closing bracket.
 4375                            let following_text_allows_autoclose = snapshot
 4376                                .chars_at(selection.start)
 4377                                .next()
 4378                                .is_none_or(|c| scope.should_autoclose_before(c));
 4379
 4380                            let preceding_text_allows_autoclose = selection.start.column == 0
 4381                                || snapshot
 4382                                    .reversed_chars_at(selection.start)
 4383                                    .next()
 4384                                    .is_none_or(|c| {
 4385                                        bracket_pair.start != bracket_pair.end
 4386                                            || !snapshot
 4387                                                .char_classifier_at(selection.start)
 4388                                                .is_word(c)
 4389                                    });
 4390
 4391                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4392                                && bracket_pair.start.len() == 1
 4393                            {
 4394                                let target = bracket_pair.start.chars().next().unwrap();
 4395                                let mut byte_offset = 0u32;
 4396                                let current_line_count = snapshot
 4397                                    .reversed_chars_at(selection.start)
 4398                                    .take_while(|&c| c != '\n')
 4399                                    .filter(|c| {
 4400                                        byte_offset += c.len_utf8() as u32;
 4401                                        if *c != target {
 4402                                            return false;
 4403                                        }
 4404
 4405                                        let point = Point::new(
 4406                                            selection.start.row,
 4407                                            selection.start.column.saturating_sub(byte_offset),
 4408                                        );
 4409
 4410                                        let is_enabled = snapshot
 4411                                            .language_scope_at(point)
 4412                                            .and_then(|scope| {
 4413                                                scope
 4414                                                    .brackets()
 4415                                                    .find(|(pair, _)| {
 4416                                                        pair.start == bracket_pair.start
 4417                                                    })
 4418                                                    .map(|(_, enabled)| enabled)
 4419                                            })
 4420                                            .unwrap_or(true);
 4421
 4422                                        let is_delimiter = snapshot
 4423                                            .language_scope_at(Point::new(
 4424                                                point.row,
 4425                                                point.column + 1,
 4426                                            ))
 4427                                            .and_then(|scope| {
 4428                                                scope
 4429                                                    .brackets()
 4430                                                    .find(|(pair, _)| {
 4431                                                        pair.start == bracket_pair.start
 4432                                                    })
 4433                                                    .map(|(_, enabled)| !enabled)
 4434                                            })
 4435                                            .unwrap_or(false);
 4436
 4437                                        is_enabled && !is_delimiter
 4438                                    })
 4439                                    .count();
 4440                                current_line_count % 2 == 1
 4441                            } else {
 4442                                false
 4443                            };
 4444
 4445                            if autoclose
 4446                                && bracket_pair.close
 4447                                && following_text_allows_autoclose
 4448                                && preceding_text_allows_autoclose
 4449                                && !is_closing_quote
 4450                            {
 4451                                let anchor = snapshot.anchor_before(selection.end);
 4452                                new_selections.push((selection.map(|_| anchor), text.len()));
 4453                                new_autoclose_regions.push((
 4454                                    anchor,
 4455                                    text.len(),
 4456                                    selection.id,
 4457                                    bracket_pair.clone(),
 4458                                ));
 4459                                edits.push((
 4460                                    selection.range(),
 4461                                    format!("{}{}", text, bracket_pair.end).into(),
 4462                                ));
 4463                                bracket_inserted = true;
 4464                                continue;
 4465                            }
 4466                        }
 4467
 4468                        if let Some(region) = autoclose_region {
 4469                            // If the selection is followed by an auto-inserted closing bracket,
 4470                            // then don't insert that closing bracket again; just move the selection
 4471                            // past the closing bracket.
 4472                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4473                                && text.as_ref() == region.pair.end.as_str()
 4474                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4475                            if should_skip {
 4476                                let anchor = snapshot.anchor_after(selection.end);
 4477                                new_selections
 4478                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4479                                continue;
 4480                            }
 4481                        }
 4482
 4483                        let always_treat_brackets_as_autoclosed = snapshot
 4484                            .language_settings_at(selection.start, cx)
 4485                            .always_treat_brackets_as_autoclosed;
 4486                        if always_treat_brackets_as_autoclosed
 4487                            && is_bracket_pair_end
 4488                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4489                        {
 4490                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4491                            // and the inserted text is a closing bracket and the selection is followed
 4492                            // by the closing bracket then move the selection past the closing bracket.
 4493                            let anchor = snapshot.anchor_after(selection.end);
 4494                            new_selections.push((selection.map(|_| anchor), text.len()));
 4495                            continue;
 4496                        }
 4497                    }
 4498                    // If an opening bracket is 1 character long and is typed while
 4499                    // text is selected, then surround that text with the bracket pair.
 4500                    else if auto_surround
 4501                        && bracket_pair.surround
 4502                        && is_bracket_pair_start
 4503                        && bracket_pair.start.chars().count() == 1
 4504                    {
 4505                        edits.push((selection.start..selection.start, text.clone()));
 4506                        edits.push((
 4507                            selection.end..selection.end,
 4508                            bracket_pair.end.as_str().into(),
 4509                        ));
 4510                        bracket_inserted = true;
 4511                        new_selections.push((
 4512                            Selection {
 4513                                id: selection.id,
 4514                                start: snapshot.anchor_after(selection.start),
 4515                                end: snapshot.anchor_before(selection.end),
 4516                                reversed: selection.reversed,
 4517                                goal: selection.goal,
 4518                            },
 4519                            0,
 4520                        ));
 4521                        continue;
 4522                    }
 4523                }
 4524            }
 4525
 4526            if self.auto_replace_emoji_shortcode
 4527                && selection.is_empty()
 4528                && text.as_ref().ends_with(':')
 4529                && let Some(possible_emoji_short_code) =
 4530                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4531                && !possible_emoji_short_code.is_empty()
 4532                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4533            {
 4534                let emoji_shortcode_start = Point::new(
 4535                    selection.start.row,
 4536                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4537                );
 4538
 4539                // Remove shortcode from buffer
 4540                edits.push((
 4541                    emoji_shortcode_start..selection.start,
 4542                    "".to_string().into(),
 4543                ));
 4544                new_selections.push((
 4545                    Selection {
 4546                        id: selection.id,
 4547                        start: snapshot.anchor_after(emoji_shortcode_start),
 4548                        end: snapshot.anchor_before(selection.start),
 4549                        reversed: selection.reversed,
 4550                        goal: selection.goal,
 4551                    },
 4552                    0,
 4553                ));
 4554
 4555                // Insert emoji
 4556                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4557                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4558                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4559
 4560                continue;
 4561            }
 4562
 4563            // If not handling any auto-close operation, then just replace the selected
 4564            // text with the given input and move the selection to the end of the
 4565            // newly inserted text.
 4566            let anchor = snapshot.anchor_after(selection.end);
 4567            if !self.linked_edit_ranges.is_empty() {
 4568                let start_anchor = snapshot.anchor_before(selection.start);
 4569
 4570                let is_word_char = text.chars().next().is_none_or(|char| {
 4571                    let classifier = snapshot
 4572                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4573                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4574                    classifier.is_word(char)
 4575                });
 4576
 4577                if is_word_char {
 4578                    if let Some(ranges) = self
 4579                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4580                    {
 4581                        for (buffer, edits) in ranges {
 4582                            linked_edits
 4583                                .entry(buffer.clone())
 4584                                .or_default()
 4585                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4586                        }
 4587                    }
 4588                } else {
 4589                    clear_linked_edit_ranges = true;
 4590                }
 4591            }
 4592
 4593            new_selections.push((selection.map(|_| anchor), 0));
 4594            edits.push((selection.start..selection.end, text.clone()));
 4595        }
 4596
 4597        drop(snapshot);
 4598
 4599        self.transact(window, cx, |this, window, cx| {
 4600            if clear_linked_edit_ranges {
 4601                this.linked_edit_ranges.clear();
 4602            }
 4603            let initial_buffer_versions =
 4604                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4605
 4606            this.buffer.update(cx, |buffer, cx| {
 4607                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4608            });
 4609            for (buffer, edits) in linked_edits {
 4610                buffer.update(cx, |buffer, cx| {
 4611                    let snapshot = buffer.snapshot();
 4612                    let edits = edits
 4613                        .into_iter()
 4614                        .map(|(range, text)| {
 4615                            use text::ToPoint as TP;
 4616                            let end_point = TP::to_point(&range.end, &snapshot);
 4617                            let start_point = TP::to_point(&range.start, &snapshot);
 4618                            (start_point..end_point, text)
 4619                        })
 4620                        .sorted_by_key(|(range, _)| range.start);
 4621                    buffer.edit(edits, None, cx);
 4622                })
 4623            }
 4624            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4625            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4626            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4627            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4628                new_anchor_selections,
 4629                &map,
 4630            )
 4631            .zip(new_selection_deltas)
 4632            .map(|(selection, delta)| Selection {
 4633                id: selection.id,
 4634                start: selection.start + delta,
 4635                end: selection.end + delta,
 4636                reversed: selection.reversed,
 4637                goal: SelectionGoal::None,
 4638            })
 4639            .collect::<Vec<_>>();
 4640
 4641            let mut i = 0;
 4642            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4643                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4644                let start = map.buffer_snapshot().anchor_before(position);
 4645                let end = map.buffer_snapshot().anchor_after(position);
 4646                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4647                    match existing_state
 4648                        .range
 4649                        .start
 4650                        .cmp(&start, map.buffer_snapshot())
 4651                    {
 4652                        Ordering::Less => i += 1,
 4653                        Ordering::Greater => break,
 4654                        Ordering::Equal => {
 4655                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4656                                Ordering::Less => i += 1,
 4657                                Ordering::Equal => break,
 4658                                Ordering::Greater => break,
 4659                            }
 4660                        }
 4661                    }
 4662                }
 4663                this.autoclose_regions.insert(
 4664                    i,
 4665                    AutocloseRegion {
 4666                        selection_id,
 4667                        range: start..end,
 4668                        pair,
 4669                    },
 4670                );
 4671            }
 4672
 4673            let had_active_edit_prediction = this.has_active_edit_prediction();
 4674            this.change_selections(
 4675                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4676                window,
 4677                cx,
 4678                |s| s.select(new_selections),
 4679            );
 4680
 4681            if !bracket_inserted
 4682                && let Some(on_type_format_task) =
 4683                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4684            {
 4685                on_type_format_task.detach_and_log_err(cx);
 4686            }
 4687
 4688            let editor_settings = EditorSettings::get_global(cx);
 4689            if bracket_inserted
 4690                && (editor_settings.auto_signature_help
 4691                    || editor_settings.show_signature_help_after_edits)
 4692            {
 4693                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4694            }
 4695
 4696            let trigger_in_words =
 4697                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4698            if this.hard_wrap.is_some() {
 4699                let latest: Range<Point> = this.selections.newest(&map).range();
 4700                if latest.is_empty()
 4701                    && this
 4702                        .buffer()
 4703                        .read(cx)
 4704                        .snapshot(cx)
 4705                        .line_len(MultiBufferRow(latest.start.row))
 4706                        == latest.start.column
 4707                {
 4708                    this.rewrap_impl(
 4709                        RewrapOptions {
 4710                            override_language_settings: true,
 4711                            preserve_existing_whitespace: true,
 4712                        },
 4713                        cx,
 4714                    )
 4715                }
 4716            }
 4717            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4718            refresh_linked_ranges(this, window, cx);
 4719            this.refresh_edit_prediction(true, false, window, cx);
 4720            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4721        });
 4722    }
 4723
 4724    fn find_possible_emoji_shortcode_at_position(
 4725        snapshot: &MultiBufferSnapshot,
 4726        position: Point,
 4727    ) -> Option<String> {
 4728        let mut chars = Vec::new();
 4729        let mut found_colon = false;
 4730        for char in snapshot.reversed_chars_at(position).take(100) {
 4731            // Found a possible emoji shortcode in the middle of the buffer
 4732            if found_colon {
 4733                if char.is_whitespace() {
 4734                    chars.reverse();
 4735                    return Some(chars.iter().collect());
 4736                }
 4737                // If the previous character is not a whitespace, we are in the middle of a word
 4738                // and we only want to complete the shortcode if the word is made up of other emojis
 4739                let mut containing_word = String::new();
 4740                for ch in snapshot
 4741                    .reversed_chars_at(position)
 4742                    .skip(chars.len() + 1)
 4743                    .take(100)
 4744                {
 4745                    if ch.is_whitespace() {
 4746                        break;
 4747                    }
 4748                    containing_word.push(ch);
 4749                }
 4750                let containing_word = containing_word.chars().rev().collect::<String>();
 4751                if util::word_consists_of_emojis(containing_word.as_str()) {
 4752                    chars.reverse();
 4753                    return Some(chars.iter().collect());
 4754                }
 4755            }
 4756
 4757            if char.is_whitespace() || !char.is_ascii() {
 4758                return None;
 4759            }
 4760            if char == ':' {
 4761                found_colon = true;
 4762            } else {
 4763                chars.push(char);
 4764            }
 4765        }
 4766        // Found a possible emoji shortcode at the beginning of the buffer
 4767        chars.reverse();
 4768        Some(chars.iter().collect())
 4769    }
 4770
 4771    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4772        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4773        self.transact(window, cx, |this, window, cx| {
 4774            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4775                let selections = this
 4776                    .selections
 4777                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4778                let multi_buffer = this.buffer.read(cx);
 4779                let buffer = multi_buffer.snapshot(cx);
 4780                selections
 4781                    .iter()
 4782                    .map(|selection| {
 4783                        let start_point = selection.start.to_point(&buffer);
 4784                        let mut existing_indent =
 4785                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4786                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4787                        let start = selection.start;
 4788                        let end = selection.end;
 4789                        let selection_is_empty = start == end;
 4790                        let language_scope = buffer.language_scope_at(start);
 4791                        let (delimiter, newline_config) = if let Some(language) = &language_scope {
 4792                            let needs_extra_newline = NewlineConfig::insert_extra_newline_brackets(
 4793                                &buffer,
 4794                                start..end,
 4795                                language,
 4796                            )
 4797                                || NewlineConfig::insert_extra_newline_tree_sitter(
 4798                                    &buffer,
 4799                                    start..end,
 4800                                );
 4801
 4802                            let mut newline_config = NewlineConfig::Newline {
 4803                                additional_indent: IndentSize::spaces(0),
 4804                                extra_line_additional_indent: if needs_extra_newline {
 4805                                    Some(IndentSize::spaces(0))
 4806                                } else {
 4807                                    None
 4808                                },
 4809                                prevent_auto_indent: false,
 4810                            };
 4811
 4812                            let comment_delimiter = maybe!({
 4813                                if !selection_is_empty {
 4814                                    return None;
 4815                                }
 4816
 4817                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4818                                    return None;
 4819                                }
 4820
 4821                                return comment_delimiter_for_newline(
 4822                                    &start_point,
 4823                                    &buffer,
 4824                                    language,
 4825                                );
 4826                            });
 4827
 4828                            let doc_delimiter = maybe!({
 4829                                if !selection_is_empty {
 4830                                    return None;
 4831                                }
 4832
 4833                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4834                                    return None;
 4835                                }
 4836
 4837                                return documentation_delimiter_for_newline(
 4838                                    &start_point,
 4839                                    &buffer,
 4840                                    language,
 4841                                    &mut newline_config,
 4842                                );
 4843                            });
 4844
 4845                            let list_delimiter = maybe!({
 4846                                if !selection_is_empty {
 4847                                    return None;
 4848                                }
 4849
 4850                                if !multi_buffer.language_settings(cx).extend_list_on_newline {
 4851                                    return None;
 4852                                }
 4853
 4854                                return list_delimiter_for_newline(
 4855                                    &start_point,
 4856                                    &buffer,
 4857                                    language,
 4858                                    &mut newline_config,
 4859                                );
 4860                            });
 4861
 4862                            (
 4863                                comment_delimiter.or(doc_delimiter).or(list_delimiter),
 4864                                newline_config,
 4865                            )
 4866                        } else {
 4867                            (
 4868                                None,
 4869                                NewlineConfig::Newline {
 4870                                    additional_indent: IndentSize::spaces(0),
 4871                                    extra_line_additional_indent: None,
 4872                                    prevent_auto_indent: false,
 4873                                },
 4874                            )
 4875                        };
 4876
 4877                        let (edit_start, new_text, prevent_auto_indent) = match &newline_config {
 4878                            NewlineConfig::ClearCurrentLine => {
 4879                                let row_start =
 4880                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 4881                                (row_start, String::new(), false)
 4882                            }
 4883                            NewlineConfig::UnindentCurrentLine { continuation } => {
 4884                                let row_start =
 4885                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 4886                                let tab_size = buffer.language_settings_at(start, cx).tab_size;
 4887                                let tab_size_indent = IndentSize::spaces(tab_size.get());
 4888                                let reduced_indent =
 4889                                    existing_indent.with_delta(Ordering::Less, tab_size_indent);
 4890                                let mut new_text = String::new();
 4891                                new_text.extend(reduced_indent.chars());
 4892                                new_text.push_str(continuation);
 4893                                (row_start, new_text, true)
 4894                            }
 4895                            NewlineConfig::Newline {
 4896                                additional_indent,
 4897                                extra_line_additional_indent,
 4898                                prevent_auto_indent,
 4899                            } => {
 4900                                let capacity_for_delimiter =
 4901                                    delimiter.as_deref().map(str::len).unwrap_or_default();
 4902                                let extra_line_len = extra_line_additional_indent
 4903                                    .map(|i| 1 + existing_indent.len as usize + i.len as usize)
 4904                                    .unwrap_or(0);
 4905                                let mut new_text = String::with_capacity(
 4906                                    1 + capacity_for_delimiter
 4907                                        + existing_indent.len as usize
 4908                                        + additional_indent.len as usize
 4909                                        + extra_line_len,
 4910                                );
 4911                                new_text.push('\n');
 4912                                new_text.extend(existing_indent.chars());
 4913                                new_text.extend(additional_indent.chars());
 4914                                if let Some(delimiter) = &delimiter {
 4915                                    new_text.push_str(delimiter);
 4916                                }
 4917                                if let Some(extra_indent) = extra_line_additional_indent {
 4918                                    new_text.push('\n');
 4919                                    new_text.extend(existing_indent.chars());
 4920                                    new_text.extend(extra_indent.chars());
 4921                                }
 4922                                (start, new_text, *prevent_auto_indent)
 4923                            }
 4924                        };
 4925
 4926                        let anchor = buffer.anchor_after(end);
 4927                        let new_selection = selection.map(|_| anchor);
 4928                        (
 4929                            ((edit_start..end, new_text), prevent_auto_indent),
 4930                            (newline_config.has_extra_line(), new_selection),
 4931                        )
 4932                    })
 4933                    .unzip()
 4934            };
 4935
 4936            let mut auto_indent_edits = Vec::new();
 4937            let mut edits = Vec::new();
 4938            for (edit, prevent_auto_indent) in edits_with_flags {
 4939                if prevent_auto_indent {
 4940                    edits.push(edit);
 4941                } else {
 4942                    auto_indent_edits.push(edit);
 4943                }
 4944            }
 4945            if !edits.is_empty() {
 4946                this.edit(edits, cx);
 4947            }
 4948            if !auto_indent_edits.is_empty() {
 4949                this.edit_with_autoindent(auto_indent_edits, cx);
 4950            }
 4951
 4952            let buffer = this.buffer.read(cx).snapshot(cx);
 4953            let new_selections = selection_info
 4954                .into_iter()
 4955                .map(|(extra_newline_inserted, new_selection)| {
 4956                    let mut cursor = new_selection.end.to_point(&buffer);
 4957                    if extra_newline_inserted {
 4958                        cursor.row -= 1;
 4959                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4960                    }
 4961                    new_selection.map(|_| cursor)
 4962                })
 4963                .collect();
 4964
 4965            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4966            this.refresh_edit_prediction(true, false, window, cx);
 4967            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 4968                task.detach_and_log_err(cx);
 4969            }
 4970        });
 4971    }
 4972
 4973    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4974        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4975
 4976        let buffer = self.buffer.read(cx);
 4977        let snapshot = buffer.snapshot(cx);
 4978
 4979        let mut edits = Vec::new();
 4980        let mut rows = Vec::new();
 4981
 4982        for (rows_inserted, selection) in self
 4983            .selections
 4984            .all_adjusted(&self.display_snapshot(cx))
 4985            .into_iter()
 4986            .enumerate()
 4987        {
 4988            let cursor = selection.head();
 4989            let row = cursor.row;
 4990
 4991            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4992
 4993            let newline = "\n".to_string();
 4994            edits.push((start_of_line..start_of_line, newline));
 4995
 4996            rows.push(row + rows_inserted as u32);
 4997        }
 4998
 4999        self.transact(window, cx, |editor, window, cx| {
 5000            editor.edit(edits, cx);
 5001
 5002            editor.change_selections(Default::default(), window, cx, |s| {
 5003                let mut index = 0;
 5004                s.move_cursors_with(|map, _, _| {
 5005                    let row = rows[index];
 5006                    index += 1;
 5007
 5008                    let point = Point::new(row, 0);
 5009                    let boundary = map.next_line_boundary(point).1;
 5010                    let clipped = map.clip_point(boundary, Bias::Left);
 5011
 5012                    (clipped, SelectionGoal::None)
 5013                });
 5014            });
 5015
 5016            let mut indent_edits = Vec::new();
 5017            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5018            for row in rows {
 5019                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5020                for (row, indent) in indents {
 5021                    if indent.len == 0 {
 5022                        continue;
 5023                    }
 5024
 5025                    let text = match indent.kind {
 5026                        IndentKind::Space => " ".repeat(indent.len as usize),
 5027                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5028                    };
 5029                    let point = Point::new(row.0, 0);
 5030                    indent_edits.push((point..point, text));
 5031                }
 5032            }
 5033            editor.edit(indent_edits, cx);
 5034            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5035                format.detach_and_log_err(cx);
 5036            }
 5037        });
 5038    }
 5039
 5040    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5041        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5042
 5043        let buffer = self.buffer.read(cx);
 5044        let snapshot = buffer.snapshot(cx);
 5045
 5046        let mut edits = Vec::new();
 5047        let mut rows = Vec::new();
 5048        let mut rows_inserted = 0;
 5049
 5050        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5051            let cursor = selection.head();
 5052            let row = cursor.row;
 5053
 5054            let point = Point::new(row + 1, 0);
 5055            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5056
 5057            let newline = "\n".to_string();
 5058            edits.push((start_of_line..start_of_line, newline));
 5059
 5060            rows_inserted += 1;
 5061            rows.push(row + rows_inserted);
 5062        }
 5063
 5064        self.transact(window, cx, |editor, window, cx| {
 5065            editor.edit(edits, cx);
 5066
 5067            editor.change_selections(Default::default(), window, cx, |s| {
 5068                let mut index = 0;
 5069                s.move_cursors_with(|map, _, _| {
 5070                    let row = rows[index];
 5071                    index += 1;
 5072
 5073                    let point = Point::new(row, 0);
 5074                    let boundary = map.next_line_boundary(point).1;
 5075                    let clipped = map.clip_point(boundary, Bias::Left);
 5076
 5077                    (clipped, SelectionGoal::None)
 5078                });
 5079            });
 5080
 5081            let mut indent_edits = Vec::new();
 5082            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5083            for row in rows {
 5084                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5085                for (row, indent) in indents {
 5086                    if indent.len == 0 {
 5087                        continue;
 5088                    }
 5089
 5090                    let text = match indent.kind {
 5091                        IndentKind::Space => " ".repeat(indent.len as usize),
 5092                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5093                    };
 5094                    let point = Point::new(row.0, 0);
 5095                    indent_edits.push((point..point, text));
 5096                }
 5097            }
 5098            editor.edit(indent_edits, cx);
 5099            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5100                format.detach_and_log_err(cx);
 5101            }
 5102        });
 5103    }
 5104
 5105    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5106        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5107            original_indent_columns: Vec::new(),
 5108        });
 5109        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5110    }
 5111
 5112    fn insert_with_autoindent_mode(
 5113        &mut self,
 5114        text: &str,
 5115        autoindent_mode: Option<AutoindentMode>,
 5116        window: &mut Window,
 5117        cx: &mut Context<Self>,
 5118    ) {
 5119        if self.read_only(cx) {
 5120            return;
 5121        }
 5122
 5123        let text: Arc<str> = text.into();
 5124        self.transact(window, cx, |this, window, cx| {
 5125            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5126            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5127                let anchors = {
 5128                    let snapshot = buffer.read(cx);
 5129                    old_selections
 5130                        .iter()
 5131                        .map(|s| {
 5132                            let anchor = snapshot.anchor_after(s.head());
 5133                            s.map(|_| anchor)
 5134                        })
 5135                        .collect::<Vec<_>>()
 5136                };
 5137                buffer.edit(
 5138                    old_selections
 5139                        .iter()
 5140                        .map(|s| (s.start..s.end, text.clone())),
 5141                    autoindent_mode,
 5142                    cx,
 5143                );
 5144                anchors
 5145            });
 5146
 5147            this.change_selections(Default::default(), window, cx, |s| {
 5148                s.select_anchors(selection_anchors);
 5149            });
 5150
 5151            cx.notify();
 5152        });
 5153    }
 5154
 5155    fn trigger_completion_on_input(
 5156        &mut self,
 5157        text: &str,
 5158        trigger_in_words: bool,
 5159        window: &mut Window,
 5160        cx: &mut Context<Self>,
 5161    ) {
 5162        let completions_source = self
 5163            .context_menu
 5164            .borrow()
 5165            .as_ref()
 5166            .and_then(|menu| match menu {
 5167                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5168                CodeContextMenu::CodeActions(_) => None,
 5169            });
 5170
 5171        match completions_source {
 5172            Some(CompletionsMenuSource::Words { .. }) => {
 5173                self.open_or_update_completions_menu(
 5174                    Some(CompletionsMenuSource::Words {
 5175                        ignore_threshold: false,
 5176                    }),
 5177                    None,
 5178                    trigger_in_words,
 5179                    window,
 5180                    cx,
 5181                );
 5182            }
 5183            _ => self.open_or_update_completions_menu(
 5184                None,
 5185                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5186                true,
 5187                window,
 5188                cx,
 5189            ),
 5190        }
 5191    }
 5192
 5193    /// If any empty selections is touching the start of its innermost containing autoclose
 5194    /// region, expand it to select the brackets.
 5195    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5196        let selections = self
 5197            .selections
 5198            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5199        let buffer = self.buffer.read(cx).read(cx);
 5200        let new_selections = self
 5201            .selections_with_autoclose_regions(selections, &buffer)
 5202            .map(|(mut selection, region)| {
 5203                if !selection.is_empty() {
 5204                    return selection;
 5205                }
 5206
 5207                if let Some(region) = region {
 5208                    let mut range = region.range.to_offset(&buffer);
 5209                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5210                        range.start -= region.pair.start.len();
 5211                        if buffer.contains_str_at(range.start, &region.pair.start)
 5212                            && buffer.contains_str_at(range.end, &region.pair.end)
 5213                        {
 5214                            range.end += region.pair.end.len();
 5215                            selection.start = range.start;
 5216                            selection.end = range.end;
 5217
 5218                            return selection;
 5219                        }
 5220                    }
 5221                }
 5222
 5223                let always_treat_brackets_as_autoclosed = buffer
 5224                    .language_settings_at(selection.start, cx)
 5225                    .always_treat_brackets_as_autoclosed;
 5226
 5227                if !always_treat_brackets_as_autoclosed {
 5228                    return selection;
 5229                }
 5230
 5231                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5232                    for (pair, enabled) in scope.brackets() {
 5233                        if !enabled || !pair.close {
 5234                            continue;
 5235                        }
 5236
 5237                        if buffer.contains_str_at(selection.start, &pair.end) {
 5238                            let pair_start_len = pair.start.len();
 5239                            if buffer.contains_str_at(
 5240                                selection.start.saturating_sub_usize(pair_start_len),
 5241                                &pair.start,
 5242                            ) {
 5243                                selection.start -= pair_start_len;
 5244                                selection.end += pair.end.len();
 5245
 5246                                return selection;
 5247                            }
 5248                        }
 5249                    }
 5250                }
 5251
 5252                selection
 5253            })
 5254            .collect();
 5255
 5256        drop(buffer);
 5257        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5258            selections.select(new_selections)
 5259        });
 5260    }
 5261
 5262    /// Iterate the given selections, and for each one, find the smallest surrounding
 5263    /// autoclose region. This uses the ordering of the selections and the autoclose
 5264    /// regions to avoid repeated comparisons.
 5265    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5266        &'a self,
 5267        selections: impl IntoIterator<Item = Selection<D>>,
 5268        buffer: &'a MultiBufferSnapshot,
 5269    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5270        let mut i = 0;
 5271        let mut regions = self.autoclose_regions.as_slice();
 5272        selections.into_iter().map(move |selection| {
 5273            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5274
 5275            let mut enclosing = None;
 5276            while let Some(pair_state) = regions.get(i) {
 5277                if pair_state.range.end.to_offset(buffer) < range.start {
 5278                    regions = &regions[i + 1..];
 5279                    i = 0;
 5280                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5281                    break;
 5282                } else {
 5283                    if pair_state.selection_id == selection.id {
 5284                        enclosing = Some(pair_state);
 5285                    }
 5286                    i += 1;
 5287                }
 5288            }
 5289
 5290            (selection, enclosing)
 5291        })
 5292    }
 5293
 5294    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5295    fn invalidate_autoclose_regions(
 5296        &mut self,
 5297        mut selections: &[Selection<Anchor>],
 5298        buffer: &MultiBufferSnapshot,
 5299    ) {
 5300        self.autoclose_regions.retain(|state| {
 5301            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5302                return false;
 5303            }
 5304
 5305            let mut i = 0;
 5306            while let Some(selection) = selections.get(i) {
 5307                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5308                    selections = &selections[1..];
 5309                    continue;
 5310                }
 5311                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5312                    break;
 5313                }
 5314                if selection.id == state.selection_id {
 5315                    return true;
 5316                } else {
 5317                    i += 1;
 5318                }
 5319            }
 5320            false
 5321        });
 5322    }
 5323
 5324    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5325        let offset = position.to_offset(buffer);
 5326        let (word_range, kind) =
 5327            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5328        if offset > word_range.start && kind == Some(CharKind::Word) {
 5329            Some(
 5330                buffer
 5331                    .text_for_range(word_range.start..offset)
 5332                    .collect::<String>(),
 5333            )
 5334        } else {
 5335            None
 5336        }
 5337    }
 5338
 5339    pub fn visible_excerpts(
 5340        &self,
 5341        lsp_related_only: bool,
 5342        cx: &mut Context<Editor>,
 5343    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5344        let project = self.project().cloned();
 5345        let multi_buffer = self.buffer().read(cx);
 5346        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5347        let multi_buffer_visible_start = self
 5348            .scroll_manager
 5349            .anchor()
 5350            .anchor
 5351            .to_point(&multi_buffer_snapshot);
 5352        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5353            multi_buffer_visible_start
 5354                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5355            Bias::Left,
 5356        );
 5357        multi_buffer_snapshot
 5358            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5359            .into_iter()
 5360            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5361            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5362                if !lsp_related_only {
 5363                    return Some((
 5364                        excerpt_id,
 5365                        (
 5366                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5367                            buffer.version().clone(),
 5368                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5369                        ),
 5370                    ));
 5371                }
 5372
 5373                let project = project.as_ref()?.read(cx);
 5374                let buffer_file = project::File::from_dyn(buffer.file())?;
 5375                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5376                let worktree_entry = buffer_worktree
 5377                    .read(cx)
 5378                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5379                if worktree_entry.is_ignored {
 5380                    None
 5381                } else {
 5382                    Some((
 5383                        excerpt_id,
 5384                        (
 5385                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5386                            buffer.version().clone(),
 5387                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5388                        ),
 5389                    ))
 5390                }
 5391            })
 5392            .collect()
 5393    }
 5394
 5395    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5396        TextLayoutDetails {
 5397            text_system: window.text_system().clone(),
 5398            editor_style: self.style.clone().unwrap(),
 5399            rem_size: window.rem_size(),
 5400            scroll_anchor: self.scroll_manager.anchor(),
 5401            visible_rows: self.visible_line_count(),
 5402            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5403        }
 5404    }
 5405
 5406    fn trigger_on_type_formatting(
 5407        &self,
 5408        input: String,
 5409        window: &mut Window,
 5410        cx: &mut Context<Self>,
 5411    ) -> Option<Task<Result<()>>> {
 5412        if input.chars().count() != 1 {
 5413            return None;
 5414        }
 5415
 5416        let project = self.project()?;
 5417        let position = self.selections.newest_anchor().head();
 5418        let (buffer, buffer_position) = self
 5419            .buffer
 5420            .read(cx)
 5421            .text_anchor_for_position(position, cx)?;
 5422
 5423        let settings = language_settings::language_settings(
 5424            buffer
 5425                .read(cx)
 5426                .language_at(buffer_position)
 5427                .map(|l| l.name()),
 5428            buffer.read(cx).file(),
 5429            cx,
 5430        );
 5431        if !settings.use_on_type_format {
 5432            return None;
 5433        }
 5434
 5435        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5436        // hence we do LSP request & edit on host side only — add formats to host's history.
 5437        let push_to_lsp_host_history = true;
 5438        // If this is not the host, append its history with new edits.
 5439        let push_to_client_history = project.read(cx).is_via_collab();
 5440
 5441        let on_type_formatting = project.update(cx, |project, cx| {
 5442            project.on_type_format(
 5443                buffer.clone(),
 5444                buffer_position,
 5445                input,
 5446                push_to_lsp_host_history,
 5447                cx,
 5448            )
 5449        });
 5450        Some(cx.spawn_in(window, async move |editor, cx| {
 5451            if let Some(transaction) = on_type_formatting.await? {
 5452                if push_to_client_history {
 5453                    buffer
 5454                        .update(cx, |buffer, _| {
 5455                            buffer.push_transaction(transaction, Instant::now());
 5456                            buffer.finalize_last_transaction();
 5457                        })
 5458                        .ok();
 5459                }
 5460                editor.update(cx, |editor, cx| {
 5461                    editor.refresh_document_highlights(cx);
 5462                })?;
 5463            }
 5464            Ok(())
 5465        }))
 5466    }
 5467
 5468    pub fn show_word_completions(
 5469        &mut self,
 5470        _: &ShowWordCompletions,
 5471        window: &mut Window,
 5472        cx: &mut Context<Self>,
 5473    ) {
 5474        self.open_or_update_completions_menu(
 5475            Some(CompletionsMenuSource::Words {
 5476                ignore_threshold: true,
 5477            }),
 5478            None,
 5479            false,
 5480            window,
 5481            cx,
 5482        );
 5483    }
 5484
 5485    pub fn show_completions(
 5486        &mut self,
 5487        _: &ShowCompletions,
 5488        window: &mut Window,
 5489        cx: &mut Context<Self>,
 5490    ) {
 5491        self.open_or_update_completions_menu(None, None, false, window, cx);
 5492    }
 5493
 5494    fn open_or_update_completions_menu(
 5495        &mut self,
 5496        requested_source: Option<CompletionsMenuSource>,
 5497        trigger: Option<String>,
 5498        trigger_in_words: bool,
 5499        window: &mut Window,
 5500        cx: &mut Context<Self>,
 5501    ) {
 5502        if self.pending_rename.is_some() {
 5503            return;
 5504        }
 5505
 5506        let completions_source = self
 5507            .context_menu
 5508            .borrow()
 5509            .as_ref()
 5510            .and_then(|menu| match menu {
 5511                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5512                CodeContextMenu::CodeActions(_) => None,
 5513            });
 5514
 5515        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5516
 5517        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5518        // inserted and selected. To handle that case, the start of the selection is used so that
 5519        // the menu starts with all choices.
 5520        let position = self
 5521            .selections
 5522            .newest_anchor()
 5523            .start
 5524            .bias_right(&multibuffer_snapshot);
 5525        if position.diff_base_anchor.is_some() {
 5526            return;
 5527        }
 5528        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5529        let Some(buffer) = buffer_position
 5530            .text_anchor
 5531            .buffer_id
 5532            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5533        else {
 5534            return;
 5535        };
 5536        let buffer_snapshot = buffer.read(cx).snapshot();
 5537
 5538        let menu_is_open = matches!(
 5539            self.context_menu.borrow().as_ref(),
 5540            Some(CodeContextMenu::Completions(_))
 5541        );
 5542
 5543        let language = buffer_snapshot
 5544            .language_at(buffer_position.text_anchor)
 5545            .map(|language| language.name());
 5546
 5547        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5548        let completion_settings = language_settings.completions.clone();
 5549
 5550        let show_completions_on_input = self
 5551            .show_completions_on_input_override
 5552            .unwrap_or(language_settings.show_completions_on_input);
 5553        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5554            return;
 5555        }
 5556
 5557        let query: Option<Arc<String>> =
 5558            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5559                .map(|query| query.into());
 5560
 5561        drop(multibuffer_snapshot);
 5562
 5563        // Hide the current completions menu when query is empty. Without this, cached
 5564        // completions from before the trigger char may be reused (#32774).
 5565        if query.is_none() && menu_is_open {
 5566            self.hide_context_menu(window, cx);
 5567        }
 5568
 5569        let mut ignore_word_threshold = false;
 5570        let provider = match requested_source {
 5571            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5572            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5573                ignore_word_threshold = ignore_threshold;
 5574                None
 5575            }
 5576            Some(CompletionsMenuSource::SnippetChoices)
 5577            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5578                log::error!("bug: SnippetChoices requested_source is not handled");
 5579                None
 5580            }
 5581        };
 5582
 5583        let sort_completions = provider
 5584            .as_ref()
 5585            .is_some_and(|provider| provider.sort_completions());
 5586
 5587        let filter_completions = provider
 5588            .as_ref()
 5589            .is_none_or(|provider| provider.filter_completions());
 5590
 5591        let was_snippets_only = matches!(
 5592            completions_source,
 5593            Some(CompletionsMenuSource::SnippetsOnly)
 5594        );
 5595
 5596        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5597            if filter_completions {
 5598                menu.filter(
 5599                    query.clone().unwrap_or_default(),
 5600                    buffer_position.text_anchor,
 5601                    &buffer,
 5602                    provider.clone(),
 5603                    window,
 5604                    cx,
 5605                );
 5606            }
 5607            // When `is_incomplete` is false, no need to re-query completions when the current query
 5608            // is a suffix of the initial query.
 5609            let was_complete = !menu.is_incomplete;
 5610            if was_complete && !was_snippets_only {
 5611                // If the new query is a suffix of the old query (typing more characters) and
 5612                // the previous result was complete, the existing completions can be filtered.
 5613                //
 5614                // Note that snippet completions are always complete.
 5615                let query_matches = match (&menu.initial_query, &query) {
 5616                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5617                    (None, _) => true,
 5618                    _ => false,
 5619                };
 5620                if query_matches {
 5621                    let position_matches = if menu.initial_position == position {
 5622                        true
 5623                    } else {
 5624                        let snapshot = self.buffer.read(cx).read(cx);
 5625                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5626                    };
 5627                    if position_matches {
 5628                        return;
 5629                    }
 5630                }
 5631            }
 5632        };
 5633
 5634        let Anchor {
 5635            excerpt_id: buffer_excerpt_id,
 5636            text_anchor: buffer_position,
 5637            ..
 5638        } = buffer_position;
 5639
 5640        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5641            buffer_snapshot.surrounding_word(buffer_position, None)
 5642        {
 5643            let word_to_exclude = buffer_snapshot
 5644                .text_for_range(word_range.clone())
 5645                .collect::<String>();
 5646            (
 5647                buffer_snapshot.anchor_before(word_range.start)
 5648                    ..buffer_snapshot.anchor_after(buffer_position),
 5649                Some(word_to_exclude),
 5650            )
 5651        } else {
 5652            (buffer_position..buffer_position, None)
 5653        };
 5654
 5655        let show_completion_documentation = buffer_snapshot
 5656            .settings_at(buffer_position, cx)
 5657            .show_completion_documentation;
 5658
 5659        // The document can be large, so stay in reasonable bounds when searching for words,
 5660        // otherwise completion pop-up might be slow to appear.
 5661        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5662        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5663        let min_word_search = buffer_snapshot.clip_point(
 5664            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5665            Bias::Left,
 5666        );
 5667        let max_word_search = buffer_snapshot.clip_point(
 5668            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5669            Bias::Right,
 5670        );
 5671        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5672            ..buffer_snapshot.point_to_offset(max_word_search);
 5673
 5674        let skip_digits = query
 5675            .as_ref()
 5676            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5677
 5678        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5679            trigger.as_ref().is_none_or(|trigger| {
 5680                provider.is_completion_trigger(
 5681                    &buffer,
 5682                    position.text_anchor,
 5683                    trigger,
 5684                    trigger_in_words,
 5685                    cx,
 5686                )
 5687            })
 5688        });
 5689
 5690        let provider_responses = if let Some(provider) = &provider
 5691            && load_provider_completions
 5692        {
 5693            let trigger_character =
 5694                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5695            let completion_context = CompletionContext {
 5696                trigger_kind: match &trigger_character {
 5697                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5698                    None => CompletionTriggerKind::INVOKED,
 5699                },
 5700                trigger_character,
 5701            };
 5702
 5703            provider.completions(
 5704                buffer_excerpt_id,
 5705                &buffer,
 5706                buffer_position,
 5707                completion_context,
 5708                window,
 5709                cx,
 5710            )
 5711        } else {
 5712            Task::ready(Ok(Vec::new()))
 5713        };
 5714
 5715        let load_word_completions = if !self.word_completions_enabled {
 5716            false
 5717        } else if requested_source
 5718            == Some(CompletionsMenuSource::Words {
 5719                ignore_threshold: true,
 5720            })
 5721        {
 5722            true
 5723        } else {
 5724            load_provider_completions
 5725                && completion_settings.words != WordsCompletionMode::Disabled
 5726                && (ignore_word_threshold || {
 5727                    let words_min_length = completion_settings.words_min_length;
 5728                    // check whether word has at least `words_min_length` characters
 5729                    let query_chars = query.iter().flat_map(|q| q.chars());
 5730                    query_chars.take(words_min_length).count() == words_min_length
 5731                })
 5732        };
 5733
 5734        let mut words = if load_word_completions {
 5735            cx.background_spawn({
 5736                let buffer_snapshot = buffer_snapshot.clone();
 5737                async move {
 5738                    buffer_snapshot.words_in_range(WordsQuery {
 5739                        fuzzy_contents: None,
 5740                        range: word_search_range,
 5741                        skip_digits,
 5742                    })
 5743                }
 5744            })
 5745        } else {
 5746            Task::ready(BTreeMap::default())
 5747        };
 5748
 5749        let snippets = if let Some(provider) = &provider
 5750            && provider.show_snippets()
 5751            && let Some(project) = self.project()
 5752        {
 5753            let char_classifier = buffer_snapshot
 5754                .char_classifier_at(buffer_position)
 5755                .scope_context(Some(CharScopeContext::Completion));
 5756            project.update(cx, |project, cx| {
 5757                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5758            })
 5759        } else {
 5760            Task::ready(Ok(CompletionResponse {
 5761                completions: Vec::new(),
 5762                display_options: Default::default(),
 5763                is_incomplete: false,
 5764            }))
 5765        };
 5766
 5767        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5768
 5769        let id = post_inc(&mut self.next_completion_id);
 5770        let task = cx.spawn_in(window, async move |editor, cx| {
 5771            let Ok(()) = editor.update(cx, |this, _| {
 5772                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5773            }) else {
 5774                return;
 5775            };
 5776
 5777            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5778            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5779            let mut completions = Vec::new();
 5780            let mut is_incomplete = false;
 5781            let mut display_options: Option<CompletionDisplayOptions> = None;
 5782            if let Some(provider_responses) = provider_responses.await.log_err()
 5783                && !provider_responses.is_empty()
 5784            {
 5785                for response in provider_responses {
 5786                    completions.extend(response.completions);
 5787                    is_incomplete = is_incomplete || response.is_incomplete;
 5788                    match display_options.as_mut() {
 5789                        None => {
 5790                            display_options = Some(response.display_options);
 5791                        }
 5792                        Some(options) => options.merge(&response.display_options),
 5793                    }
 5794                }
 5795                if completion_settings.words == WordsCompletionMode::Fallback {
 5796                    words = Task::ready(BTreeMap::default());
 5797                }
 5798            }
 5799            let display_options = display_options.unwrap_or_default();
 5800
 5801            let mut words = words.await;
 5802            if let Some(word_to_exclude) = &word_to_exclude {
 5803                words.remove(word_to_exclude);
 5804            }
 5805            for lsp_completion in &completions {
 5806                words.remove(&lsp_completion.new_text);
 5807            }
 5808            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5809                replace_range: word_replace_range.clone(),
 5810                new_text: word.clone(),
 5811                label: CodeLabel::plain(word, None),
 5812                match_start: None,
 5813                snippet_deduplication_key: None,
 5814                icon_path: None,
 5815                documentation: None,
 5816                source: CompletionSource::BufferWord {
 5817                    word_range,
 5818                    resolved: false,
 5819                },
 5820                insert_text_mode: Some(InsertTextMode::AS_IS),
 5821                confirm: None,
 5822            }));
 5823
 5824            completions.extend(
 5825                snippets
 5826                    .await
 5827                    .into_iter()
 5828                    .flat_map(|response| response.completions),
 5829            );
 5830
 5831            let menu = if completions.is_empty() {
 5832                None
 5833            } else {
 5834                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5835                    let languages = editor
 5836                        .workspace
 5837                        .as_ref()
 5838                        .and_then(|(workspace, _)| workspace.upgrade())
 5839                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5840                    let menu = CompletionsMenu::new(
 5841                        id,
 5842                        requested_source.unwrap_or(if load_provider_completions {
 5843                            CompletionsMenuSource::Normal
 5844                        } else {
 5845                            CompletionsMenuSource::SnippetsOnly
 5846                        }),
 5847                        sort_completions,
 5848                        show_completion_documentation,
 5849                        position,
 5850                        query.clone(),
 5851                        is_incomplete,
 5852                        buffer.clone(),
 5853                        completions.into(),
 5854                        editor
 5855                            .context_menu()
 5856                            .borrow_mut()
 5857                            .as_ref()
 5858                            .map(|menu| menu.primary_scroll_handle()),
 5859                        display_options,
 5860                        snippet_sort_order,
 5861                        languages,
 5862                        language,
 5863                        cx,
 5864                    );
 5865
 5866                    let query = if filter_completions { query } else { None };
 5867                    let matches_task = menu.do_async_filtering(
 5868                        query.unwrap_or_default(),
 5869                        buffer_position,
 5870                        &buffer,
 5871                        cx,
 5872                    );
 5873                    (menu, matches_task)
 5874                }) else {
 5875                    return;
 5876                };
 5877
 5878                let matches = matches_task.await;
 5879
 5880                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5881                    // Newer menu already set, so exit.
 5882                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5883                        editor.context_menu.borrow().as_ref()
 5884                        && prev_menu.id > id
 5885                    {
 5886                        return;
 5887                    };
 5888
 5889                    // Only valid to take prev_menu because either the new menu is immediately set
 5890                    // below, or the menu is hidden.
 5891                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5892                        editor.context_menu.borrow_mut().take()
 5893                    {
 5894                        let position_matches =
 5895                            if prev_menu.initial_position == menu.initial_position {
 5896                                true
 5897                            } else {
 5898                                let snapshot = editor.buffer.read(cx).read(cx);
 5899                                prev_menu.initial_position.to_offset(&snapshot)
 5900                                    == menu.initial_position.to_offset(&snapshot)
 5901                            };
 5902                        if position_matches {
 5903                            // Preserve markdown cache before `set_filter_results` because it will
 5904                            // try to populate the documentation cache.
 5905                            menu.preserve_markdown_cache(prev_menu);
 5906                        }
 5907                    };
 5908
 5909                    menu.set_filter_results(matches, provider, window, cx);
 5910                }) else {
 5911                    return;
 5912                };
 5913
 5914                menu.visible().then_some(menu)
 5915            };
 5916
 5917            editor
 5918                .update_in(cx, |editor, window, cx| {
 5919                    if editor.focus_handle.is_focused(window)
 5920                        && let Some(menu) = menu
 5921                    {
 5922                        *editor.context_menu.borrow_mut() =
 5923                            Some(CodeContextMenu::Completions(menu));
 5924
 5925                        crate::hover_popover::hide_hover(editor, cx);
 5926                        if editor.show_edit_predictions_in_menu() {
 5927                            editor.update_visible_edit_prediction(window, cx);
 5928                        } else {
 5929                            editor.discard_edit_prediction(false, cx);
 5930                        }
 5931
 5932                        cx.notify();
 5933                        return;
 5934                    }
 5935
 5936                    if editor.completion_tasks.len() <= 1 {
 5937                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5938                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5939                        // If it was already hidden and we don't show edit predictions in the menu,
 5940                        // we should also show the edit prediction when available.
 5941                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5942                            editor.update_visible_edit_prediction(window, cx);
 5943                        }
 5944                    }
 5945                })
 5946                .ok();
 5947        });
 5948
 5949        self.completion_tasks.push((id, task));
 5950    }
 5951
 5952    #[cfg(feature = "test-support")]
 5953    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5954        let menu = self.context_menu.borrow();
 5955        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5956            let completions = menu.completions.borrow();
 5957            Some(completions.to_vec())
 5958        } else {
 5959            None
 5960        }
 5961    }
 5962
 5963    pub fn with_completions_menu_matching_id<R>(
 5964        &self,
 5965        id: CompletionId,
 5966        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5967    ) -> R {
 5968        let mut context_menu = self.context_menu.borrow_mut();
 5969        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5970            return f(None);
 5971        };
 5972        if completions_menu.id != id {
 5973            return f(None);
 5974        }
 5975        f(Some(completions_menu))
 5976    }
 5977
 5978    pub fn confirm_completion(
 5979        &mut self,
 5980        action: &ConfirmCompletion,
 5981        window: &mut Window,
 5982        cx: &mut Context<Self>,
 5983    ) -> Option<Task<Result<()>>> {
 5984        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5985        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5986    }
 5987
 5988    pub fn confirm_completion_insert(
 5989        &mut self,
 5990        _: &ConfirmCompletionInsert,
 5991        window: &mut Window,
 5992        cx: &mut Context<Self>,
 5993    ) -> Option<Task<Result<()>>> {
 5994        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5995        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5996    }
 5997
 5998    pub fn confirm_completion_replace(
 5999        &mut self,
 6000        _: &ConfirmCompletionReplace,
 6001        window: &mut Window,
 6002        cx: &mut Context<Self>,
 6003    ) -> Option<Task<Result<()>>> {
 6004        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6005        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6006    }
 6007
 6008    pub fn compose_completion(
 6009        &mut self,
 6010        action: &ComposeCompletion,
 6011        window: &mut Window,
 6012        cx: &mut Context<Self>,
 6013    ) -> Option<Task<Result<()>>> {
 6014        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6015        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6016    }
 6017
 6018    fn do_completion(
 6019        &mut self,
 6020        item_ix: Option<usize>,
 6021        intent: CompletionIntent,
 6022        window: &mut Window,
 6023        cx: &mut Context<Editor>,
 6024    ) -> Option<Task<Result<()>>> {
 6025        use language::ToOffset as _;
 6026
 6027        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6028        else {
 6029            return None;
 6030        };
 6031
 6032        let candidate_id = {
 6033            let entries = completions_menu.entries.borrow();
 6034            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6035            if self.show_edit_predictions_in_menu() {
 6036                self.discard_edit_prediction(true, cx);
 6037            }
 6038            mat.candidate_id
 6039        };
 6040
 6041        let completion = completions_menu
 6042            .completions
 6043            .borrow()
 6044            .get(candidate_id)?
 6045            .clone();
 6046        cx.stop_propagation();
 6047
 6048        let buffer_handle = completions_menu.buffer.clone();
 6049
 6050        let CompletionEdit {
 6051            new_text,
 6052            snippet,
 6053            replace_range,
 6054        } = process_completion_for_edit(
 6055            &completion,
 6056            intent,
 6057            &buffer_handle,
 6058            &completions_menu.initial_position.text_anchor,
 6059            cx,
 6060        );
 6061
 6062        let buffer = buffer_handle.read(cx);
 6063        let snapshot = self.buffer.read(cx).snapshot(cx);
 6064        let newest_anchor = self.selections.newest_anchor();
 6065        let replace_range_multibuffer = {
 6066            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6067            excerpt.map_range_from_buffer(replace_range.clone())
 6068        };
 6069        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6070            return None;
 6071        }
 6072
 6073        let old_text = buffer
 6074            .text_for_range(replace_range.clone())
 6075            .collect::<String>();
 6076        let lookbehind = newest_anchor
 6077            .start
 6078            .text_anchor
 6079            .to_offset(buffer)
 6080            .saturating_sub(replace_range.start.0);
 6081        let lookahead = replace_range
 6082            .end
 6083            .0
 6084            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6085        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6086        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6087
 6088        let selections = self
 6089            .selections
 6090            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6091        let mut ranges = Vec::new();
 6092        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6093
 6094        for selection in &selections {
 6095            let range = if selection.id == newest_anchor.id {
 6096                replace_range_multibuffer.clone()
 6097            } else {
 6098                let mut range = selection.range();
 6099
 6100                // if prefix is present, don't duplicate it
 6101                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6102                    range.start = range.start.saturating_sub_usize(lookbehind);
 6103
 6104                    // if suffix is also present, mimic the newest cursor and replace it
 6105                    if selection.id != newest_anchor.id
 6106                        && snapshot.contains_str_at(range.end, suffix)
 6107                    {
 6108                        range.end += lookahead;
 6109                    }
 6110                }
 6111                range
 6112            };
 6113
 6114            ranges.push(range.clone());
 6115
 6116            if !self.linked_edit_ranges.is_empty() {
 6117                let start_anchor = snapshot.anchor_before(range.start);
 6118                let end_anchor = snapshot.anchor_after(range.end);
 6119                if let Some(ranges) = self
 6120                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6121                {
 6122                    for (buffer, edits) in ranges {
 6123                        linked_edits
 6124                            .entry(buffer.clone())
 6125                            .or_default()
 6126                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6127                    }
 6128                }
 6129            }
 6130        }
 6131
 6132        let common_prefix_len = old_text
 6133            .chars()
 6134            .zip(new_text.chars())
 6135            .take_while(|(a, b)| a == b)
 6136            .map(|(a, _)| a.len_utf8())
 6137            .sum::<usize>();
 6138
 6139        cx.emit(EditorEvent::InputHandled {
 6140            utf16_range_to_replace: None,
 6141            text: new_text[common_prefix_len..].into(),
 6142        });
 6143
 6144        self.transact(window, cx, |editor, window, cx| {
 6145            if let Some(mut snippet) = snippet {
 6146                snippet.text = new_text.to_string();
 6147                editor
 6148                    .insert_snippet(&ranges, snippet, window, cx)
 6149                    .log_err();
 6150            } else {
 6151                editor.buffer.update(cx, |multi_buffer, cx| {
 6152                    let auto_indent = match completion.insert_text_mode {
 6153                        Some(InsertTextMode::AS_IS) => None,
 6154                        _ => editor.autoindent_mode.clone(),
 6155                    };
 6156                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6157                    multi_buffer.edit(edits, auto_indent, cx);
 6158                });
 6159            }
 6160            for (buffer, edits) in linked_edits {
 6161                buffer.update(cx, |buffer, cx| {
 6162                    let snapshot = buffer.snapshot();
 6163                    let edits = edits
 6164                        .into_iter()
 6165                        .map(|(range, text)| {
 6166                            use text::ToPoint as TP;
 6167                            let end_point = TP::to_point(&range.end, &snapshot);
 6168                            let start_point = TP::to_point(&range.start, &snapshot);
 6169                            (start_point..end_point, text)
 6170                        })
 6171                        .sorted_by_key(|(range, _)| range.start);
 6172                    buffer.edit(edits, None, cx);
 6173                })
 6174            }
 6175
 6176            editor.refresh_edit_prediction(true, false, window, cx);
 6177        });
 6178        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6179
 6180        let show_new_completions_on_confirm = completion
 6181            .confirm
 6182            .as_ref()
 6183            .is_some_and(|confirm| confirm(intent, window, cx));
 6184        if show_new_completions_on_confirm {
 6185            self.open_or_update_completions_menu(None, None, false, window, cx);
 6186        }
 6187
 6188        let provider = self.completion_provider.as_ref()?;
 6189
 6190        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6191        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6192            let CompletionSource::Lsp {
 6193                lsp_completion,
 6194                server_id,
 6195                ..
 6196            } = &completion.source
 6197            else {
 6198                return None;
 6199            };
 6200            let lsp_command = lsp_completion.command.as_ref()?;
 6201            let available_commands = lsp_store
 6202                .read(cx)
 6203                .lsp_server_capabilities
 6204                .get(server_id)
 6205                .and_then(|server_capabilities| {
 6206                    server_capabilities
 6207                        .execute_command_provider
 6208                        .as_ref()
 6209                        .map(|options| options.commands.as_slice())
 6210                })?;
 6211            if available_commands.contains(&lsp_command.command) {
 6212                Some(CodeAction {
 6213                    server_id: *server_id,
 6214                    range: language::Anchor::MIN..language::Anchor::MIN,
 6215                    lsp_action: LspAction::Command(lsp_command.clone()),
 6216                    resolved: false,
 6217                })
 6218            } else {
 6219                None
 6220            }
 6221        });
 6222
 6223        drop(completion);
 6224        let apply_edits = provider.apply_additional_edits_for_completion(
 6225            buffer_handle.clone(),
 6226            completions_menu.completions.clone(),
 6227            candidate_id,
 6228            true,
 6229            cx,
 6230        );
 6231
 6232        let editor_settings = EditorSettings::get_global(cx);
 6233        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6234            // After the code completion is finished, users often want to know what signatures are needed.
 6235            // so we should automatically call signature_help
 6236            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6237        }
 6238
 6239        Some(cx.spawn_in(window, async move |editor, cx| {
 6240            apply_edits.await?;
 6241
 6242            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6243                let title = command.lsp_action.title().to_owned();
 6244                let project_transaction = lsp_store
 6245                    .update(cx, |lsp_store, cx| {
 6246                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6247                    })?
 6248                    .await
 6249                    .context("applying post-completion command")?;
 6250                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6251                    Self::open_project_transaction(
 6252                        &editor,
 6253                        workspace.downgrade(),
 6254                        project_transaction,
 6255                        title,
 6256                        cx,
 6257                    )
 6258                    .await?;
 6259                }
 6260            }
 6261
 6262            Ok(())
 6263        }))
 6264    }
 6265
 6266    pub fn toggle_code_actions(
 6267        &mut self,
 6268        action: &ToggleCodeActions,
 6269        window: &mut Window,
 6270        cx: &mut Context<Self>,
 6271    ) {
 6272        let quick_launch = action.quick_launch;
 6273        let mut context_menu = self.context_menu.borrow_mut();
 6274        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6275            if code_actions.deployed_from == action.deployed_from {
 6276                // Toggle if we're selecting the same one
 6277                *context_menu = None;
 6278                cx.notify();
 6279                return;
 6280            } else {
 6281                // Otherwise, clear it and start a new one
 6282                *context_menu = None;
 6283                cx.notify();
 6284            }
 6285        }
 6286        drop(context_menu);
 6287        let snapshot = self.snapshot(window, cx);
 6288        let deployed_from = action.deployed_from.clone();
 6289        let action = action.clone();
 6290        self.completion_tasks.clear();
 6291        self.discard_edit_prediction(false, cx);
 6292
 6293        let multibuffer_point = match &action.deployed_from {
 6294            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6295                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6296            }
 6297            _ => self
 6298                .selections
 6299                .newest::<Point>(&snapshot.display_snapshot)
 6300                .head(),
 6301        };
 6302        let Some((buffer, buffer_row)) = snapshot
 6303            .buffer_snapshot()
 6304            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6305            .and_then(|(buffer_snapshot, range)| {
 6306                self.buffer()
 6307                    .read(cx)
 6308                    .buffer(buffer_snapshot.remote_id())
 6309                    .map(|buffer| (buffer, range.start.row))
 6310            })
 6311        else {
 6312            return;
 6313        };
 6314        let buffer_id = buffer.read(cx).remote_id();
 6315        let tasks = self
 6316            .tasks
 6317            .get(&(buffer_id, buffer_row))
 6318            .map(|t| Arc::new(t.to_owned()));
 6319
 6320        if !self.focus_handle.is_focused(window) {
 6321            return;
 6322        }
 6323        let project = self.project.clone();
 6324
 6325        let code_actions_task = match deployed_from {
 6326            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6327            _ => self.code_actions(buffer_row, window, cx),
 6328        };
 6329
 6330        let runnable_task = match deployed_from {
 6331            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6332            _ => {
 6333                let mut task_context_task = Task::ready(None);
 6334                if let Some(tasks) = &tasks
 6335                    && let Some(project) = project
 6336                {
 6337                    task_context_task =
 6338                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6339                }
 6340
 6341                cx.spawn_in(window, {
 6342                    let buffer = buffer.clone();
 6343                    async move |editor, cx| {
 6344                        let task_context = task_context_task.await;
 6345
 6346                        let resolved_tasks =
 6347                            tasks
 6348                                .zip(task_context.clone())
 6349                                .map(|(tasks, task_context)| ResolvedTasks {
 6350                                    templates: tasks.resolve(&task_context).collect(),
 6351                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6352                                        multibuffer_point.row,
 6353                                        tasks.column,
 6354                                    )),
 6355                                });
 6356                        let debug_scenarios = editor
 6357                            .update(cx, |editor, cx| {
 6358                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6359                            })?
 6360                            .await;
 6361                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6362                    }
 6363                })
 6364            }
 6365        };
 6366
 6367        cx.spawn_in(window, async move |editor, cx| {
 6368            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6369            let code_actions = code_actions_task.await;
 6370            let spawn_straight_away = quick_launch
 6371                && resolved_tasks
 6372                    .as_ref()
 6373                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6374                && code_actions
 6375                    .as_ref()
 6376                    .is_none_or(|actions| actions.is_empty())
 6377                && debug_scenarios.is_empty();
 6378
 6379            editor.update_in(cx, |editor, window, cx| {
 6380                crate::hover_popover::hide_hover(editor, cx);
 6381                let actions = CodeActionContents::new(
 6382                    resolved_tasks,
 6383                    code_actions,
 6384                    debug_scenarios,
 6385                    task_context.unwrap_or_default(),
 6386                );
 6387
 6388                // Don't show the menu if there are no actions available
 6389                if actions.is_empty() {
 6390                    cx.notify();
 6391                    return Task::ready(Ok(()));
 6392                }
 6393
 6394                *editor.context_menu.borrow_mut() =
 6395                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6396                        buffer,
 6397                        actions,
 6398                        selected_item: Default::default(),
 6399                        scroll_handle: UniformListScrollHandle::default(),
 6400                        deployed_from,
 6401                    }));
 6402                cx.notify();
 6403                if spawn_straight_away
 6404                    && let Some(task) = editor.confirm_code_action(
 6405                        &ConfirmCodeAction { item_ix: Some(0) },
 6406                        window,
 6407                        cx,
 6408                    )
 6409                {
 6410                    return task;
 6411                }
 6412
 6413                Task::ready(Ok(()))
 6414            })
 6415        })
 6416        .detach_and_log_err(cx);
 6417    }
 6418
 6419    fn debug_scenarios(
 6420        &mut self,
 6421        resolved_tasks: &Option<ResolvedTasks>,
 6422        buffer: &Entity<Buffer>,
 6423        cx: &mut App,
 6424    ) -> Task<Vec<task::DebugScenario>> {
 6425        maybe!({
 6426            let project = self.project()?;
 6427            let dap_store = project.read(cx).dap_store();
 6428            let mut scenarios = vec![];
 6429            let resolved_tasks = resolved_tasks.as_ref()?;
 6430            let buffer = buffer.read(cx);
 6431            let language = buffer.language()?;
 6432            let file = buffer.file();
 6433            let debug_adapter = language_settings(language.name().into(), file, cx)
 6434                .debuggers
 6435                .first()
 6436                .map(SharedString::from)
 6437                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6438
 6439            dap_store.update(cx, |dap_store, cx| {
 6440                for (_, task) in &resolved_tasks.templates {
 6441                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6442                        task.original_task().clone(),
 6443                        debug_adapter.clone().into(),
 6444                        task.display_label().to_owned().into(),
 6445                        cx,
 6446                    );
 6447                    scenarios.push(maybe_scenario);
 6448                }
 6449            });
 6450            Some(cx.background_spawn(async move {
 6451                futures::future::join_all(scenarios)
 6452                    .await
 6453                    .into_iter()
 6454                    .flatten()
 6455                    .collect::<Vec<_>>()
 6456            }))
 6457        })
 6458        .unwrap_or_else(|| Task::ready(vec![]))
 6459    }
 6460
 6461    fn code_actions(
 6462        &mut self,
 6463        buffer_row: u32,
 6464        window: &mut Window,
 6465        cx: &mut Context<Self>,
 6466    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6467        let mut task = self.code_actions_task.take();
 6468        cx.spawn_in(window, async move |editor, cx| {
 6469            while let Some(prev_task) = task {
 6470                prev_task.await.log_err();
 6471                task = editor
 6472                    .update(cx, |this, _| this.code_actions_task.take())
 6473                    .ok()?;
 6474            }
 6475
 6476            editor
 6477                .update(cx, |editor, cx| {
 6478                    editor
 6479                        .available_code_actions
 6480                        .clone()
 6481                        .and_then(|(location, code_actions)| {
 6482                            let snapshot = location.buffer.read(cx).snapshot();
 6483                            let point_range = location.range.to_point(&snapshot);
 6484                            let point_range = point_range.start.row..=point_range.end.row;
 6485                            if point_range.contains(&buffer_row) {
 6486                                Some(code_actions)
 6487                            } else {
 6488                                None
 6489                            }
 6490                        })
 6491                })
 6492                .ok()
 6493                .flatten()
 6494        })
 6495    }
 6496
 6497    pub fn confirm_code_action(
 6498        &mut self,
 6499        action: &ConfirmCodeAction,
 6500        window: &mut Window,
 6501        cx: &mut Context<Self>,
 6502    ) -> Option<Task<Result<()>>> {
 6503        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6504
 6505        let actions_menu =
 6506            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6507                menu
 6508            } else {
 6509                return None;
 6510            };
 6511
 6512        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6513        let action = actions_menu.actions.get(action_ix)?;
 6514        let title = action.label();
 6515        let buffer = actions_menu.buffer;
 6516        let workspace = self.workspace()?;
 6517
 6518        match action {
 6519            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6520                workspace.update(cx, |workspace, cx| {
 6521                    workspace.schedule_resolved_task(
 6522                        task_source_kind,
 6523                        resolved_task,
 6524                        false,
 6525                        window,
 6526                        cx,
 6527                    );
 6528
 6529                    Some(Task::ready(Ok(())))
 6530                })
 6531            }
 6532            CodeActionsItem::CodeAction {
 6533                excerpt_id,
 6534                action,
 6535                provider,
 6536            } => {
 6537                let apply_code_action =
 6538                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6539                let workspace = workspace.downgrade();
 6540                Some(cx.spawn_in(window, async move |editor, cx| {
 6541                    let project_transaction = apply_code_action.await?;
 6542                    Self::open_project_transaction(
 6543                        &editor,
 6544                        workspace,
 6545                        project_transaction,
 6546                        title,
 6547                        cx,
 6548                    )
 6549                    .await
 6550                }))
 6551            }
 6552            CodeActionsItem::DebugScenario(scenario) => {
 6553                let context = actions_menu.actions.context;
 6554
 6555                workspace.update(cx, |workspace, cx| {
 6556                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6557                    workspace.start_debug_session(
 6558                        scenario,
 6559                        context,
 6560                        Some(buffer),
 6561                        None,
 6562                        window,
 6563                        cx,
 6564                    );
 6565                });
 6566                Some(Task::ready(Ok(())))
 6567            }
 6568        }
 6569    }
 6570
 6571    fn open_transaction_for_hidden_buffers(
 6572        workspace: Entity<Workspace>,
 6573        transaction: ProjectTransaction,
 6574        title: String,
 6575        window: &mut Window,
 6576        cx: &mut Context<Self>,
 6577    ) {
 6578        if transaction.0.is_empty() {
 6579            return;
 6580        }
 6581
 6582        let edited_buffers_already_open = {
 6583            let other_editors: Vec<Entity<Editor>> = workspace
 6584                .read(cx)
 6585                .panes()
 6586                .iter()
 6587                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 6588                .filter(|editor| editor.entity_id() != cx.entity_id())
 6589                .collect();
 6590
 6591            transaction.0.keys().all(|buffer| {
 6592                other_editors.iter().any(|editor| {
 6593                    let multi_buffer = editor.read(cx).buffer();
 6594                    multi_buffer.read(cx).is_singleton()
 6595                        && multi_buffer
 6596                            .read(cx)
 6597                            .as_singleton()
 6598                            .map_or(false, |singleton| {
 6599                                singleton.entity_id() == buffer.entity_id()
 6600                            })
 6601                })
 6602            })
 6603        };
 6604        if !edited_buffers_already_open {
 6605            let workspace = workspace.downgrade();
 6606            cx.defer_in(window, move |_, window, cx| {
 6607                cx.spawn_in(window, async move |editor, cx| {
 6608                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 6609                        .await
 6610                        .ok()
 6611                })
 6612                .detach();
 6613            });
 6614        }
 6615    }
 6616
 6617    pub async fn open_project_transaction(
 6618        editor: &WeakEntity<Editor>,
 6619        workspace: WeakEntity<Workspace>,
 6620        transaction: ProjectTransaction,
 6621        title: String,
 6622        cx: &mut AsyncWindowContext,
 6623    ) -> Result<()> {
 6624        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6625        cx.update(|_, cx| {
 6626            entries.sort_unstable_by_key(|(buffer, _)| {
 6627                buffer.read(cx).file().map(|f| f.path().clone())
 6628            });
 6629        })?;
 6630        if entries.is_empty() {
 6631            return Ok(());
 6632        }
 6633
 6634        // If the project transaction's edits are all contained within this editor, then
 6635        // avoid opening a new editor to display them.
 6636
 6637        if let [(buffer, transaction)] = &*entries {
 6638            let excerpt = editor.update(cx, |editor, cx| {
 6639                editor
 6640                    .buffer()
 6641                    .read(cx)
 6642                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6643            })?;
 6644            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6645                && excerpted_buffer == *buffer
 6646            {
 6647                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6648                    let excerpt_range = excerpt_range.to_offset(buffer);
 6649                    buffer
 6650                        .edited_ranges_for_transaction::<usize>(transaction)
 6651                        .all(|range| {
 6652                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6653                        })
 6654                })?;
 6655
 6656                if all_edits_within_excerpt {
 6657                    return Ok(());
 6658                }
 6659            }
 6660        }
 6661
 6662        let mut ranges_to_highlight = Vec::new();
 6663        let excerpt_buffer = cx.new(|cx| {
 6664            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6665            for (buffer_handle, transaction) in &entries {
 6666                let edited_ranges = buffer_handle
 6667                    .read(cx)
 6668                    .edited_ranges_for_transaction::<Point>(transaction)
 6669                    .collect::<Vec<_>>();
 6670                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6671                    PathKey::for_buffer(buffer_handle, cx),
 6672                    buffer_handle.clone(),
 6673                    edited_ranges,
 6674                    multibuffer_context_lines(cx),
 6675                    cx,
 6676                );
 6677
 6678                ranges_to_highlight.extend(ranges);
 6679            }
 6680            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6681            multibuffer
 6682        })?;
 6683
 6684        workspace.update_in(cx, |workspace, window, cx| {
 6685            let project = workspace.project().clone();
 6686            let editor =
 6687                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6688            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6689            editor.update(cx, |editor, cx| {
 6690                editor.highlight_background::<Self>(
 6691                    &ranges_to_highlight,
 6692                    |_, theme| theme.colors().editor_highlighted_line_background,
 6693                    cx,
 6694                );
 6695            });
 6696        })?;
 6697
 6698        Ok(())
 6699    }
 6700
 6701    pub fn clear_code_action_providers(&mut self) {
 6702        self.code_action_providers.clear();
 6703        self.available_code_actions.take();
 6704    }
 6705
 6706    pub fn add_code_action_provider(
 6707        &mut self,
 6708        provider: Rc<dyn CodeActionProvider>,
 6709        window: &mut Window,
 6710        cx: &mut Context<Self>,
 6711    ) {
 6712        if self
 6713            .code_action_providers
 6714            .iter()
 6715            .any(|existing_provider| existing_provider.id() == provider.id())
 6716        {
 6717            return;
 6718        }
 6719
 6720        self.code_action_providers.push(provider);
 6721        self.refresh_code_actions(window, cx);
 6722    }
 6723
 6724    pub fn remove_code_action_provider(
 6725        &mut self,
 6726        id: Arc<str>,
 6727        window: &mut Window,
 6728        cx: &mut Context<Self>,
 6729    ) {
 6730        self.code_action_providers
 6731            .retain(|provider| provider.id() != id);
 6732        self.refresh_code_actions(window, cx);
 6733    }
 6734
 6735    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6736        !self.code_action_providers.is_empty()
 6737            && EditorSettings::get_global(cx).toolbar.code_actions
 6738    }
 6739
 6740    pub fn has_available_code_actions(&self) -> bool {
 6741        self.available_code_actions
 6742            .as_ref()
 6743            .is_some_and(|(_, actions)| !actions.is_empty())
 6744    }
 6745
 6746    fn render_inline_code_actions(
 6747        &self,
 6748        icon_size: ui::IconSize,
 6749        display_row: DisplayRow,
 6750        is_active: bool,
 6751        cx: &mut Context<Self>,
 6752    ) -> AnyElement {
 6753        let show_tooltip = !self.context_menu_visible();
 6754        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6755            .icon_size(icon_size)
 6756            .shape(ui::IconButtonShape::Square)
 6757            .icon_color(ui::Color::Hidden)
 6758            .toggle_state(is_active)
 6759            .when(show_tooltip, |this| {
 6760                this.tooltip({
 6761                    let focus_handle = self.focus_handle.clone();
 6762                    move |_window, cx| {
 6763                        Tooltip::for_action_in(
 6764                            "Toggle Code Actions",
 6765                            &ToggleCodeActions {
 6766                                deployed_from: None,
 6767                                quick_launch: false,
 6768                            },
 6769                            &focus_handle,
 6770                            cx,
 6771                        )
 6772                    }
 6773                })
 6774            })
 6775            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6776                window.focus(&editor.focus_handle(cx), cx);
 6777                editor.toggle_code_actions(
 6778                    &crate::actions::ToggleCodeActions {
 6779                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6780                            display_row,
 6781                        )),
 6782                        quick_launch: false,
 6783                    },
 6784                    window,
 6785                    cx,
 6786                );
 6787            }))
 6788            .into_any_element()
 6789    }
 6790
 6791    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6792        &self.context_menu
 6793    }
 6794
 6795    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6796        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6797            cx.background_executor()
 6798                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6799                .await;
 6800
 6801            let (start_buffer, start, _, end, newest_selection) = this
 6802                .update(cx, |this, cx| {
 6803                    let newest_selection = this.selections.newest_anchor().clone();
 6804                    if newest_selection.head().diff_base_anchor.is_some() {
 6805                        return None;
 6806                    }
 6807                    let display_snapshot = this.display_snapshot(cx);
 6808                    let newest_selection_adjusted =
 6809                        this.selections.newest_adjusted(&display_snapshot);
 6810                    let buffer = this.buffer.read(cx);
 6811
 6812                    let (start_buffer, start) =
 6813                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6814                    let (end_buffer, end) =
 6815                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6816
 6817                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6818                })?
 6819                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6820                .context(
 6821                    "Expected selection to lie in a single buffer when refreshing code actions",
 6822                )?;
 6823            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6824                let providers = this.code_action_providers.clone();
 6825                let tasks = this
 6826                    .code_action_providers
 6827                    .iter()
 6828                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6829                    .collect::<Vec<_>>();
 6830                (providers, tasks)
 6831            })?;
 6832
 6833            let mut actions = Vec::new();
 6834            for (provider, provider_actions) in
 6835                providers.into_iter().zip(future::join_all(tasks).await)
 6836            {
 6837                if let Some(provider_actions) = provider_actions.log_err() {
 6838                    actions.extend(provider_actions.into_iter().map(|action| {
 6839                        AvailableCodeAction {
 6840                            excerpt_id: newest_selection.start.excerpt_id,
 6841                            action,
 6842                            provider: provider.clone(),
 6843                        }
 6844                    }));
 6845                }
 6846            }
 6847
 6848            this.update(cx, |this, cx| {
 6849                this.available_code_actions = if actions.is_empty() {
 6850                    None
 6851                } else {
 6852                    Some((
 6853                        Location {
 6854                            buffer: start_buffer,
 6855                            range: start..end,
 6856                        },
 6857                        actions.into(),
 6858                    ))
 6859                };
 6860                cx.notify();
 6861            })
 6862        }));
 6863    }
 6864
 6865    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6866        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6867            self.show_git_blame_inline = false;
 6868
 6869            self.show_git_blame_inline_delay_task =
 6870                Some(cx.spawn_in(window, async move |this, cx| {
 6871                    cx.background_executor().timer(delay).await;
 6872
 6873                    this.update(cx, |this, cx| {
 6874                        this.show_git_blame_inline = true;
 6875                        cx.notify();
 6876                    })
 6877                    .log_err();
 6878                }));
 6879        }
 6880    }
 6881
 6882    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6883        let snapshot = self.snapshot(window, cx);
 6884        let cursor = self
 6885            .selections
 6886            .newest::<Point>(&snapshot.display_snapshot)
 6887            .head();
 6888        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6889        else {
 6890            return;
 6891        };
 6892
 6893        if self.blame.is_none() {
 6894            self.start_git_blame(true, window, cx);
 6895        }
 6896        let Some(blame) = self.blame.as_ref() else {
 6897            return;
 6898        };
 6899
 6900        let row_info = RowInfo {
 6901            buffer_id: Some(buffer.remote_id()),
 6902            buffer_row: Some(point.row),
 6903            ..Default::default()
 6904        };
 6905        let Some((buffer, blame_entry)) = blame
 6906            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6907            .flatten()
 6908        else {
 6909            return;
 6910        };
 6911
 6912        let anchor = self.selections.newest_anchor().head();
 6913        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 6914        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6915            self.show_blame_popover(
 6916                buffer,
 6917                &blame_entry,
 6918                position + last_bounds.origin,
 6919                true,
 6920                cx,
 6921            );
 6922        };
 6923    }
 6924
 6925    fn show_blame_popover(
 6926        &mut self,
 6927        buffer: BufferId,
 6928        blame_entry: &BlameEntry,
 6929        position: gpui::Point<Pixels>,
 6930        ignore_timeout: bool,
 6931        cx: &mut Context<Self>,
 6932    ) {
 6933        if let Some(state) = &mut self.inline_blame_popover {
 6934            state.hide_task.take();
 6935        } else {
 6936            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6937            let blame_entry = blame_entry.clone();
 6938            let show_task = cx.spawn(async move |editor, cx| {
 6939                if !ignore_timeout {
 6940                    cx.background_executor()
 6941                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6942                        .await;
 6943                }
 6944                editor
 6945                    .update(cx, |editor, cx| {
 6946                        editor.inline_blame_popover_show_task.take();
 6947                        let Some(blame) = editor.blame.as_ref() else {
 6948                            return;
 6949                        };
 6950                        let blame = blame.read(cx);
 6951                        let details = blame.details_for_entry(buffer, &blame_entry);
 6952                        let markdown = cx.new(|cx| {
 6953                            Markdown::new(
 6954                                details
 6955                                    .as_ref()
 6956                                    .map(|message| message.message.clone())
 6957                                    .unwrap_or_default(),
 6958                                None,
 6959                                None,
 6960                                cx,
 6961                            )
 6962                        });
 6963                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6964                            position,
 6965                            hide_task: None,
 6966                            popover_bounds: None,
 6967                            popover_state: InlineBlamePopoverState {
 6968                                scroll_handle: ScrollHandle::new(),
 6969                                commit_message: details,
 6970                                markdown,
 6971                            },
 6972                            keyboard_grace: ignore_timeout,
 6973                        });
 6974                        cx.notify();
 6975                    })
 6976                    .ok();
 6977            });
 6978            self.inline_blame_popover_show_task = Some(show_task);
 6979        }
 6980    }
 6981
 6982    pub fn has_mouse_context_menu(&self) -> bool {
 6983        self.mouse_context_menu.is_some()
 6984    }
 6985
 6986    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6987        self.inline_blame_popover_show_task.take();
 6988        if let Some(state) = &mut self.inline_blame_popover {
 6989            let hide_task = cx.spawn(async move |editor, cx| {
 6990                if !ignore_timeout {
 6991                    cx.background_executor()
 6992                        .timer(std::time::Duration::from_millis(100))
 6993                        .await;
 6994                }
 6995                editor
 6996                    .update(cx, |editor, cx| {
 6997                        editor.inline_blame_popover.take();
 6998                        cx.notify();
 6999                    })
 7000                    .ok();
 7001            });
 7002            state.hide_task = Some(hide_task);
 7003            true
 7004        } else {
 7005            false
 7006        }
 7007    }
 7008
 7009    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7010        if self.pending_rename.is_some() {
 7011            return None;
 7012        }
 7013
 7014        let provider = self.semantics_provider.clone()?;
 7015        let buffer = self.buffer.read(cx);
 7016        let newest_selection = self.selections.newest_anchor().clone();
 7017        let cursor_position = newest_selection.head();
 7018        let (cursor_buffer, cursor_buffer_position) =
 7019            buffer.text_anchor_for_position(cursor_position, cx)?;
 7020        let (tail_buffer, tail_buffer_position) =
 7021            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7022        if cursor_buffer != tail_buffer {
 7023            return None;
 7024        }
 7025
 7026        let snapshot = cursor_buffer.read(cx).snapshot();
 7027        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7028        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7029        if start_word_range != end_word_range {
 7030            self.document_highlights_task.take();
 7031            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 7032            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 7033            return None;
 7034        }
 7035
 7036        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7037        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7038            cx.background_executor()
 7039                .timer(Duration::from_millis(debounce))
 7040                .await;
 7041
 7042            let highlights = if let Some(highlights) = cx
 7043                .update(|cx| {
 7044                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7045                })
 7046                .ok()
 7047                .flatten()
 7048            {
 7049                highlights.await.log_err()
 7050            } else {
 7051                None
 7052            };
 7053
 7054            if let Some(highlights) = highlights {
 7055                this.update(cx, |this, cx| {
 7056                    if this.pending_rename.is_some() {
 7057                        return;
 7058                    }
 7059
 7060                    let buffer = this.buffer.read(cx);
 7061                    if buffer
 7062                        .text_anchor_for_position(cursor_position, cx)
 7063                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7064                    {
 7065                        return;
 7066                    }
 7067
 7068                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7069                    let mut write_ranges = Vec::new();
 7070                    let mut read_ranges = Vec::new();
 7071                    for highlight in highlights {
 7072                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7073                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7074                        {
 7075                            let start = highlight
 7076                                .range
 7077                                .start
 7078                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7079                            let end = highlight
 7080                                .range
 7081                                .end
 7082                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7083                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7084                                continue;
 7085                            }
 7086
 7087                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7088                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7089                                write_ranges.push(range);
 7090                            } else {
 7091                                read_ranges.push(range);
 7092                            }
 7093                        }
 7094                    }
 7095
 7096                    this.highlight_background::<DocumentHighlightRead>(
 7097                        &read_ranges,
 7098                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7099                        cx,
 7100                    );
 7101                    this.highlight_background::<DocumentHighlightWrite>(
 7102                        &write_ranges,
 7103                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7104                        cx,
 7105                    );
 7106                    cx.notify();
 7107                })
 7108                .log_err();
 7109            }
 7110        }));
 7111        None
 7112    }
 7113
 7114    fn prepare_highlight_query_from_selection(
 7115        &mut self,
 7116        window: &Window,
 7117        cx: &mut Context<Editor>,
 7118    ) -> Option<(String, Range<Anchor>)> {
 7119        if matches!(self.mode, EditorMode::SingleLine) {
 7120            return None;
 7121        }
 7122        if !EditorSettings::get_global(cx).selection_highlight {
 7123            return None;
 7124        }
 7125        if self.selections.count() != 1 || self.selections.line_mode() {
 7126            return None;
 7127        }
 7128        let snapshot = self.snapshot(window, cx);
 7129        let selection = self.selections.newest::<Point>(&snapshot);
 7130        // If the selection spans multiple rows OR it is empty
 7131        if selection.start.row != selection.end.row
 7132            || selection.start.column == selection.end.column
 7133        {
 7134            return None;
 7135        }
 7136        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7137        let query = snapshot
 7138            .buffer_snapshot()
 7139            .text_for_range(selection_anchor_range.clone())
 7140            .collect::<String>();
 7141        if query.trim().is_empty() {
 7142            return None;
 7143        }
 7144        Some((query, selection_anchor_range))
 7145    }
 7146
 7147    #[ztracing::instrument(skip_all)]
 7148    fn update_selection_occurrence_highlights(
 7149        &mut self,
 7150        query_text: String,
 7151        query_range: Range<Anchor>,
 7152        multi_buffer_range_to_query: Range<Point>,
 7153        use_debounce: bool,
 7154        window: &mut Window,
 7155        cx: &mut Context<Editor>,
 7156    ) -> Task<()> {
 7157        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7158        cx.spawn_in(window, async move |editor, cx| {
 7159            if use_debounce {
 7160                cx.background_executor()
 7161                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7162                    .await;
 7163            }
 7164            let match_task = cx.background_spawn(async move {
 7165                let buffer_ranges = multi_buffer_snapshot
 7166                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7167                    .into_iter()
 7168                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7169                let mut match_ranges = Vec::new();
 7170                let Ok(regex) = project::search::SearchQuery::text(
 7171                    query_text.clone(),
 7172                    false,
 7173                    false,
 7174                    false,
 7175                    Default::default(),
 7176                    Default::default(),
 7177                    false,
 7178                    None,
 7179                ) else {
 7180                    return Vec::default();
 7181                };
 7182                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7183                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7184                    match_ranges.extend(
 7185                        regex
 7186                            .search(
 7187                                buffer_snapshot,
 7188                                Some(search_range.start.0..search_range.end.0),
 7189                            )
 7190                            .await
 7191                            .into_iter()
 7192                            .filter_map(|match_range| {
 7193                                let match_start = buffer_snapshot
 7194                                    .anchor_after(search_range.start + match_range.start);
 7195                                let match_end = buffer_snapshot
 7196                                    .anchor_before(search_range.start + match_range.end);
 7197                                let match_anchor_range =
 7198                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7199                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7200                            }),
 7201                    );
 7202                }
 7203                match_ranges
 7204            });
 7205            let match_ranges = match_task.await;
 7206            editor
 7207                .update_in(cx, |editor, _, cx| {
 7208                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7209                    if !match_ranges.is_empty() {
 7210                        editor.highlight_background::<SelectedTextHighlight>(
 7211                            &match_ranges,
 7212                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7213                            cx,
 7214                        )
 7215                    }
 7216                })
 7217                .log_err();
 7218        })
 7219    }
 7220
 7221    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7222        struct NewlineFold;
 7223        let type_id = std::any::TypeId::of::<NewlineFold>();
 7224        if !self.mode.is_single_line() {
 7225            return;
 7226        }
 7227        let snapshot = self.snapshot(window, cx);
 7228        if snapshot.buffer_snapshot().max_point().row == 0 {
 7229            return;
 7230        }
 7231        let task = cx.background_spawn(async move {
 7232            let new_newlines = snapshot
 7233                .buffer_chars_at(MultiBufferOffset(0))
 7234                .filter_map(|(c, i)| {
 7235                    if c == '\n' {
 7236                        Some(
 7237                            snapshot.buffer_snapshot().anchor_after(i)
 7238                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7239                        )
 7240                    } else {
 7241                        None
 7242                    }
 7243                })
 7244                .collect::<Vec<_>>();
 7245            let existing_newlines = snapshot
 7246                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7247                .filter_map(|fold| {
 7248                    if fold.placeholder.type_tag == Some(type_id) {
 7249                        Some(fold.range.start..fold.range.end)
 7250                    } else {
 7251                        None
 7252                    }
 7253                })
 7254                .collect::<Vec<_>>();
 7255
 7256            (new_newlines, existing_newlines)
 7257        });
 7258        self.folding_newlines = cx.spawn(async move |this, cx| {
 7259            let (new_newlines, existing_newlines) = task.await;
 7260            if new_newlines == existing_newlines {
 7261                return;
 7262            }
 7263            let placeholder = FoldPlaceholder {
 7264                render: Arc::new(move |_, _, cx| {
 7265                    div()
 7266                        .bg(cx.theme().status().hint_background)
 7267                        .border_b_1()
 7268                        .size_full()
 7269                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7270                        .border_color(cx.theme().status().hint)
 7271                        .child("\\n")
 7272                        .into_any()
 7273                }),
 7274                constrain_width: false,
 7275                merge_adjacent: false,
 7276                type_tag: Some(type_id),
 7277            };
 7278            let creases = new_newlines
 7279                .into_iter()
 7280                .map(|range| Crease::simple(range, placeholder.clone()))
 7281                .collect();
 7282            this.update(cx, |this, cx| {
 7283                this.display_map.update(cx, |display_map, cx| {
 7284                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7285                    display_map.fold(creases, cx);
 7286                });
 7287            })
 7288            .ok();
 7289        });
 7290    }
 7291
 7292    #[ztracing::instrument(skip_all)]
 7293    fn refresh_selected_text_highlights(
 7294        &mut self,
 7295        on_buffer_edit: bool,
 7296        window: &mut Window,
 7297        cx: &mut Context<Editor>,
 7298    ) {
 7299        let Some((query_text, query_range)) =
 7300            self.prepare_highlight_query_from_selection(window, cx)
 7301        else {
 7302            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7303            self.quick_selection_highlight_task.take();
 7304            self.debounced_selection_highlight_task.take();
 7305            return;
 7306        };
 7307        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7308        if on_buffer_edit
 7309            || self
 7310                .quick_selection_highlight_task
 7311                .as_ref()
 7312                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7313        {
 7314            let multi_buffer_visible_start = self
 7315                .scroll_manager
 7316                .anchor()
 7317                .anchor
 7318                .to_point(&multi_buffer_snapshot);
 7319            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7320                multi_buffer_visible_start
 7321                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7322                Bias::Left,
 7323            );
 7324            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7325            self.quick_selection_highlight_task = Some((
 7326                query_range.clone(),
 7327                self.update_selection_occurrence_highlights(
 7328                    query_text.clone(),
 7329                    query_range.clone(),
 7330                    multi_buffer_visible_range,
 7331                    false,
 7332                    window,
 7333                    cx,
 7334                ),
 7335            ));
 7336        }
 7337        if on_buffer_edit
 7338            || self
 7339                .debounced_selection_highlight_task
 7340                .as_ref()
 7341                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7342        {
 7343            let multi_buffer_start = multi_buffer_snapshot
 7344                .anchor_before(MultiBufferOffset(0))
 7345                .to_point(&multi_buffer_snapshot);
 7346            let multi_buffer_end = multi_buffer_snapshot
 7347                .anchor_after(multi_buffer_snapshot.len())
 7348                .to_point(&multi_buffer_snapshot);
 7349            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7350            self.debounced_selection_highlight_task = Some((
 7351                query_range.clone(),
 7352                self.update_selection_occurrence_highlights(
 7353                    query_text,
 7354                    query_range,
 7355                    multi_buffer_full_range,
 7356                    true,
 7357                    window,
 7358                    cx,
 7359                ),
 7360            ));
 7361        }
 7362    }
 7363
 7364    pub fn refresh_edit_prediction(
 7365        &mut self,
 7366        debounce: bool,
 7367        user_requested: bool,
 7368        window: &mut Window,
 7369        cx: &mut Context<Self>,
 7370    ) -> Option<()> {
 7371        if DisableAiSettings::get_global(cx).disable_ai {
 7372            return None;
 7373        }
 7374
 7375        let provider = self.edit_prediction_provider()?;
 7376        let cursor = self.selections.newest_anchor().head();
 7377        let (buffer, cursor_buffer_position) =
 7378            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7379
 7380        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7381            self.discard_edit_prediction(false, cx);
 7382            return None;
 7383        }
 7384
 7385        self.update_visible_edit_prediction(window, cx);
 7386
 7387        if !user_requested
 7388            && (!self.should_show_edit_predictions()
 7389                || !self.is_focused(window)
 7390                || buffer.read(cx).is_empty())
 7391        {
 7392            self.discard_edit_prediction(false, cx);
 7393            return None;
 7394        }
 7395
 7396        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7397        Some(())
 7398    }
 7399
 7400    fn show_edit_predictions_in_menu(&self) -> bool {
 7401        match self.edit_prediction_settings {
 7402            EditPredictionSettings::Disabled => false,
 7403            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7404        }
 7405    }
 7406
 7407    pub fn edit_predictions_enabled(&self) -> bool {
 7408        match self.edit_prediction_settings {
 7409            EditPredictionSettings::Disabled => false,
 7410            EditPredictionSettings::Enabled { .. } => true,
 7411        }
 7412    }
 7413
 7414    fn edit_prediction_requires_modifier(&self) -> bool {
 7415        match self.edit_prediction_settings {
 7416            EditPredictionSettings::Disabled => false,
 7417            EditPredictionSettings::Enabled {
 7418                preview_requires_modifier,
 7419                ..
 7420            } => preview_requires_modifier,
 7421        }
 7422    }
 7423
 7424    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7425        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7426            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7427            self.discard_edit_prediction(false, cx);
 7428        } else {
 7429            let selection = self.selections.newest_anchor();
 7430            let cursor = selection.head();
 7431
 7432            if let Some((buffer, cursor_buffer_position)) =
 7433                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7434            {
 7435                self.edit_prediction_settings =
 7436                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7437            }
 7438        }
 7439    }
 7440
 7441    fn edit_prediction_settings_at_position(
 7442        &self,
 7443        buffer: &Entity<Buffer>,
 7444        buffer_position: language::Anchor,
 7445        cx: &App,
 7446    ) -> EditPredictionSettings {
 7447        if !self.mode.is_full()
 7448            || !self.show_edit_predictions_override.unwrap_or(true)
 7449            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7450        {
 7451            return EditPredictionSettings::Disabled;
 7452        }
 7453
 7454        let buffer = buffer.read(cx);
 7455
 7456        let file = buffer.file();
 7457
 7458        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7459            return EditPredictionSettings::Disabled;
 7460        };
 7461
 7462        let by_provider = matches!(
 7463            self.menu_edit_predictions_policy,
 7464            MenuEditPredictionsPolicy::ByProvider
 7465        );
 7466
 7467        let show_in_menu = by_provider
 7468            && self
 7469                .edit_prediction_provider
 7470                .as_ref()
 7471                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7472
 7473        let preview_requires_modifier =
 7474            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7475
 7476        EditPredictionSettings::Enabled {
 7477            show_in_menu,
 7478            preview_requires_modifier,
 7479        }
 7480    }
 7481
 7482    fn should_show_edit_predictions(&self) -> bool {
 7483        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7484    }
 7485
 7486    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7487        matches!(
 7488            self.edit_prediction_preview,
 7489            EditPredictionPreview::Active { .. }
 7490        )
 7491    }
 7492
 7493    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7494        let cursor = self.selections.newest_anchor().head();
 7495        if let Some((buffer, cursor_position)) =
 7496            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7497        {
 7498            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7499        } else {
 7500            false
 7501        }
 7502    }
 7503
 7504    pub fn supports_minimap(&self, cx: &App) -> bool {
 7505        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7506    }
 7507
 7508    fn edit_predictions_enabled_in_buffer(
 7509        &self,
 7510        buffer: &Entity<Buffer>,
 7511        buffer_position: language::Anchor,
 7512        cx: &App,
 7513    ) -> bool {
 7514        maybe!({
 7515            if self.read_only(cx) {
 7516                return Some(false);
 7517            }
 7518            let provider = self.edit_prediction_provider()?;
 7519            if !provider.is_enabled(buffer, buffer_position, cx) {
 7520                return Some(false);
 7521            }
 7522            let buffer = buffer.read(cx);
 7523            let Some(file) = buffer.file() else {
 7524                return Some(true);
 7525            };
 7526            let settings = all_language_settings(Some(file), cx);
 7527            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7528        })
 7529        .unwrap_or(false)
 7530    }
 7531
 7532    pub fn show_edit_prediction(
 7533        &mut self,
 7534        _: &ShowEditPrediction,
 7535        window: &mut Window,
 7536        cx: &mut Context<Self>,
 7537    ) {
 7538        if !self.has_active_edit_prediction() {
 7539            self.refresh_edit_prediction(false, true, window, cx);
 7540            return;
 7541        }
 7542
 7543        self.update_visible_edit_prediction(window, cx);
 7544    }
 7545
 7546    pub fn display_cursor_names(
 7547        &mut self,
 7548        _: &DisplayCursorNames,
 7549        window: &mut Window,
 7550        cx: &mut Context<Self>,
 7551    ) {
 7552        self.show_cursor_names(window, cx);
 7553    }
 7554
 7555    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7556        self.show_cursor_names = true;
 7557        cx.notify();
 7558        cx.spawn_in(window, async move |this, cx| {
 7559            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7560            this.update(cx, |this, cx| {
 7561                this.show_cursor_names = false;
 7562                cx.notify()
 7563            })
 7564            .ok()
 7565        })
 7566        .detach();
 7567    }
 7568
 7569    pub fn accept_partial_edit_prediction(
 7570        &mut self,
 7571        granularity: EditPredictionGranularity,
 7572        window: &mut Window,
 7573        cx: &mut Context<Self>,
 7574    ) {
 7575        if self.show_edit_predictions_in_menu() {
 7576            self.hide_context_menu(window, cx);
 7577        }
 7578
 7579        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7580            return;
 7581        };
 7582
 7583        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 7584            return;
 7585        }
 7586
 7587        match &active_edit_prediction.completion {
 7588            EditPrediction::MoveWithin { target, .. } => {
 7589                let target = *target;
 7590
 7591                if matches!(granularity, EditPredictionGranularity::Full) {
 7592                    if let Some(position_map) = &self.last_position_map {
 7593                        let target_row = target.to_display_point(&position_map.snapshot).row();
 7594                        let is_visible = position_map.visible_row_range.contains(&target_row);
 7595
 7596                        if is_visible || !self.edit_prediction_requires_modifier() {
 7597                            self.unfold_ranges(&[target..target], true, false, cx);
 7598                            self.change_selections(
 7599                                SelectionEffects::scroll(Autoscroll::newest()),
 7600                                window,
 7601                                cx,
 7602                                |selections| {
 7603                                    selections.select_anchor_ranges([target..target]);
 7604                                },
 7605                            );
 7606                            self.clear_row_highlights::<EditPredictionPreview>();
 7607                            self.edit_prediction_preview
 7608                                .set_previous_scroll_position(None);
 7609                        } else {
 7610                            // Highlight and request scroll
 7611                            self.edit_prediction_preview
 7612                                .set_previous_scroll_position(Some(
 7613                                    position_map.snapshot.scroll_anchor,
 7614                                ));
 7615                            self.highlight_rows::<EditPredictionPreview>(
 7616                                target..target,
 7617                                cx.theme().colors().editor_highlighted_line_background,
 7618                                RowHighlightOptions {
 7619                                    autoscroll: true,
 7620                                    ..Default::default()
 7621                                },
 7622                                cx,
 7623                            );
 7624                            self.request_autoscroll(Autoscroll::fit(), cx);
 7625                        }
 7626                    }
 7627                } else {
 7628                    self.change_selections(
 7629                        SelectionEffects::scroll(Autoscroll::newest()),
 7630                        window,
 7631                        cx,
 7632                        |selections| {
 7633                            selections.select_anchor_ranges([target..target]);
 7634                        },
 7635                    );
 7636                }
 7637            }
 7638            EditPrediction::MoveOutside { snapshot, target } => {
 7639                if let Some(workspace) = self.workspace() {
 7640                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7641                        .detach_and_log_err(cx);
 7642                }
 7643            }
 7644            EditPrediction::Edit { edits, .. } => {
 7645                self.report_edit_prediction_event(
 7646                    active_edit_prediction.completion_id.clone(),
 7647                    true,
 7648                    cx,
 7649                );
 7650
 7651                match granularity {
 7652                    EditPredictionGranularity::Full => {
 7653                        if let Some(provider) = self.edit_prediction_provider() {
 7654                            provider.accept(cx);
 7655                        }
 7656
 7657                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7658                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7659                        let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7660
 7661                        self.buffer.update(cx, |buffer, cx| {
 7662                            buffer.edit(edits.iter().cloned(), None, cx)
 7663                        });
 7664
 7665                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7666                            s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7667                        });
 7668
 7669                        let selections = self.selections.disjoint_anchors_arc();
 7670                        if let Some(transaction_id_now) =
 7671                            self.buffer.read(cx).last_transaction_id(cx)
 7672                        {
 7673                            if transaction_id_prev != Some(transaction_id_now) {
 7674                                self.selection_history
 7675                                    .insert_transaction(transaction_id_now, selections);
 7676                            }
 7677                        }
 7678
 7679                        self.update_visible_edit_prediction(window, cx);
 7680                        if self.active_edit_prediction.is_none() {
 7681                            self.refresh_edit_prediction(true, true, window, cx);
 7682                        }
 7683                        cx.notify();
 7684                    }
 7685                    _ => {
 7686                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7687                        let cursor_offset = self
 7688                            .selections
 7689                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7690                            .head();
 7691
 7692                        let insertion = edits.iter().find_map(|(range, text)| {
 7693                            let range = range.to_offset(&snapshot);
 7694                            if range.is_empty() && range.start == cursor_offset {
 7695                                Some(text)
 7696                            } else {
 7697                                None
 7698                            }
 7699                        });
 7700
 7701                        if let Some(text) = insertion {
 7702                            let text_to_insert = match granularity {
 7703                                EditPredictionGranularity::Word => {
 7704                                    let mut partial = text
 7705                                        .chars()
 7706                                        .by_ref()
 7707                                        .take_while(|c| c.is_alphabetic())
 7708                                        .collect::<String>();
 7709                                    if partial.is_empty() {
 7710                                        partial = text
 7711                                            .chars()
 7712                                            .by_ref()
 7713                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7714                                            .collect::<String>();
 7715                                    }
 7716                                    partial
 7717                                }
 7718                                EditPredictionGranularity::Line => {
 7719                                    if let Some(line) = text.split_inclusive('\n').next() {
 7720                                        line.to_string()
 7721                                    } else {
 7722                                        text.to_string()
 7723                                    }
 7724                                }
 7725                                EditPredictionGranularity::Full => unreachable!(),
 7726                            };
 7727
 7728                            cx.emit(EditorEvent::InputHandled {
 7729                                utf16_range_to_replace: None,
 7730                                text: text_to_insert.clone().into(),
 7731                            });
 7732
 7733                            self.insert_with_autoindent_mode(&text_to_insert, None, window, cx);
 7734                            self.refresh_edit_prediction(true, true, window, cx);
 7735                            cx.notify();
 7736                        } else {
 7737                            self.accept_partial_edit_prediction(
 7738                                EditPredictionGranularity::Full,
 7739                                window,
 7740                                cx,
 7741                            );
 7742                        }
 7743                    }
 7744                }
 7745            }
 7746        }
 7747
 7748        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7749    }
 7750
 7751    pub fn accept_next_word_edit_prediction(
 7752        &mut self,
 7753        _: &AcceptNextWordEditPrediction,
 7754        window: &mut Window,
 7755        cx: &mut Context<Self>,
 7756    ) {
 7757        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 7758    }
 7759
 7760    pub fn accept_next_line_edit_prediction(
 7761        &mut self,
 7762        _: &AcceptNextLineEditPrediction,
 7763        window: &mut Window,
 7764        cx: &mut Context<Self>,
 7765    ) {
 7766        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 7767    }
 7768
 7769    pub fn accept_edit_prediction(
 7770        &mut self,
 7771        _: &AcceptEditPrediction,
 7772        window: &mut Window,
 7773        cx: &mut Context<Self>,
 7774    ) {
 7775        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 7776    }
 7777
 7778    fn discard_edit_prediction(
 7779        &mut self,
 7780        should_report_edit_prediction_event: bool,
 7781        cx: &mut Context<Self>,
 7782    ) -> bool {
 7783        if should_report_edit_prediction_event {
 7784            let completion_id = self
 7785                .active_edit_prediction
 7786                .as_ref()
 7787                .and_then(|active_completion| active_completion.completion_id.clone());
 7788
 7789            self.report_edit_prediction_event(completion_id, false, cx);
 7790        }
 7791
 7792        if let Some(provider) = self.edit_prediction_provider() {
 7793            provider.discard(cx);
 7794        }
 7795
 7796        self.take_active_edit_prediction(cx)
 7797    }
 7798
 7799    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7800        let Some(provider) = self.edit_prediction_provider() else {
 7801            return;
 7802        };
 7803
 7804        let Some((_, buffer, _)) = self
 7805            .buffer
 7806            .read(cx)
 7807            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7808        else {
 7809            return;
 7810        };
 7811
 7812        let extension = buffer
 7813            .read(cx)
 7814            .file()
 7815            .and_then(|file| Some(file.path().extension()?.to_string()));
 7816
 7817        let event_type = match accepted {
 7818            true => "Edit Prediction Accepted",
 7819            false => "Edit Prediction Discarded",
 7820        };
 7821        telemetry::event!(
 7822            event_type,
 7823            provider = provider.name(),
 7824            prediction_id = id,
 7825            suggestion_accepted = accepted,
 7826            file_extension = extension,
 7827        );
 7828    }
 7829
 7830    fn open_editor_at_anchor(
 7831        snapshot: &language::BufferSnapshot,
 7832        target: language::Anchor,
 7833        workspace: &Entity<Workspace>,
 7834        window: &mut Window,
 7835        cx: &mut App,
 7836    ) -> Task<Result<()>> {
 7837        workspace.update(cx, |workspace, cx| {
 7838            let path = snapshot.file().map(|file| file.full_path(cx));
 7839            let Some(path) =
 7840                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7841            else {
 7842                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7843            };
 7844            let target = text::ToPoint::to_point(&target, snapshot);
 7845            let item = workspace.open_path(path, None, true, window, cx);
 7846            window.spawn(cx, async move |cx| {
 7847                let Some(editor) = item.await?.downcast::<Editor>() else {
 7848                    return Ok(());
 7849                };
 7850                editor
 7851                    .update_in(cx, |editor, window, cx| {
 7852                        editor.go_to_singleton_buffer_point(target, window, cx);
 7853                    })
 7854                    .ok();
 7855                anyhow::Ok(())
 7856            })
 7857        })
 7858    }
 7859
 7860    pub fn has_active_edit_prediction(&self) -> bool {
 7861        self.active_edit_prediction.is_some()
 7862    }
 7863
 7864    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7865        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7866            return false;
 7867        };
 7868
 7869        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7870        self.clear_highlights::<EditPredictionHighlight>(cx);
 7871        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7872        true
 7873    }
 7874
 7875    /// Returns true when we're displaying the edit prediction popover below the cursor
 7876    /// like we are not previewing and the LSP autocomplete menu is visible
 7877    /// or we are in `when_holding_modifier` mode.
 7878    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7879        if self.edit_prediction_preview_is_active()
 7880            || !self.show_edit_predictions_in_menu()
 7881            || !self.edit_predictions_enabled()
 7882        {
 7883            return false;
 7884        }
 7885
 7886        if self.has_visible_completions_menu() {
 7887            return true;
 7888        }
 7889
 7890        has_completion && self.edit_prediction_requires_modifier()
 7891    }
 7892
 7893    fn handle_modifiers_changed(
 7894        &mut self,
 7895        modifiers: Modifiers,
 7896        position_map: &PositionMap,
 7897        window: &mut Window,
 7898        cx: &mut Context<Self>,
 7899    ) {
 7900        // Ensure that the edit prediction preview is updated, even when not
 7901        // enabled, if there's an active edit prediction preview.
 7902        if self.show_edit_predictions_in_menu()
 7903            || matches!(
 7904                self.edit_prediction_preview,
 7905                EditPredictionPreview::Active { .. }
 7906            )
 7907        {
 7908            self.update_edit_prediction_preview(&modifiers, window, cx);
 7909        }
 7910
 7911        self.update_selection_mode(&modifiers, position_map, window, cx);
 7912
 7913        let mouse_position = window.mouse_position();
 7914        if !position_map.text_hitbox.is_hovered(window) {
 7915            return;
 7916        }
 7917
 7918        self.update_hovered_link(
 7919            position_map.point_for_position(mouse_position),
 7920            &position_map.snapshot,
 7921            modifiers,
 7922            window,
 7923            cx,
 7924        )
 7925    }
 7926
 7927    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7928        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7929            MultiCursorModifier::Alt => modifiers.secondary(),
 7930            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7931        }
 7932    }
 7933
 7934    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7935        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7936            MultiCursorModifier::Alt => modifiers.alt,
 7937            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7938        }
 7939    }
 7940
 7941    fn columnar_selection_mode(
 7942        modifiers: &Modifiers,
 7943        cx: &mut Context<Self>,
 7944    ) -> Option<ColumnarMode> {
 7945        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7946            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7947                Some(ColumnarMode::FromMouse)
 7948            } else if Self::is_alt_pressed(modifiers, cx) {
 7949                Some(ColumnarMode::FromSelection)
 7950            } else {
 7951                None
 7952            }
 7953        } else {
 7954            None
 7955        }
 7956    }
 7957
 7958    fn update_selection_mode(
 7959        &mut self,
 7960        modifiers: &Modifiers,
 7961        position_map: &PositionMap,
 7962        window: &mut Window,
 7963        cx: &mut Context<Self>,
 7964    ) {
 7965        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7966            return;
 7967        };
 7968        if self.selections.pending_anchor().is_none() {
 7969            return;
 7970        }
 7971
 7972        let mouse_position = window.mouse_position();
 7973        let point_for_position = position_map.point_for_position(mouse_position);
 7974        let position = point_for_position.previous_valid;
 7975
 7976        self.select(
 7977            SelectPhase::BeginColumnar {
 7978                position,
 7979                reset: false,
 7980                mode,
 7981                goal_column: point_for_position.exact_unclipped.column(),
 7982            },
 7983            window,
 7984            cx,
 7985        );
 7986    }
 7987
 7988    fn update_edit_prediction_preview(
 7989        &mut self,
 7990        modifiers: &Modifiers,
 7991        window: &mut Window,
 7992        cx: &mut Context<Self>,
 7993    ) {
 7994        let mut modifiers_held = false;
 7995
 7996        // Check bindings for all granularities.
 7997        // If the user holds the key for Word, Line, or Full, we want to show the preview.
 7998        let granularities = [
 7999            EditPredictionGranularity::Full,
 8000            EditPredictionGranularity::Line,
 8001            EditPredictionGranularity::Word,
 8002        ];
 8003
 8004        for granularity in granularities {
 8005            if let Some(keystroke) = self
 8006                .accept_edit_prediction_keybind(granularity, window, cx)
 8007                .keystroke()
 8008            {
 8009                modifiers_held = modifiers_held
 8010                    || (keystroke.modifiers() == modifiers && keystroke.modifiers().modified());
 8011            }
 8012        }
 8013
 8014        if modifiers_held {
 8015            if matches!(
 8016                self.edit_prediction_preview,
 8017                EditPredictionPreview::Inactive { .. }
 8018            ) {
 8019                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 8020                    provider.provider.did_show(cx)
 8021                }
 8022
 8023                self.edit_prediction_preview = EditPredictionPreview::Active {
 8024                    previous_scroll_position: None,
 8025                    since: Instant::now(),
 8026                };
 8027
 8028                self.update_visible_edit_prediction(window, cx);
 8029                cx.notify();
 8030            }
 8031        } else if let EditPredictionPreview::Active {
 8032            previous_scroll_position,
 8033            since,
 8034        } = self.edit_prediction_preview
 8035        {
 8036            if let (Some(previous_scroll_position), Some(position_map)) =
 8037                (previous_scroll_position, self.last_position_map.as_ref())
 8038            {
 8039                self.set_scroll_position(
 8040                    previous_scroll_position
 8041                        .scroll_position(&position_map.snapshot.display_snapshot),
 8042                    window,
 8043                    cx,
 8044                );
 8045            }
 8046
 8047            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8048                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8049            };
 8050            self.clear_row_highlights::<EditPredictionPreview>();
 8051            self.update_visible_edit_prediction(window, cx);
 8052            cx.notify();
 8053        }
 8054    }
 8055
 8056    fn update_visible_edit_prediction(
 8057        &mut self,
 8058        _window: &mut Window,
 8059        cx: &mut Context<Self>,
 8060    ) -> Option<()> {
 8061        if DisableAiSettings::get_global(cx).disable_ai {
 8062            return None;
 8063        }
 8064
 8065        if self.ime_transaction.is_some() {
 8066            self.discard_edit_prediction(false, cx);
 8067            return None;
 8068        }
 8069
 8070        let selection = self.selections.newest_anchor();
 8071        let cursor = selection.head();
 8072        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8073        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8074        let excerpt_id = cursor.excerpt_id;
 8075
 8076        let show_in_menu = self.show_edit_predictions_in_menu();
 8077        let completions_menu_has_precedence = !show_in_menu
 8078            && (self.context_menu.borrow().is_some()
 8079                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8080
 8081        if completions_menu_has_precedence
 8082            || !offset_selection.is_empty()
 8083            || self
 8084                .active_edit_prediction
 8085                .as_ref()
 8086                .is_some_and(|completion| {
 8087                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8088                        return false;
 8089                    };
 8090                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8091                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8092                    !invalidation_range.contains(&offset_selection.head())
 8093                })
 8094        {
 8095            self.discard_edit_prediction(false, cx);
 8096            return None;
 8097        }
 8098
 8099        self.take_active_edit_prediction(cx);
 8100        let Some(provider) = self.edit_prediction_provider() else {
 8101            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8102            return None;
 8103        };
 8104
 8105        let (buffer, cursor_buffer_position) =
 8106            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8107
 8108        self.edit_prediction_settings =
 8109            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8110
 8111        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8112
 8113        if self.edit_prediction_indent_conflict {
 8114            let cursor_point = cursor.to_point(&multibuffer);
 8115            let mut suggested_indent = None;
 8116            multibuffer.suggested_indents_callback(
 8117                cursor_point.row..cursor_point.row + 1,
 8118                |_, indent| {
 8119                    suggested_indent = Some(indent);
 8120                    ControlFlow::Break(())
 8121                },
 8122                cx,
 8123            );
 8124
 8125            if let Some(indent) = suggested_indent
 8126                && indent.len == cursor_point.column
 8127            {
 8128                self.edit_prediction_indent_conflict = false;
 8129            }
 8130        }
 8131
 8132        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8133
 8134        let (completion_id, edits, edit_preview) = match edit_prediction {
 8135            edit_prediction_types::EditPrediction::Local {
 8136                id,
 8137                edits,
 8138                edit_preview,
 8139            } => (id, edits, edit_preview),
 8140            edit_prediction_types::EditPrediction::Jump {
 8141                id,
 8142                snapshot,
 8143                target,
 8144            } => {
 8145                self.stale_edit_prediction_in_menu = None;
 8146                self.active_edit_prediction = Some(EditPredictionState {
 8147                    inlay_ids: vec![],
 8148                    completion: EditPrediction::MoveOutside { snapshot, target },
 8149                    completion_id: id,
 8150                    invalidation_range: None,
 8151                });
 8152                cx.notify();
 8153                return Some(());
 8154            }
 8155        };
 8156
 8157        let edits = edits
 8158            .into_iter()
 8159            .flat_map(|(range, new_text)| {
 8160                Some((
 8161                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8162                    new_text,
 8163                ))
 8164            })
 8165            .collect::<Vec<_>>();
 8166        if edits.is_empty() {
 8167            return None;
 8168        }
 8169
 8170        let first_edit_start = edits.first().unwrap().0.start;
 8171        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8172        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8173
 8174        let last_edit_end = edits.last().unwrap().0.end;
 8175        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8176        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8177
 8178        let cursor_row = cursor.to_point(&multibuffer).row;
 8179
 8180        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8181
 8182        let mut inlay_ids = Vec::new();
 8183        let invalidation_row_range;
 8184        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8185            Some(cursor_row..edit_end_row)
 8186        } else if cursor_row > edit_end_row {
 8187            Some(edit_start_row..cursor_row)
 8188        } else {
 8189            None
 8190        };
 8191        let supports_jump = self
 8192            .edit_prediction_provider
 8193            .as_ref()
 8194            .map(|provider| provider.provider.supports_jump_to_edit())
 8195            .unwrap_or(true);
 8196
 8197        let is_move = supports_jump
 8198            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8199        let completion = if is_move {
 8200            invalidation_row_range =
 8201                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8202            let target = first_edit_start;
 8203            EditPrediction::MoveWithin { target, snapshot }
 8204        } else {
 8205            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8206                && !self.edit_predictions_hidden_for_vim_mode;
 8207
 8208            if show_completions_in_buffer {
 8209                if let Some(provider) = &self.edit_prediction_provider {
 8210                    provider.provider.did_show(cx);
 8211                }
 8212                if edits
 8213                    .iter()
 8214                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8215                {
 8216                    let mut inlays = Vec::new();
 8217                    for (range, new_text) in &edits {
 8218                        let inlay = Inlay::edit_prediction(
 8219                            post_inc(&mut self.next_inlay_id),
 8220                            range.start,
 8221                            new_text.as_ref(),
 8222                        );
 8223                        inlay_ids.push(inlay.id);
 8224                        inlays.push(inlay);
 8225                    }
 8226
 8227                    self.splice_inlays(&[], inlays, cx);
 8228                } else {
 8229                    let background_color = cx.theme().status().deleted_background;
 8230                    self.highlight_text::<EditPredictionHighlight>(
 8231                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8232                        HighlightStyle {
 8233                            background_color: Some(background_color),
 8234                            ..Default::default()
 8235                        },
 8236                        cx,
 8237                    );
 8238                }
 8239            }
 8240
 8241            invalidation_row_range = edit_start_row..edit_end_row;
 8242
 8243            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8244                if provider.show_tab_accept_marker() {
 8245                    EditDisplayMode::TabAccept
 8246                } else {
 8247                    EditDisplayMode::Inline
 8248                }
 8249            } else {
 8250                EditDisplayMode::DiffPopover
 8251            };
 8252
 8253            EditPrediction::Edit {
 8254                edits,
 8255                edit_preview,
 8256                display_mode,
 8257                snapshot,
 8258            }
 8259        };
 8260
 8261        let invalidation_range = multibuffer
 8262            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8263            ..multibuffer.anchor_after(Point::new(
 8264                invalidation_row_range.end,
 8265                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8266            ));
 8267
 8268        self.stale_edit_prediction_in_menu = None;
 8269        self.active_edit_prediction = Some(EditPredictionState {
 8270            inlay_ids,
 8271            completion,
 8272            completion_id,
 8273            invalidation_range: Some(invalidation_range),
 8274        });
 8275
 8276        cx.notify();
 8277
 8278        Some(())
 8279    }
 8280
 8281    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8282        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8283    }
 8284
 8285    fn clear_tasks(&mut self) {
 8286        self.tasks.clear()
 8287    }
 8288
 8289    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8290        if self.tasks.insert(key, value).is_some() {
 8291            // This case should hopefully be rare, but just in case...
 8292            log::error!(
 8293                "multiple different run targets found on a single line, only the last target will be rendered"
 8294            )
 8295        }
 8296    }
 8297
 8298    /// Get all display points of breakpoints that will be rendered within editor
 8299    ///
 8300    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8301    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8302    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8303    fn active_breakpoints(
 8304        &self,
 8305        range: Range<DisplayRow>,
 8306        window: &mut Window,
 8307        cx: &mut Context<Self>,
 8308    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8309        let mut breakpoint_display_points = HashMap::default();
 8310
 8311        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8312            return breakpoint_display_points;
 8313        };
 8314
 8315        let snapshot = self.snapshot(window, cx);
 8316
 8317        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8318        let Some(project) = self.project() else {
 8319            return breakpoint_display_points;
 8320        };
 8321
 8322        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8323            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8324
 8325        for (buffer_snapshot, range, excerpt_id) in
 8326            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8327        {
 8328            let Some(buffer) = project
 8329                .read(cx)
 8330                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8331            else {
 8332                continue;
 8333            };
 8334            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8335                &buffer,
 8336                Some(
 8337                    buffer_snapshot.anchor_before(range.start)
 8338                        ..buffer_snapshot.anchor_after(range.end),
 8339                ),
 8340                buffer_snapshot,
 8341                cx,
 8342            );
 8343            for (breakpoint, state) in breakpoints {
 8344                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8345                let position = multi_buffer_anchor
 8346                    .to_point(&multi_buffer_snapshot)
 8347                    .to_display_point(&snapshot);
 8348
 8349                breakpoint_display_points.insert(
 8350                    position.row(),
 8351                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8352                );
 8353            }
 8354        }
 8355
 8356        breakpoint_display_points
 8357    }
 8358
 8359    fn breakpoint_context_menu(
 8360        &self,
 8361        anchor: Anchor,
 8362        window: &mut Window,
 8363        cx: &mut Context<Self>,
 8364    ) -> Entity<ui::ContextMenu> {
 8365        let weak_editor = cx.weak_entity();
 8366        let focus_handle = self.focus_handle(cx);
 8367
 8368        let row = self
 8369            .buffer
 8370            .read(cx)
 8371            .snapshot(cx)
 8372            .summary_for_anchor::<Point>(&anchor)
 8373            .row;
 8374
 8375        let breakpoint = self
 8376            .breakpoint_at_row(row, window, cx)
 8377            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8378
 8379        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8380            "Edit Log Breakpoint"
 8381        } else {
 8382            "Set Log Breakpoint"
 8383        };
 8384
 8385        let condition_breakpoint_msg = if breakpoint
 8386            .as_ref()
 8387            .is_some_and(|bp| bp.1.condition.is_some())
 8388        {
 8389            "Edit Condition Breakpoint"
 8390        } else {
 8391            "Set Condition Breakpoint"
 8392        };
 8393
 8394        let hit_condition_breakpoint_msg = if breakpoint
 8395            .as_ref()
 8396            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8397        {
 8398            "Edit Hit Condition Breakpoint"
 8399        } else {
 8400            "Set Hit Condition Breakpoint"
 8401        };
 8402
 8403        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8404            "Unset Breakpoint"
 8405        } else {
 8406            "Set Breakpoint"
 8407        };
 8408
 8409        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8410
 8411        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8412            BreakpointState::Enabled => Some("Disable"),
 8413            BreakpointState::Disabled => Some("Enable"),
 8414        });
 8415
 8416        let (anchor, breakpoint) =
 8417            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8418
 8419        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8420            menu.on_blur_subscription(Subscription::new(|| {}))
 8421                .context(focus_handle)
 8422                .when(run_to_cursor, |this| {
 8423                    let weak_editor = weak_editor.clone();
 8424                    this.entry("Run to cursor", None, move |window, cx| {
 8425                        weak_editor
 8426                            .update(cx, |editor, cx| {
 8427                                editor.change_selections(
 8428                                    SelectionEffects::no_scroll(),
 8429                                    window,
 8430                                    cx,
 8431                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8432                                );
 8433                            })
 8434                            .ok();
 8435
 8436                        window.dispatch_action(Box::new(RunToCursor), cx);
 8437                    })
 8438                    .separator()
 8439                })
 8440                .when_some(toggle_state_msg, |this, msg| {
 8441                    this.entry(msg, None, {
 8442                        let weak_editor = weak_editor.clone();
 8443                        let breakpoint = breakpoint.clone();
 8444                        move |_window, cx| {
 8445                            weak_editor
 8446                                .update(cx, |this, cx| {
 8447                                    this.edit_breakpoint_at_anchor(
 8448                                        anchor,
 8449                                        breakpoint.as_ref().clone(),
 8450                                        BreakpointEditAction::InvertState,
 8451                                        cx,
 8452                                    );
 8453                                })
 8454                                .log_err();
 8455                        }
 8456                    })
 8457                })
 8458                .entry(set_breakpoint_msg, None, {
 8459                    let weak_editor = weak_editor.clone();
 8460                    let breakpoint = breakpoint.clone();
 8461                    move |_window, cx| {
 8462                        weak_editor
 8463                            .update(cx, |this, cx| {
 8464                                this.edit_breakpoint_at_anchor(
 8465                                    anchor,
 8466                                    breakpoint.as_ref().clone(),
 8467                                    BreakpointEditAction::Toggle,
 8468                                    cx,
 8469                                );
 8470                            })
 8471                            .log_err();
 8472                    }
 8473                })
 8474                .entry(log_breakpoint_msg, None, {
 8475                    let breakpoint = breakpoint.clone();
 8476                    let weak_editor = weak_editor.clone();
 8477                    move |window, cx| {
 8478                        weak_editor
 8479                            .update(cx, |this, cx| {
 8480                                this.add_edit_breakpoint_block(
 8481                                    anchor,
 8482                                    breakpoint.as_ref(),
 8483                                    BreakpointPromptEditAction::Log,
 8484                                    window,
 8485                                    cx,
 8486                                );
 8487                            })
 8488                            .log_err();
 8489                    }
 8490                })
 8491                .entry(condition_breakpoint_msg, None, {
 8492                    let breakpoint = breakpoint.clone();
 8493                    let weak_editor = weak_editor.clone();
 8494                    move |window, cx| {
 8495                        weak_editor
 8496                            .update(cx, |this, cx| {
 8497                                this.add_edit_breakpoint_block(
 8498                                    anchor,
 8499                                    breakpoint.as_ref(),
 8500                                    BreakpointPromptEditAction::Condition,
 8501                                    window,
 8502                                    cx,
 8503                                );
 8504                            })
 8505                            .log_err();
 8506                    }
 8507                })
 8508                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8509                    weak_editor
 8510                        .update(cx, |this, cx| {
 8511                            this.add_edit_breakpoint_block(
 8512                                anchor,
 8513                                breakpoint.as_ref(),
 8514                                BreakpointPromptEditAction::HitCondition,
 8515                                window,
 8516                                cx,
 8517                            );
 8518                        })
 8519                        .log_err();
 8520                })
 8521        })
 8522    }
 8523
 8524    fn render_breakpoint(
 8525        &self,
 8526        position: Anchor,
 8527        row: DisplayRow,
 8528        breakpoint: &Breakpoint,
 8529        state: Option<BreakpointSessionState>,
 8530        cx: &mut Context<Self>,
 8531    ) -> IconButton {
 8532        let is_rejected = state.is_some_and(|s| !s.verified);
 8533        // Is it a breakpoint that shows up when hovering over gutter?
 8534        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8535            (false, false),
 8536            |PhantomBreakpointIndicator {
 8537                 is_active,
 8538                 display_row,
 8539                 collides_with_existing_breakpoint,
 8540             }| {
 8541                (
 8542                    is_active && display_row == row,
 8543                    collides_with_existing_breakpoint,
 8544                )
 8545            },
 8546        );
 8547
 8548        let (color, icon) = {
 8549            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8550                (false, false) => ui::IconName::DebugBreakpoint,
 8551                (true, false) => ui::IconName::DebugLogBreakpoint,
 8552                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8553                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8554            };
 8555
 8556            let color = cx.theme().colors();
 8557
 8558            let color = if is_phantom {
 8559                if collides_with_existing {
 8560                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8561                } else {
 8562                    Color::Hint
 8563                }
 8564            } else if is_rejected {
 8565                Color::Disabled
 8566            } else {
 8567                Color::Debugger
 8568            };
 8569
 8570            (color, icon)
 8571        };
 8572
 8573        let breakpoint = Arc::from(breakpoint.clone());
 8574
 8575        let alt_as_text = gpui::Keystroke {
 8576            modifiers: Modifiers::secondary_key(),
 8577            ..Default::default()
 8578        };
 8579        let primary_action_text = if breakpoint.is_disabled() {
 8580            "Enable breakpoint"
 8581        } else if is_phantom && !collides_with_existing {
 8582            "Set breakpoint"
 8583        } else {
 8584            "Unset breakpoint"
 8585        };
 8586        let focus_handle = self.focus_handle.clone();
 8587
 8588        let meta = if is_rejected {
 8589            SharedString::from("No executable code is associated with this line.")
 8590        } else if collides_with_existing && !breakpoint.is_disabled() {
 8591            SharedString::from(format!(
 8592                "{alt_as_text}-click to disable,\nright-click for more options."
 8593            ))
 8594        } else {
 8595            SharedString::from("Right-click for more options.")
 8596        };
 8597        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8598            .icon_size(IconSize::XSmall)
 8599            .size(ui::ButtonSize::None)
 8600            .when(is_rejected, |this| {
 8601                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8602            })
 8603            .icon_color(color)
 8604            .style(ButtonStyle::Transparent)
 8605            .on_click(cx.listener({
 8606                move |editor, event: &ClickEvent, window, cx| {
 8607                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8608                        BreakpointEditAction::InvertState
 8609                    } else {
 8610                        BreakpointEditAction::Toggle
 8611                    };
 8612
 8613                    window.focus(&editor.focus_handle(cx), cx);
 8614                    editor.edit_breakpoint_at_anchor(
 8615                        position,
 8616                        breakpoint.as_ref().clone(),
 8617                        edit_action,
 8618                        cx,
 8619                    );
 8620                }
 8621            }))
 8622            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8623                editor.set_breakpoint_context_menu(
 8624                    row,
 8625                    Some(position),
 8626                    event.position(),
 8627                    window,
 8628                    cx,
 8629                );
 8630            }))
 8631            .tooltip(move |_window, cx| {
 8632                Tooltip::with_meta_in(
 8633                    primary_action_text,
 8634                    Some(&ToggleBreakpoint),
 8635                    meta.clone(),
 8636                    &focus_handle,
 8637                    cx,
 8638                )
 8639            })
 8640    }
 8641
 8642    fn build_tasks_context(
 8643        project: &Entity<Project>,
 8644        buffer: &Entity<Buffer>,
 8645        buffer_row: u32,
 8646        tasks: &Arc<RunnableTasks>,
 8647        cx: &mut Context<Self>,
 8648    ) -> Task<Option<task::TaskContext>> {
 8649        let position = Point::new(buffer_row, tasks.column);
 8650        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8651        let location = Location {
 8652            buffer: buffer.clone(),
 8653            range: range_start..range_start,
 8654        };
 8655        // Fill in the environmental variables from the tree-sitter captures
 8656        let mut captured_task_variables = TaskVariables::default();
 8657        for (capture_name, value) in tasks.extra_variables.clone() {
 8658            captured_task_variables.insert(
 8659                task::VariableName::Custom(capture_name.into()),
 8660                value.clone(),
 8661            );
 8662        }
 8663        project.update(cx, |project, cx| {
 8664            project.task_store().update(cx, |task_store, cx| {
 8665                task_store.task_context_for_location(captured_task_variables, location, cx)
 8666            })
 8667        })
 8668    }
 8669
 8670    pub fn spawn_nearest_task(
 8671        &mut self,
 8672        action: &SpawnNearestTask,
 8673        window: &mut Window,
 8674        cx: &mut Context<Self>,
 8675    ) {
 8676        let Some((workspace, _)) = self.workspace.clone() else {
 8677            return;
 8678        };
 8679        let Some(project) = self.project.clone() else {
 8680            return;
 8681        };
 8682
 8683        // Try to find a closest, enclosing node using tree-sitter that has a task
 8684        let Some((buffer, buffer_row, tasks)) = self
 8685            .find_enclosing_node_task(cx)
 8686            // Or find the task that's closest in row-distance.
 8687            .or_else(|| self.find_closest_task(cx))
 8688        else {
 8689            return;
 8690        };
 8691
 8692        let reveal_strategy = action.reveal;
 8693        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8694        cx.spawn_in(window, async move |_, cx| {
 8695            let context = task_context.await?;
 8696            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8697
 8698            let resolved = &mut resolved_task.resolved;
 8699            resolved.reveal = reveal_strategy;
 8700
 8701            workspace
 8702                .update_in(cx, |workspace, window, cx| {
 8703                    workspace.schedule_resolved_task(
 8704                        task_source_kind,
 8705                        resolved_task,
 8706                        false,
 8707                        window,
 8708                        cx,
 8709                    );
 8710                })
 8711                .ok()
 8712        })
 8713        .detach();
 8714    }
 8715
 8716    fn find_closest_task(
 8717        &mut self,
 8718        cx: &mut Context<Self>,
 8719    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8720        let cursor_row = self
 8721            .selections
 8722            .newest_adjusted(&self.display_snapshot(cx))
 8723            .head()
 8724            .row;
 8725
 8726        let ((buffer_id, row), tasks) = self
 8727            .tasks
 8728            .iter()
 8729            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8730
 8731        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8732        let tasks = Arc::new(tasks.to_owned());
 8733        Some((buffer, *row, tasks))
 8734    }
 8735
 8736    fn find_enclosing_node_task(
 8737        &mut self,
 8738        cx: &mut Context<Self>,
 8739    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8740        let snapshot = self.buffer.read(cx).snapshot(cx);
 8741        let offset = self
 8742            .selections
 8743            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8744            .head();
 8745        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8746        let offset = excerpt.map_offset_to_buffer(offset);
 8747        let buffer_id = excerpt.buffer().remote_id();
 8748
 8749        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8750        let mut cursor = layer.node().walk();
 8751
 8752        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8753            if cursor.node().end_byte() == offset.0 {
 8754                cursor.goto_next_sibling();
 8755            }
 8756        }
 8757
 8758        // Ascend to the smallest ancestor that contains the range and has a task.
 8759        loop {
 8760            let node = cursor.node();
 8761            let node_range = node.byte_range();
 8762            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8763
 8764            // Check if this node contains our offset
 8765            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8766                // If it contains offset, check for task
 8767                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8768                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8769                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8770                }
 8771            }
 8772
 8773            if !cursor.goto_parent() {
 8774                break;
 8775            }
 8776        }
 8777        None
 8778    }
 8779
 8780    fn render_run_indicator(
 8781        &self,
 8782        _style: &EditorStyle,
 8783        is_active: bool,
 8784        row: DisplayRow,
 8785        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8786        cx: &mut Context<Self>,
 8787    ) -> IconButton {
 8788        let color = Color::Muted;
 8789        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8790
 8791        IconButton::new(
 8792            ("run_indicator", row.0 as usize),
 8793            ui::IconName::PlayOutlined,
 8794        )
 8795        .shape(ui::IconButtonShape::Square)
 8796        .icon_size(IconSize::XSmall)
 8797        .icon_color(color)
 8798        .toggle_state(is_active)
 8799        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8800            let quick_launch = match e {
 8801                ClickEvent::Keyboard(_) => true,
 8802                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8803            };
 8804
 8805            window.focus(&editor.focus_handle(cx), cx);
 8806            editor.toggle_code_actions(
 8807                &ToggleCodeActions {
 8808                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8809                    quick_launch,
 8810                },
 8811                window,
 8812                cx,
 8813            );
 8814        }))
 8815        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8816            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8817        }))
 8818    }
 8819
 8820    pub fn context_menu_visible(&self) -> bool {
 8821        !self.edit_prediction_preview_is_active()
 8822            && self
 8823                .context_menu
 8824                .borrow()
 8825                .as_ref()
 8826                .is_some_and(|menu| menu.visible())
 8827    }
 8828
 8829    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8830        self.context_menu
 8831            .borrow()
 8832            .as_ref()
 8833            .map(|menu| menu.origin())
 8834    }
 8835
 8836    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8837        self.context_menu_options = Some(options);
 8838    }
 8839
 8840    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8841    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8842
 8843    fn render_edit_prediction_popover(
 8844        &mut self,
 8845        text_bounds: &Bounds<Pixels>,
 8846        content_origin: gpui::Point<Pixels>,
 8847        right_margin: Pixels,
 8848        editor_snapshot: &EditorSnapshot,
 8849        visible_row_range: Range<DisplayRow>,
 8850        scroll_top: ScrollOffset,
 8851        scroll_bottom: ScrollOffset,
 8852        line_layouts: &[LineWithInvisibles],
 8853        line_height: Pixels,
 8854        scroll_position: gpui::Point<ScrollOffset>,
 8855        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8856        newest_selection_head: Option<DisplayPoint>,
 8857        editor_width: Pixels,
 8858        style: &EditorStyle,
 8859        window: &mut Window,
 8860        cx: &mut App,
 8861    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8862        if self.mode().is_minimap() {
 8863            return None;
 8864        }
 8865        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8866
 8867        if self.edit_prediction_visible_in_cursor_popover(true) {
 8868            return None;
 8869        }
 8870
 8871        match &active_edit_prediction.completion {
 8872            EditPrediction::MoveWithin { target, .. } => {
 8873                let target_display_point = target.to_display_point(editor_snapshot);
 8874
 8875                if self.edit_prediction_requires_modifier() {
 8876                    if !self.edit_prediction_preview_is_active() {
 8877                        return None;
 8878                    }
 8879
 8880                    self.render_edit_prediction_modifier_jump_popover(
 8881                        text_bounds,
 8882                        content_origin,
 8883                        visible_row_range,
 8884                        line_layouts,
 8885                        line_height,
 8886                        scroll_pixel_position,
 8887                        newest_selection_head,
 8888                        target_display_point,
 8889                        window,
 8890                        cx,
 8891                    )
 8892                } else {
 8893                    self.render_edit_prediction_eager_jump_popover(
 8894                        text_bounds,
 8895                        content_origin,
 8896                        editor_snapshot,
 8897                        visible_row_range,
 8898                        scroll_top,
 8899                        scroll_bottom,
 8900                        line_height,
 8901                        scroll_pixel_position,
 8902                        target_display_point,
 8903                        editor_width,
 8904                        window,
 8905                        cx,
 8906                    )
 8907                }
 8908            }
 8909            EditPrediction::Edit {
 8910                display_mode: EditDisplayMode::Inline,
 8911                ..
 8912            } => None,
 8913            EditPrediction::Edit {
 8914                display_mode: EditDisplayMode::TabAccept,
 8915                edits,
 8916                ..
 8917            } => {
 8918                let range = &edits.first()?.0;
 8919                let target_display_point = range.end.to_display_point(editor_snapshot);
 8920
 8921                self.render_edit_prediction_end_of_line_popover(
 8922                    "Accept",
 8923                    editor_snapshot,
 8924                    visible_row_range,
 8925                    target_display_point,
 8926                    line_height,
 8927                    scroll_pixel_position,
 8928                    content_origin,
 8929                    editor_width,
 8930                    window,
 8931                    cx,
 8932                )
 8933            }
 8934            EditPrediction::Edit {
 8935                edits,
 8936                edit_preview,
 8937                display_mode: EditDisplayMode::DiffPopover,
 8938                snapshot,
 8939            } => self.render_edit_prediction_diff_popover(
 8940                text_bounds,
 8941                content_origin,
 8942                right_margin,
 8943                editor_snapshot,
 8944                visible_row_range,
 8945                line_layouts,
 8946                line_height,
 8947                scroll_position,
 8948                scroll_pixel_position,
 8949                newest_selection_head,
 8950                editor_width,
 8951                style,
 8952                edits,
 8953                edit_preview,
 8954                snapshot,
 8955                window,
 8956                cx,
 8957            ),
 8958            EditPrediction::MoveOutside { snapshot, .. } => {
 8959                let mut element = self
 8960                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 8961                    .into_any();
 8962
 8963                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8964                let origin_x = text_bounds.size.width - size.width - px(30.);
 8965                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 8966                element.prepaint_at(origin, window, cx);
 8967
 8968                Some((element, origin))
 8969            }
 8970        }
 8971    }
 8972
 8973    fn render_edit_prediction_modifier_jump_popover(
 8974        &mut self,
 8975        text_bounds: &Bounds<Pixels>,
 8976        content_origin: gpui::Point<Pixels>,
 8977        visible_row_range: Range<DisplayRow>,
 8978        line_layouts: &[LineWithInvisibles],
 8979        line_height: Pixels,
 8980        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8981        newest_selection_head: Option<DisplayPoint>,
 8982        target_display_point: DisplayPoint,
 8983        window: &mut Window,
 8984        cx: &mut App,
 8985    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8986        let scrolled_content_origin =
 8987            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8988
 8989        const SCROLL_PADDING_Y: Pixels = px(12.);
 8990
 8991        if target_display_point.row() < visible_row_range.start {
 8992            return self.render_edit_prediction_scroll_popover(
 8993                |_| SCROLL_PADDING_Y,
 8994                IconName::ArrowUp,
 8995                visible_row_range,
 8996                line_layouts,
 8997                newest_selection_head,
 8998                scrolled_content_origin,
 8999                window,
 9000                cx,
 9001            );
 9002        } else if target_display_point.row() >= visible_row_range.end {
 9003            return self.render_edit_prediction_scroll_popover(
 9004                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9005                IconName::ArrowDown,
 9006                visible_row_range,
 9007                line_layouts,
 9008                newest_selection_head,
 9009                scrolled_content_origin,
 9010                window,
 9011                cx,
 9012            );
 9013        }
 9014
 9015        const POLE_WIDTH: Pixels = px(2.);
 9016
 9017        let line_layout =
 9018            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9019        let target_column = target_display_point.column() as usize;
 9020
 9021        let target_x = line_layout.x_for_index(target_column);
 9022        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9023            - scroll_pixel_position.y;
 9024
 9025        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9026
 9027        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9028        border_color.l += 0.001;
 9029
 9030        let mut element = v_flex()
 9031            .items_end()
 9032            .when(flag_on_right, |el| el.items_start())
 9033            .child(if flag_on_right {
 9034                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9035                    .rounded_bl(px(0.))
 9036                    .rounded_tl(px(0.))
 9037                    .border_l_2()
 9038                    .border_color(border_color)
 9039            } else {
 9040                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9041                    .rounded_br(px(0.))
 9042                    .rounded_tr(px(0.))
 9043                    .border_r_2()
 9044                    .border_color(border_color)
 9045            })
 9046            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9047            .into_any();
 9048
 9049        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9050
 9051        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9052            - point(
 9053                if flag_on_right {
 9054                    POLE_WIDTH
 9055                } else {
 9056                    size.width - POLE_WIDTH
 9057                },
 9058                size.height - line_height,
 9059            );
 9060
 9061        origin.x = origin.x.max(content_origin.x);
 9062
 9063        element.prepaint_at(origin, window, cx);
 9064
 9065        Some((element, origin))
 9066    }
 9067
 9068    fn render_edit_prediction_scroll_popover(
 9069        &mut self,
 9070        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9071        scroll_icon: IconName,
 9072        visible_row_range: Range<DisplayRow>,
 9073        line_layouts: &[LineWithInvisibles],
 9074        newest_selection_head: Option<DisplayPoint>,
 9075        scrolled_content_origin: gpui::Point<Pixels>,
 9076        window: &mut Window,
 9077        cx: &mut App,
 9078    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9079        let mut element = self
 9080            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9081            .into_any();
 9082
 9083        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9084
 9085        let cursor = newest_selection_head?;
 9086        let cursor_row_layout =
 9087            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9088        let cursor_column = cursor.column() as usize;
 9089
 9090        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9091
 9092        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9093
 9094        element.prepaint_at(origin, window, cx);
 9095        Some((element, origin))
 9096    }
 9097
 9098    fn render_edit_prediction_eager_jump_popover(
 9099        &mut self,
 9100        text_bounds: &Bounds<Pixels>,
 9101        content_origin: gpui::Point<Pixels>,
 9102        editor_snapshot: &EditorSnapshot,
 9103        visible_row_range: Range<DisplayRow>,
 9104        scroll_top: ScrollOffset,
 9105        scroll_bottom: ScrollOffset,
 9106        line_height: Pixels,
 9107        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9108        target_display_point: DisplayPoint,
 9109        editor_width: Pixels,
 9110        window: &mut Window,
 9111        cx: &mut App,
 9112    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9113        if target_display_point.row().as_f64() < scroll_top {
 9114            let mut element = self
 9115                .render_edit_prediction_line_popover(
 9116                    "Jump to Edit",
 9117                    Some(IconName::ArrowUp),
 9118                    window,
 9119                    cx,
 9120                )
 9121                .into_any();
 9122
 9123            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9124            let offset = point(
 9125                (text_bounds.size.width - size.width) / 2.,
 9126                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9127            );
 9128
 9129            let origin = text_bounds.origin + offset;
 9130            element.prepaint_at(origin, window, cx);
 9131            Some((element, origin))
 9132        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9133            let mut element = self
 9134                .render_edit_prediction_line_popover(
 9135                    "Jump to Edit",
 9136                    Some(IconName::ArrowDown),
 9137                    window,
 9138                    cx,
 9139                )
 9140                .into_any();
 9141
 9142            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9143            let offset = point(
 9144                (text_bounds.size.width - size.width) / 2.,
 9145                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9146            );
 9147
 9148            let origin = text_bounds.origin + offset;
 9149            element.prepaint_at(origin, window, cx);
 9150            Some((element, origin))
 9151        } else {
 9152            self.render_edit_prediction_end_of_line_popover(
 9153                "Jump to Edit",
 9154                editor_snapshot,
 9155                visible_row_range,
 9156                target_display_point,
 9157                line_height,
 9158                scroll_pixel_position,
 9159                content_origin,
 9160                editor_width,
 9161                window,
 9162                cx,
 9163            )
 9164        }
 9165    }
 9166
 9167    fn render_edit_prediction_end_of_line_popover(
 9168        self: &mut Editor,
 9169        label: &'static str,
 9170        editor_snapshot: &EditorSnapshot,
 9171        visible_row_range: Range<DisplayRow>,
 9172        target_display_point: DisplayPoint,
 9173        line_height: Pixels,
 9174        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9175        content_origin: gpui::Point<Pixels>,
 9176        editor_width: Pixels,
 9177        window: &mut Window,
 9178        cx: &mut App,
 9179    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9180        let target_line_end = DisplayPoint::new(
 9181            target_display_point.row(),
 9182            editor_snapshot.line_len(target_display_point.row()),
 9183        );
 9184
 9185        let mut element = self
 9186            .render_edit_prediction_line_popover(label, None, window, cx)
 9187            .into_any();
 9188
 9189        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9190
 9191        let line_origin =
 9192            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9193
 9194        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9195        let mut origin = start_point
 9196            + line_origin
 9197            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9198        origin.x = origin.x.max(content_origin.x);
 9199
 9200        let max_x = content_origin.x + editor_width - size.width;
 9201
 9202        if origin.x > max_x {
 9203            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9204
 9205            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9206                origin.y += offset;
 9207                IconName::ArrowUp
 9208            } else {
 9209                origin.y -= offset;
 9210                IconName::ArrowDown
 9211            };
 9212
 9213            element = self
 9214                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9215                .into_any();
 9216
 9217            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9218
 9219            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9220        }
 9221
 9222        element.prepaint_at(origin, window, cx);
 9223        Some((element, origin))
 9224    }
 9225
 9226    fn render_edit_prediction_diff_popover(
 9227        self: &Editor,
 9228        text_bounds: &Bounds<Pixels>,
 9229        content_origin: gpui::Point<Pixels>,
 9230        right_margin: Pixels,
 9231        editor_snapshot: &EditorSnapshot,
 9232        visible_row_range: Range<DisplayRow>,
 9233        line_layouts: &[LineWithInvisibles],
 9234        line_height: Pixels,
 9235        scroll_position: gpui::Point<ScrollOffset>,
 9236        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9237        newest_selection_head: Option<DisplayPoint>,
 9238        editor_width: Pixels,
 9239        style: &EditorStyle,
 9240        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9241        edit_preview: &Option<language::EditPreview>,
 9242        snapshot: &language::BufferSnapshot,
 9243        window: &mut Window,
 9244        cx: &mut App,
 9245    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9246        let edit_start = edits
 9247            .first()
 9248            .unwrap()
 9249            .0
 9250            .start
 9251            .to_display_point(editor_snapshot);
 9252        let edit_end = edits
 9253            .last()
 9254            .unwrap()
 9255            .0
 9256            .end
 9257            .to_display_point(editor_snapshot);
 9258
 9259        let is_visible = visible_row_range.contains(&edit_start.row())
 9260            || visible_row_range.contains(&edit_end.row());
 9261        if !is_visible {
 9262            return None;
 9263        }
 9264
 9265        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9266            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9267        } else {
 9268            // Fallback for providers without edit_preview
 9269            crate::edit_prediction_fallback_text(edits, cx)
 9270        };
 9271
 9272        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9273        let line_count = highlighted_edits.text.lines().count();
 9274
 9275        const BORDER_WIDTH: Pixels = px(1.);
 9276
 9277        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9278        let has_keybind = keybind.is_some();
 9279
 9280        let mut element = h_flex()
 9281            .items_start()
 9282            .child(
 9283                h_flex()
 9284                    .bg(cx.theme().colors().editor_background)
 9285                    .border(BORDER_WIDTH)
 9286                    .shadow_xs()
 9287                    .border_color(cx.theme().colors().border)
 9288                    .rounded_l_lg()
 9289                    .when(line_count > 1, |el| el.rounded_br_lg())
 9290                    .pr_1()
 9291                    .child(styled_text),
 9292            )
 9293            .child(
 9294                h_flex()
 9295                    .h(line_height + BORDER_WIDTH * 2.)
 9296                    .px_1p5()
 9297                    .gap_1()
 9298                    // Workaround: For some reason, there's a gap if we don't do this
 9299                    .ml(-BORDER_WIDTH)
 9300                    .shadow(vec![gpui::BoxShadow {
 9301                        color: gpui::black().opacity(0.05),
 9302                        offset: point(px(1.), px(1.)),
 9303                        blur_radius: px(2.),
 9304                        spread_radius: px(0.),
 9305                    }])
 9306                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9307                    .border(BORDER_WIDTH)
 9308                    .border_color(cx.theme().colors().border)
 9309                    .rounded_r_lg()
 9310                    .id("edit_prediction_diff_popover_keybind")
 9311                    .when(!has_keybind, |el| {
 9312                        let status_colors = cx.theme().status();
 9313
 9314                        el.bg(status_colors.error_background)
 9315                            .border_color(status_colors.error.opacity(0.6))
 9316                            .child(Icon::new(IconName::Info).color(Color::Error))
 9317                            .cursor_default()
 9318                            .hoverable_tooltip(move |_window, cx| {
 9319                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9320                            })
 9321                    })
 9322                    .children(keybind),
 9323            )
 9324            .into_any();
 9325
 9326        let longest_row =
 9327            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9328        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9329            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9330        } else {
 9331            layout_line(
 9332                longest_row,
 9333                editor_snapshot,
 9334                style,
 9335                editor_width,
 9336                |_| false,
 9337                window,
 9338                cx,
 9339            )
 9340            .width
 9341        };
 9342
 9343        let viewport_bounds =
 9344            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9345                right: -right_margin,
 9346                ..Default::default()
 9347            });
 9348
 9349        let x_after_longest = Pixels::from(
 9350            ScrollPixelOffset::from(
 9351                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9352            ) - scroll_pixel_position.x,
 9353        );
 9354
 9355        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9356
 9357        // Fully visible if it can be displayed within the window (allow overlapping other
 9358        // panes). However, this is only allowed if the popover starts within text_bounds.
 9359        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9360            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9361
 9362        let mut origin = if can_position_to_the_right {
 9363            point(
 9364                x_after_longest,
 9365                text_bounds.origin.y
 9366                    + Pixels::from(
 9367                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9368                            - scroll_pixel_position.y,
 9369                    ),
 9370            )
 9371        } else {
 9372            let cursor_row = newest_selection_head.map(|head| head.row());
 9373            let above_edit = edit_start
 9374                .row()
 9375                .0
 9376                .checked_sub(line_count as u32)
 9377                .map(DisplayRow);
 9378            let below_edit = Some(edit_end.row() + 1);
 9379            let above_cursor =
 9380                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9381            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9382
 9383            // Place the edit popover adjacent to the edit if there is a location
 9384            // available that is onscreen and does not obscure the cursor. Otherwise,
 9385            // place it adjacent to the cursor.
 9386            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9387                .into_iter()
 9388                .flatten()
 9389                .find(|&start_row| {
 9390                    let end_row = start_row + line_count as u32;
 9391                    visible_row_range.contains(&start_row)
 9392                        && visible_row_range.contains(&end_row)
 9393                        && cursor_row
 9394                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9395                })?;
 9396
 9397            content_origin
 9398                + point(
 9399                    Pixels::from(-scroll_pixel_position.x),
 9400                    Pixels::from(
 9401                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9402                    ),
 9403                )
 9404        };
 9405
 9406        origin.x -= BORDER_WIDTH;
 9407
 9408        window.defer_draw(element, origin, 1);
 9409
 9410        // Do not return an element, since it will already be drawn due to defer_draw.
 9411        None
 9412    }
 9413
 9414    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9415        px(30.)
 9416    }
 9417
 9418    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9419        if self.read_only(cx) {
 9420            cx.theme().players().read_only()
 9421        } else {
 9422            self.style.as_ref().unwrap().local_player
 9423        }
 9424    }
 9425
 9426    fn render_edit_prediction_accept_keybind(
 9427        &self,
 9428        window: &mut Window,
 9429        cx: &mut App,
 9430    ) -> Option<AnyElement> {
 9431        let accept_binding =
 9432            self.accept_edit_prediction_keybind(EditPredictionGranularity::Full, window, cx);
 9433        let accept_keystroke = accept_binding.keystroke()?;
 9434
 9435        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9436
 9437        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9438            Color::Accent
 9439        } else {
 9440            Color::Muted
 9441        };
 9442
 9443        h_flex()
 9444            .px_0p5()
 9445            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9446            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9447            .text_size(TextSize::XSmall.rems(cx))
 9448            .child(h_flex().children(ui::render_modifiers(
 9449                accept_keystroke.modifiers(),
 9450                PlatformStyle::platform(),
 9451                Some(modifiers_color),
 9452                Some(IconSize::XSmall.rems().into()),
 9453                true,
 9454            )))
 9455            .when(is_platform_style_mac, |parent| {
 9456                parent.child(accept_keystroke.key().to_string())
 9457            })
 9458            .when(!is_platform_style_mac, |parent| {
 9459                parent.child(
 9460                    Key::new(
 9461                        util::capitalize(accept_keystroke.key()),
 9462                        Some(Color::Default),
 9463                    )
 9464                    .size(Some(IconSize::XSmall.rems().into())),
 9465                )
 9466            })
 9467            .into_any()
 9468            .into()
 9469    }
 9470
 9471    fn render_edit_prediction_line_popover(
 9472        &self,
 9473        label: impl Into<SharedString>,
 9474        icon: Option<IconName>,
 9475        window: &mut Window,
 9476        cx: &mut App,
 9477    ) -> Stateful<Div> {
 9478        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9479
 9480        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9481        let has_keybind = keybind.is_some();
 9482
 9483        h_flex()
 9484            .id("ep-line-popover")
 9485            .py_0p5()
 9486            .pl_1()
 9487            .pr(padding_right)
 9488            .gap_1()
 9489            .rounded_md()
 9490            .border_1()
 9491            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9492            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9493            .shadow_xs()
 9494            .when(!has_keybind, |el| {
 9495                let status_colors = cx.theme().status();
 9496
 9497                el.bg(status_colors.error_background)
 9498                    .border_color(status_colors.error.opacity(0.6))
 9499                    .pl_2()
 9500                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9501                    .cursor_default()
 9502                    .hoverable_tooltip(move |_window, cx| {
 9503                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9504                    })
 9505            })
 9506            .children(keybind)
 9507            .child(
 9508                Label::new(label)
 9509                    .size(LabelSize::Small)
 9510                    .when(!has_keybind, |el| {
 9511                        el.color(cx.theme().status().error.into()).strikethrough()
 9512                    }),
 9513            )
 9514            .when(!has_keybind, |el| {
 9515                el.child(
 9516                    h_flex().ml_1().child(
 9517                        Icon::new(IconName::Info)
 9518                            .size(IconSize::Small)
 9519                            .color(cx.theme().status().error.into()),
 9520                    ),
 9521                )
 9522            })
 9523            .when_some(icon, |element, icon| {
 9524                element.child(
 9525                    div()
 9526                        .mt(px(1.5))
 9527                        .child(Icon::new(icon).size(IconSize::Small)),
 9528                )
 9529            })
 9530    }
 9531
 9532    fn render_edit_prediction_jump_outside_popover(
 9533        &self,
 9534        snapshot: &BufferSnapshot,
 9535        window: &mut Window,
 9536        cx: &mut App,
 9537    ) -> Stateful<Div> {
 9538        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9539        let has_keybind = keybind.is_some();
 9540
 9541        let file_name = snapshot
 9542            .file()
 9543            .map(|file| SharedString::new(file.file_name(cx)))
 9544            .unwrap_or(SharedString::new_static("untitled"));
 9545
 9546        h_flex()
 9547            .id("ep-jump-outside-popover")
 9548            .py_1()
 9549            .px_2()
 9550            .gap_1()
 9551            .rounded_md()
 9552            .border_1()
 9553            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9554            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9555            .shadow_xs()
 9556            .when(!has_keybind, |el| {
 9557                let status_colors = cx.theme().status();
 9558
 9559                el.bg(status_colors.error_background)
 9560                    .border_color(status_colors.error.opacity(0.6))
 9561                    .pl_2()
 9562                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9563                    .cursor_default()
 9564                    .hoverable_tooltip(move |_window, cx| {
 9565                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9566                    })
 9567            })
 9568            .children(keybind)
 9569            .child(
 9570                Label::new(file_name)
 9571                    .size(LabelSize::Small)
 9572                    .buffer_font(cx)
 9573                    .when(!has_keybind, |el| {
 9574                        el.color(cx.theme().status().error.into()).strikethrough()
 9575                    }),
 9576            )
 9577            .when(!has_keybind, |el| {
 9578                el.child(
 9579                    h_flex().ml_1().child(
 9580                        Icon::new(IconName::Info)
 9581                            .size(IconSize::Small)
 9582                            .color(cx.theme().status().error.into()),
 9583                    ),
 9584                )
 9585            })
 9586            .child(
 9587                div()
 9588                    .mt(px(1.5))
 9589                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9590            )
 9591    }
 9592
 9593    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9594        let accent_color = cx.theme().colors().text_accent;
 9595        let editor_bg_color = cx.theme().colors().editor_background;
 9596        editor_bg_color.blend(accent_color.opacity(0.1))
 9597    }
 9598
 9599    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9600        let accent_color = cx.theme().colors().text_accent;
 9601        let editor_bg_color = cx.theme().colors().editor_background;
 9602        editor_bg_color.blend(accent_color.opacity(0.6))
 9603    }
 9604    fn get_prediction_provider_icon_name(
 9605        provider: &Option<RegisteredEditPredictionDelegate>,
 9606    ) -> IconName {
 9607        match provider {
 9608            Some(provider) => match provider.provider.name() {
 9609                "copilot" => IconName::Copilot,
 9610                "supermaven" => IconName::Supermaven,
 9611                _ => IconName::ZedPredict,
 9612            },
 9613            None => IconName::ZedPredict,
 9614        }
 9615    }
 9616
 9617    fn render_edit_prediction_cursor_popover(
 9618        &self,
 9619        min_width: Pixels,
 9620        max_width: Pixels,
 9621        cursor_point: Point,
 9622        style: &EditorStyle,
 9623        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9624        _window: &Window,
 9625        cx: &mut Context<Editor>,
 9626    ) -> Option<AnyElement> {
 9627        let provider = self.edit_prediction_provider.as_ref()?;
 9628        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9629
 9630        let is_refreshing = provider.provider.is_refreshing(cx);
 9631
 9632        fn pending_completion_container(icon: IconName) -> Div {
 9633            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9634        }
 9635
 9636        let completion = match &self.active_edit_prediction {
 9637            Some(prediction) => {
 9638                if !self.has_visible_completions_menu() {
 9639                    const RADIUS: Pixels = px(6.);
 9640                    const BORDER_WIDTH: Pixels = px(1.);
 9641
 9642                    return Some(
 9643                        h_flex()
 9644                            .elevation_2(cx)
 9645                            .border(BORDER_WIDTH)
 9646                            .border_color(cx.theme().colors().border)
 9647                            .when(accept_keystroke.is_none(), |el| {
 9648                                el.border_color(cx.theme().status().error)
 9649                            })
 9650                            .rounded(RADIUS)
 9651                            .rounded_tl(px(0.))
 9652                            .overflow_hidden()
 9653                            .child(div().px_1p5().child(match &prediction.completion {
 9654                                EditPrediction::MoveWithin { target, snapshot } => {
 9655                                    use text::ToPoint as _;
 9656                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9657                                    {
 9658                                        Icon::new(IconName::ZedPredictDown)
 9659                                    } else {
 9660                                        Icon::new(IconName::ZedPredictUp)
 9661                                    }
 9662                                }
 9663                                EditPrediction::MoveOutside { .. } => {
 9664                                    // TODO [zeta2] custom icon for external jump?
 9665                                    Icon::new(provider_icon)
 9666                                }
 9667                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9668                            }))
 9669                            .child(
 9670                                h_flex()
 9671                                    .gap_1()
 9672                                    .py_1()
 9673                                    .px_2()
 9674                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9675                                    .border_l_1()
 9676                                    .border_color(cx.theme().colors().border)
 9677                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9678                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9679                                        el.child(
 9680                                            Label::new("Hold")
 9681                                                .size(LabelSize::Small)
 9682                                                .when(accept_keystroke.is_none(), |el| {
 9683                                                    el.strikethrough()
 9684                                                })
 9685                                                .line_height_style(LineHeightStyle::UiLabel),
 9686                                        )
 9687                                    })
 9688                                    .id("edit_prediction_cursor_popover_keybind")
 9689                                    .when(accept_keystroke.is_none(), |el| {
 9690                                        let status_colors = cx.theme().status();
 9691
 9692                                        el.bg(status_colors.error_background)
 9693                                            .border_color(status_colors.error.opacity(0.6))
 9694                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9695                                            .cursor_default()
 9696                                            .hoverable_tooltip(move |_window, cx| {
 9697                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9698                                                    .into()
 9699                                            })
 9700                                    })
 9701                                    .when_some(
 9702                                        accept_keystroke.as_ref(),
 9703                                        |el, accept_keystroke| {
 9704                                            el.child(h_flex().children(ui::render_modifiers(
 9705                                                accept_keystroke.modifiers(),
 9706                                                PlatformStyle::platform(),
 9707                                                Some(Color::Default),
 9708                                                Some(IconSize::XSmall.rems().into()),
 9709                                                false,
 9710                                            )))
 9711                                        },
 9712                                    ),
 9713                            )
 9714                            .into_any(),
 9715                    );
 9716                }
 9717
 9718                self.render_edit_prediction_cursor_popover_preview(
 9719                    prediction,
 9720                    cursor_point,
 9721                    style,
 9722                    cx,
 9723                )?
 9724            }
 9725
 9726            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9727                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9728                    stale_completion,
 9729                    cursor_point,
 9730                    style,
 9731                    cx,
 9732                )?,
 9733
 9734                None => pending_completion_container(provider_icon)
 9735                    .child(Label::new("...").size(LabelSize::Small)),
 9736            },
 9737
 9738            None => pending_completion_container(provider_icon)
 9739                .child(Label::new("...").size(LabelSize::Small)),
 9740        };
 9741
 9742        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9743            completion
 9744                .with_animation(
 9745                    "loading-completion",
 9746                    Animation::new(Duration::from_secs(2))
 9747                        .repeat()
 9748                        .with_easing(pulsating_between(0.4, 0.8)),
 9749                    |label, delta| label.opacity(delta),
 9750                )
 9751                .into_any_element()
 9752        } else {
 9753            completion.into_any_element()
 9754        };
 9755
 9756        let has_completion = self.active_edit_prediction.is_some();
 9757
 9758        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9759        Some(
 9760            h_flex()
 9761                .min_w(min_width)
 9762                .max_w(max_width)
 9763                .flex_1()
 9764                .elevation_2(cx)
 9765                .border_color(cx.theme().colors().border)
 9766                .child(
 9767                    div()
 9768                        .flex_1()
 9769                        .py_1()
 9770                        .px_2()
 9771                        .overflow_hidden()
 9772                        .child(completion),
 9773                )
 9774                .when_some(accept_keystroke, |el, accept_keystroke| {
 9775                    if !accept_keystroke.modifiers().modified() {
 9776                        return el;
 9777                    }
 9778
 9779                    el.child(
 9780                        h_flex()
 9781                            .h_full()
 9782                            .border_l_1()
 9783                            .rounded_r_lg()
 9784                            .border_color(cx.theme().colors().border)
 9785                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9786                            .gap_1()
 9787                            .py_1()
 9788                            .px_2()
 9789                            .child(
 9790                                h_flex()
 9791                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9792                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9793                                    .child(h_flex().children(ui::render_modifiers(
 9794                                        accept_keystroke.modifiers(),
 9795                                        PlatformStyle::platform(),
 9796                                        Some(if !has_completion {
 9797                                            Color::Muted
 9798                                        } else {
 9799                                            Color::Default
 9800                                        }),
 9801                                        None,
 9802                                        false,
 9803                                    ))),
 9804                            )
 9805                            .child(Label::new("Preview").into_any_element())
 9806                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9807                    )
 9808                })
 9809                .into_any(),
 9810        )
 9811    }
 9812
 9813    fn render_edit_prediction_cursor_popover_preview(
 9814        &self,
 9815        completion: &EditPredictionState,
 9816        cursor_point: Point,
 9817        style: &EditorStyle,
 9818        cx: &mut Context<Editor>,
 9819    ) -> Option<Div> {
 9820        use text::ToPoint as _;
 9821
 9822        fn render_relative_row_jump(
 9823            prefix: impl Into<String>,
 9824            current_row: u32,
 9825            target_row: u32,
 9826        ) -> Div {
 9827            let (row_diff, arrow) = if target_row < current_row {
 9828                (current_row - target_row, IconName::ArrowUp)
 9829            } else {
 9830                (target_row - current_row, IconName::ArrowDown)
 9831            };
 9832
 9833            h_flex()
 9834                .child(
 9835                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9836                        .color(Color::Muted)
 9837                        .size(LabelSize::Small),
 9838                )
 9839                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9840        }
 9841
 9842        let supports_jump = self
 9843            .edit_prediction_provider
 9844            .as_ref()
 9845            .map(|provider| provider.provider.supports_jump_to_edit())
 9846            .unwrap_or(true);
 9847
 9848        match &completion.completion {
 9849            EditPrediction::MoveWithin {
 9850                target, snapshot, ..
 9851            } => {
 9852                if !supports_jump {
 9853                    return None;
 9854                }
 9855
 9856                Some(
 9857                    h_flex()
 9858                        .px_2()
 9859                        .gap_2()
 9860                        .flex_1()
 9861                        .child(
 9862                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9863                                Icon::new(IconName::ZedPredictDown)
 9864                            } else {
 9865                                Icon::new(IconName::ZedPredictUp)
 9866                            },
 9867                        )
 9868                        .child(Label::new("Jump to Edit")),
 9869                )
 9870            }
 9871            EditPrediction::MoveOutside { snapshot, .. } => {
 9872                let file_name = snapshot
 9873                    .file()
 9874                    .map(|file| file.file_name(cx))
 9875                    .unwrap_or("untitled");
 9876                Some(
 9877                    h_flex()
 9878                        .px_2()
 9879                        .gap_2()
 9880                        .flex_1()
 9881                        .child(Icon::new(IconName::ZedPredict))
 9882                        .child(Label::new(format!("Jump to {file_name}"))),
 9883                )
 9884            }
 9885            EditPrediction::Edit {
 9886                edits,
 9887                edit_preview,
 9888                snapshot,
 9889                display_mode: _,
 9890            } => {
 9891                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9892
 9893                let (highlighted_edits, has_more_lines) =
 9894                    if let Some(edit_preview) = edit_preview.as_ref() {
 9895                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9896                            .first_line_preview()
 9897                    } else {
 9898                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9899                    };
 9900
 9901                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9902                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9903
 9904                let preview = h_flex()
 9905                    .gap_1()
 9906                    .min_w_16()
 9907                    .child(styled_text)
 9908                    .when(has_more_lines, |parent| parent.child(""));
 9909
 9910                let left = if supports_jump && first_edit_row != cursor_point.row {
 9911                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9912                        .into_any_element()
 9913                } else {
 9914                    let icon_name =
 9915                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9916                    Icon::new(icon_name).into_any_element()
 9917                };
 9918
 9919                Some(
 9920                    h_flex()
 9921                        .h_full()
 9922                        .flex_1()
 9923                        .gap_2()
 9924                        .pr_1()
 9925                        .overflow_x_hidden()
 9926                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9927                        .child(left)
 9928                        .child(preview),
 9929                )
 9930            }
 9931        }
 9932    }
 9933
 9934    pub fn render_context_menu(
 9935        &mut self,
 9936        max_height_in_lines: u32,
 9937        window: &mut Window,
 9938        cx: &mut Context<Editor>,
 9939    ) -> Option<AnyElement> {
 9940        let menu = self.context_menu.borrow();
 9941        let menu = menu.as_ref()?;
 9942        if !menu.visible() {
 9943            return None;
 9944        };
 9945        self.style
 9946            .as_ref()
 9947            .map(|style| menu.render(style, max_height_in_lines, window, cx))
 9948    }
 9949
 9950    fn render_context_menu_aside(
 9951        &mut self,
 9952        max_size: Size<Pixels>,
 9953        window: &mut Window,
 9954        cx: &mut Context<Editor>,
 9955    ) -> Option<AnyElement> {
 9956        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9957            if menu.visible() {
 9958                menu.render_aside(max_size, window, cx)
 9959            } else {
 9960                None
 9961            }
 9962        })
 9963    }
 9964
 9965    fn hide_context_menu(
 9966        &mut self,
 9967        window: &mut Window,
 9968        cx: &mut Context<Self>,
 9969    ) -> Option<CodeContextMenu> {
 9970        cx.notify();
 9971        self.completion_tasks.clear();
 9972        let context_menu = self.context_menu.borrow_mut().take();
 9973        self.stale_edit_prediction_in_menu.take();
 9974        self.update_visible_edit_prediction(window, cx);
 9975        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9976            && let Some(completion_provider) = &self.completion_provider
 9977        {
 9978            completion_provider.selection_changed(None, window, cx);
 9979        }
 9980        context_menu
 9981    }
 9982
 9983    fn show_snippet_choices(
 9984        &mut self,
 9985        choices: &Vec<String>,
 9986        selection: Range<Anchor>,
 9987        cx: &mut Context<Self>,
 9988    ) {
 9989        let Some((_, buffer, _)) = self
 9990            .buffer()
 9991            .read(cx)
 9992            .excerpt_containing(selection.start, cx)
 9993        else {
 9994            return;
 9995        };
 9996        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9997        else {
 9998            return;
 9999        };
10000        if buffer != end_buffer {
10001            log::error!("expected anchor range to have matching buffer IDs");
10002            return;
10003        }
10004
10005        let id = post_inc(&mut self.next_completion_id);
10006        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10007        let mut context_menu = self.context_menu.borrow_mut();
10008        let old_menu = context_menu.take();
10009        *context_menu = Some(CodeContextMenu::Completions(
10010            CompletionsMenu::new_snippet_choices(
10011                id,
10012                true,
10013                choices,
10014                selection,
10015                buffer,
10016                old_menu.map(|menu| menu.primary_scroll_handle()),
10017                snippet_sort_order,
10018            ),
10019        ));
10020    }
10021
10022    pub fn insert_snippet(
10023        &mut self,
10024        insertion_ranges: &[Range<MultiBufferOffset>],
10025        snippet: Snippet,
10026        window: &mut Window,
10027        cx: &mut Context<Self>,
10028    ) -> Result<()> {
10029        struct Tabstop<T> {
10030            is_end_tabstop: bool,
10031            ranges: Vec<Range<T>>,
10032            choices: Option<Vec<String>>,
10033        }
10034
10035        let tabstops = self.buffer.update(cx, |buffer, cx| {
10036            let snippet_text: Arc<str> = snippet.text.clone().into();
10037            let edits = insertion_ranges
10038                .iter()
10039                .cloned()
10040                .map(|range| (range, snippet_text.clone()));
10041            let autoindent_mode = AutoindentMode::Block {
10042                original_indent_columns: Vec::new(),
10043            };
10044            buffer.edit(edits, Some(autoindent_mode), cx);
10045
10046            let snapshot = &*buffer.read(cx);
10047            let snippet = &snippet;
10048            snippet
10049                .tabstops
10050                .iter()
10051                .map(|tabstop| {
10052                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10053                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10054                    });
10055                    let mut tabstop_ranges = tabstop
10056                        .ranges
10057                        .iter()
10058                        .flat_map(|tabstop_range| {
10059                            let mut delta = 0_isize;
10060                            insertion_ranges.iter().map(move |insertion_range| {
10061                                let insertion_start = insertion_range.start + delta;
10062                                delta += snippet.text.len() as isize
10063                                    - (insertion_range.end - insertion_range.start) as isize;
10064
10065                                let start =
10066                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10067                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10068                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10069                            })
10070                        })
10071                        .collect::<Vec<_>>();
10072                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10073
10074                    Tabstop {
10075                        is_end_tabstop,
10076                        ranges: tabstop_ranges,
10077                        choices: tabstop.choices.clone(),
10078                    }
10079                })
10080                .collect::<Vec<_>>()
10081        });
10082        if let Some(tabstop) = tabstops.first() {
10083            self.change_selections(Default::default(), window, cx, |s| {
10084                // Reverse order so that the first range is the newest created selection.
10085                // Completions will use it and autoscroll will prioritize it.
10086                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10087            });
10088
10089            if let Some(choices) = &tabstop.choices
10090                && let Some(selection) = tabstop.ranges.first()
10091            {
10092                self.show_snippet_choices(choices, selection.clone(), cx)
10093            }
10094
10095            // If we're already at the last tabstop and it's at the end of the snippet,
10096            // we're done, we don't need to keep the state around.
10097            if !tabstop.is_end_tabstop {
10098                let choices = tabstops
10099                    .iter()
10100                    .map(|tabstop| tabstop.choices.clone())
10101                    .collect();
10102
10103                let ranges = tabstops
10104                    .into_iter()
10105                    .map(|tabstop| tabstop.ranges)
10106                    .collect::<Vec<_>>();
10107
10108                self.snippet_stack.push(SnippetState {
10109                    active_index: 0,
10110                    ranges,
10111                    choices,
10112                });
10113            }
10114
10115            // Check whether the just-entered snippet ends with an auto-closable bracket.
10116            if self.autoclose_regions.is_empty() {
10117                let snapshot = self.buffer.read(cx).snapshot(cx);
10118                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10119                    let selection_head = selection.head();
10120                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10121                        continue;
10122                    };
10123
10124                    let mut bracket_pair = None;
10125                    let max_lookup_length = scope
10126                        .brackets()
10127                        .map(|(pair, _)| {
10128                            pair.start
10129                                .as_str()
10130                                .chars()
10131                                .count()
10132                                .max(pair.end.as_str().chars().count())
10133                        })
10134                        .max();
10135                    if let Some(max_lookup_length) = max_lookup_length {
10136                        let next_text = snapshot
10137                            .chars_at(selection_head)
10138                            .take(max_lookup_length)
10139                            .collect::<String>();
10140                        let prev_text = snapshot
10141                            .reversed_chars_at(selection_head)
10142                            .take(max_lookup_length)
10143                            .collect::<String>();
10144
10145                        for (pair, enabled) in scope.brackets() {
10146                            if enabled
10147                                && pair.close
10148                                && prev_text.starts_with(pair.start.as_str())
10149                                && next_text.starts_with(pair.end.as_str())
10150                            {
10151                                bracket_pair = Some(pair.clone());
10152                                break;
10153                            }
10154                        }
10155                    }
10156
10157                    if let Some(pair) = bracket_pair {
10158                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10159                        let autoclose_enabled =
10160                            self.use_autoclose && snapshot_settings.use_autoclose;
10161                        if autoclose_enabled {
10162                            let start = snapshot.anchor_after(selection_head);
10163                            let end = snapshot.anchor_after(selection_head);
10164                            self.autoclose_regions.push(AutocloseRegion {
10165                                selection_id: selection.id,
10166                                range: start..end,
10167                                pair,
10168                            });
10169                        }
10170                    }
10171                }
10172            }
10173        }
10174        Ok(())
10175    }
10176
10177    pub fn move_to_next_snippet_tabstop(
10178        &mut self,
10179        window: &mut Window,
10180        cx: &mut Context<Self>,
10181    ) -> bool {
10182        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10183    }
10184
10185    pub fn move_to_prev_snippet_tabstop(
10186        &mut self,
10187        window: &mut Window,
10188        cx: &mut Context<Self>,
10189    ) -> bool {
10190        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10191    }
10192
10193    pub fn move_to_snippet_tabstop(
10194        &mut self,
10195        bias: Bias,
10196        window: &mut Window,
10197        cx: &mut Context<Self>,
10198    ) -> bool {
10199        if let Some(mut snippet) = self.snippet_stack.pop() {
10200            match bias {
10201                Bias::Left => {
10202                    if snippet.active_index > 0 {
10203                        snippet.active_index -= 1;
10204                    } else {
10205                        self.snippet_stack.push(snippet);
10206                        return false;
10207                    }
10208                }
10209                Bias::Right => {
10210                    if snippet.active_index + 1 < snippet.ranges.len() {
10211                        snippet.active_index += 1;
10212                    } else {
10213                        self.snippet_stack.push(snippet);
10214                        return false;
10215                    }
10216                }
10217            }
10218            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10219                self.change_selections(Default::default(), window, cx, |s| {
10220                    // Reverse order so that the first range is the newest created selection.
10221                    // Completions will use it and autoscroll will prioritize it.
10222                    s.select_ranges(current_ranges.iter().rev().cloned())
10223                });
10224
10225                if let Some(choices) = &snippet.choices[snippet.active_index]
10226                    && let Some(selection) = current_ranges.first()
10227                {
10228                    self.show_snippet_choices(choices, selection.clone(), cx);
10229                }
10230
10231                // If snippet state is not at the last tabstop, push it back on the stack
10232                if snippet.active_index + 1 < snippet.ranges.len() {
10233                    self.snippet_stack.push(snippet);
10234                }
10235                return true;
10236            }
10237        }
10238
10239        false
10240    }
10241
10242    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10243        self.transact(window, cx, |this, window, cx| {
10244            this.select_all(&SelectAll, window, cx);
10245            this.insert("", window, cx);
10246        });
10247    }
10248
10249    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10250        if self.read_only(cx) {
10251            return;
10252        }
10253        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10254        self.transact(window, cx, |this, window, cx| {
10255            this.select_autoclose_pair(window, cx);
10256
10257            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10258
10259            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10260            if !this.linked_edit_ranges.is_empty() {
10261                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10262                let snapshot = this.buffer.read(cx).snapshot(cx);
10263
10264                for selection in selections.iter() {
10265                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10266                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10267                    if selection_start.buffer_id != selection_end.buffer_id {
10268                        continue;
10269                    }
10270                    if let Some(ranges) =
10271                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10272                    {
10273                        for (buffer, entries) in ranges {
10274                            linked_ranges.entry(buffer).or_default().extend(entries);
10275                        }
10276                    }
10277                }
10278            }
10279
10280            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10281            for selection in &mut selections {
10282                if selection.is_empty() {
10283                    let old_head = selection.head();
10284                    let mut new_head =
10285                        movement::left(&display_map, old_head.to_display_point(&display_map))
10286                            .to_point(&display_map);
10287                    if let Some((buffer, line_buffer_range)) = display_map
10288                        .buffer_snapshot()
10289                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10290                    {
10291                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10292                        let indent_len = match indent_size.kind {
10293                            IndentKind::Space => {
10294                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10295                            }
10296                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10297                        };
10298                        if old_head.column <= indent_size.len && old_head.column > 0 {
10299                            let indent_len = indent_len.get();
10300                            new_head = cmp::min(
10301                                new_head,
10302                                MultiBufferPoint::new(
10303                                    old_head.row,
10304                                    ((old_head.column - 1) / indent_len) * indent_len,
10305                                ),
10306                            );
10307                        }
10308                    }
10309
10310                    selection.set_head(new_head, SelectionGoal::None);
10311                }
10312            }
10313
10314            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10315            this.insert("", window, cx);
10316            let empty_str: Arc<str> = Arc::from("");
10317            for (buffer, edits) in linked_ranges {
10318                let snapshot = buffer.read(cx).snapshot();
10319                use text::ToPoint as TP;
10320
10321                let edits = edits
10322                    .into_iter()
10323                    .map(|range| {
10324                        let end_point = TP::to_point(&range.end, &snapshot);
10325                        let mut start_point = TP::to_point(&range.start, &snapshot);
10326
10327                        if end_point == start_point {
10328                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10329                                .saturating_sub(1);
10330                            start_point =
10331                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10332                        };
10333
10334                        (start_point..end_point, empty_str.clone())
10335                    })
10336                    .sorted_by_key(|(range, _)| range.start)
10337                    .collect::<Vec<_>>();
10338                buffer.update(cx, |this, cx| {
10339                    this.edit(edits, None, cx);
10340                })
10341            }
10342            this.refresh_edit_prediction(true, false, window, cx);
10343            refresh_linked_ranges(this, window, cx);
10344        });
10345    }
10346
10347    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10348        if self.read_only(cx) {
10349            return;
10350        }
10351        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10352        self.transact(window, cx, |this, window, cx| {
10353            this.change_selections(Default::default(), window, cx, |s| {
10354                s.move_with(|map, selection| {
10355                    if selection.is_empty() {
10356                        let cursor = movement::right(map, selection.head());
10357                        selection.end = cursor;
10358                        selection.reversed = true;
10359                        selection.goal = SelectionGoal::None;
10360                    }
10361                })
10362            });
10363            this.insert("", window, cx);
10364            this.refresh_edit_prediction(true, false, window, cx);
10365        });
10366    }
10367
10368    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10369        if self.mode.is_single_line() {
10370            cx.propagate();
10371            return;
10372        }
10373
10374        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10375        if self.move_to_prev_snippet_tabstop(window, cx) {
10376            return;
10377        }
10378        self.outdent(&Outdent, window, cx);
10379    }
10380
10381    pub fn next_snippet_tabstop(
10382        &mut self,
10383        _: &NextSnippetTabstop,
10384        window: &mut Window,
10385        cx: &mut Context<Self>,
10386    ) {
10387        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10388            cx.propagate();
10389            return;
10390        }
10391
10392        if self.move_to_next_snippet_tabstop(window, cx) {
10393            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10394            return;
10395        }
10396        cx.propagate();
10397    }
10398
10399    pub fn previous_snippet_tabstop(
10400        &mut self,
10401        _: &PreviousSnippetTabstop,
10402        window: &mut Window,
10403        cx: &mut Context<Self>,
10404    ) {
10405        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10406            cx.propagate();
10407            return;
10408        }
10409
10410        if self.move_to_prev_snippet_tabstop(window, cx) {
10411            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10412            return;
10413        }
10414        cx.propagate();
10415    }
10416
10417    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10418        if self.mode.is_single_line() {
10419            cx.propagate();
10420            return;
10421        }
10422
10423        if self.move_to_next_snippet_tabstop(window, cx) {
10424            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10425            return;
10426        }
10427        if self.read_only(cx) {
10428            return;
10429        }
10430        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10431        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10432        let buffer = self.buffer.read(cx);
10433        let snapshot = buffer.snapshot(cx);
10434        let rows_iter = selections.iter().map(|s| s.head().row);
10435        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10436
10437        let has_some_cursor_in_whitespace = selections
10438            .iter()
10439            .filter(|selection| selection.is_empty())
10440            .any(|selection| {
10441                let cursor = selection.head();
10442                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10443                cursor.column < current_indent.len
10444            });
10445
10446        let mut edits = Vec::new();
10447        let mut prev_edited_row = 0;
10448        let mut row_delta = 0;
10449        for selection in &mut selections {
10450            if selection.start.row != prev_edited_row {
10451                row_delta = 0;
10452            }
10453            prev_edited_row = selection.end.row;
10454
10455            // If cursor is after a list prefix, make selection non-empty to trigger line indent
10456            if selection.is_empty() {
10457                let cursor = selection.head();
10458                let settings = buffer.language_settings_at(cursor, cx);
10459                if settings.indent_list_on_tab {
10460                    if let Some(language) = snapshot.language_scope_at(Point::new(cursor.row, 0)) {
10461                        if is_list_prefix_row(MultiBufferRow(cursor.row), &snapshot, &language) {
10462                            row_delta = Self::indent_selection(
10463                                buffer, &snapshot, selection, &mut edits, row_delta, cx,
10464                            );
10465                            continue;
10466                        }
10467                    }
10468                }
10469            }
10470
10471            // If the selection is non-empty, then increase the indentation of the selected lines.
10472            if !selection.is_empty() {
10473                row_delta =
10474                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10475                continue;
10476            }
10477
10478            let cursor = selection.head();
10479            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10480            if let Some(suggested_indent) =
10481                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10482            {
10483                // Don't do anything if already at suggested indent
10484                // and there is any other cursor which is not
10485                if has_some_cursor_in_whitespace
10486                    && cursor.column == current_indent.len
10487                    && current_indent.len == suggested_indent.len
10488                {
10489                    continue;
10490                }
10491
10492                // Adjust line and move cursor to suggested indent
10493                // if cursor is not at suggested indent
10494                if cursor.column < suggested_indent.len
10495                    && cursor.column <= current_indent.len
10496                    && current_indent.len <= suggested_indent.len
10497                {
10498                    selection.start = Point::new(cursor.row, suggested_indent.len);
10499                    selection.end = selection.start;
10500                    if row_delta == 0 {
10501                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10502                            cursor.row,
10503                            current_indent,
10504                            suggested_indent,
10505                        ));
10506                        row_delta = suggested_indent.len - current_indent.len;
10507                    }
10508                    continue;
10509                }
10510
10511                // If current indent is more than suggested indent
10512                // only move cursor to current indent and skip indent
10513                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10514                    selection.start = Point::new(cursor.row, current_indent.len);
10515                    selection.end = selection.start;
10516                    continue;
10517                }
10518            }
10519
10520            // Otherwise, insert a hard or soft tab.
10521            let settings = buffer.language_settings_at(cursor, cx);
10522            let tab_size = if settings.hard_tabs {
10523                IndentSize::tab()
10524            } else {
10525                let tab_size = settings.tab_size.get();
10526                let indent_remainder = snapshot
10527                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10528                    .flat_map(str::chars)
10529                    .fold(row_delta % tab_size, |counter: u32, c| {
10530                        if c == '\t' {
10531                            0
10532                        } else {
10533                            (counter + 1) % tab_size
10534                        }
10535                    });
10536
10537                let chars_to_next_tab_stop = tab_size - indent_remainder;
10538                IndentSize::spaces(chars_to_next_tab_stop)
10539            };
10540            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10541            selection.end = selection.start;
10542            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10543            row_delta += tab_size.len;
10544        }
10545
10546        self.transact(window, cx, |this, window, cx| {
10547            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10548            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10549            this.refresh_edit_prediction(true, false, window, cx);
10550        });
10551    }
10552
10553    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10554        if self.read_only(cx) {
10555            return;
10556        }
10557        if self.mode.is_single_line() {
10558            cx.propagate();
10559            return;
10560        }
10561
10562        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10563        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10564        let mut prev_edited_row = 0;
10565        let mut row_delta = 0;
10566        let mut edits = Vec::new();
10567        let buffer = self.buffer.read(cx);
10568        let snapshot = buffer.snapshot(cx);
10569        for selection in &mut selections {
10570            if selection.start.row != prev_edited_row {
10571                row_delta = 0;
10572            }
10573            prev_edited_row = selection.end.row;
10574
10575            row_delta =
10576                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10577        }
10578
10579        self.transact(window, cx, |this, window, cx| {
10580            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10581            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10582        });
10583    }
10584
10585    fn indent_selection(
10586        buffer: &MultiBuffer,
10587        snapshot: &MultiBufferSnapshot,
10588        selection: &mut Selection<Point>,
10589        edits: &mut Vec<(Range<Point>, String)>,
10590        delta_for_start_row: u32,
10591        cx: &App,
10592    ) -> u32 {
10593        let settings = buffer.language_settings_at(selection.start, cx);
10594        let tab_size = settings.tab_size.get();
10595        let indent_kind = if settings.hard_tabs {
10596            IndentKind::Tab
10597        } else {
10598            IndentKind::Space
10599        };
10600        let mut start_row = selection.start.row;
10601        let mut end_row = selection.end.row + 1;
10602
10603        // If a selection ends at the beginning of a line, don't indent
10604        // that last line.
10605        if selection.end.column == 0 && selection.end.row > selection.start.row {
10606            end_row -= 1;
10607        }
10608
10609        // Avoid re-indenting a row that has already been indented by a
10610        // previous selection, but still update this selection's column
10611        // to reflect that indentation.
10612        if delta_for_start_row > 0 {
10613            start_row += 1;
10614            selection.start.column += delta_for_start_row;
10615            if selection.end.row == selection.start.row {
10616                selection.end.column += delta_for_start_row;
10617            }
10618        }
10619
10620        let mut delta_for_end_row = 0;
10621        let has_multiple_rows = start_row + 1 != end_row;
10622        for row in start_row..end_row {
10623            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10624            let indent_delta = match (current_indent.kind, indent_kind) {
10625                (IndentKind::Space, IndentKind::Space) => {
10626                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10627                    IndentSize::spaces(columns_to_next_tab_stop)
10628                }
10629                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10630                (_, IndentKind::Tab) => IndentSize::tab(),
10631            };
10632
10633            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10634                0
10635            } else {
10636                selection.start.column
10637            };
10638            let row_start = Point::new(row, start);
10639            edits.push((
10640                row_start..row_start,
10641                indent_delta.chars().collect::<String>(),
10642            ));
10643
10644            // Update this selection's endpoints to reflect the indentation.
10645            if row == selection.start.row {
10646                selection.start.column += indent_delta.len;
10647            }
10648            if row == selection.end.row {
10649                selection.end.column += indent_delta.len;
10650                delta_for_end_row = indent_delta.len;
10651            }
10652        }
10653
10654        if selection.start.row == selection.end.row {
10655            delta_for_start_row + delta_for_end_row
10656        } else {
10657            delta_for_end_row
10658        }
10659    }
10660
10661    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10662        if self.read_only(cx) {
10663            return;
10664        }
10665        if self.mode.is_single_line() {
10666            cx.propagate();
10667            return;
10668        }
10669
10670        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10671        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10672        let selections = self.selections.all::<Point>(&display_map);
10673        let mut deletion_ranges = Vec::new();
10674        let mut last_outdent = None;
10675        {
10676            let buffer = self.buffer.read(cx);
10677            let snapshot = buffer.snapshot(cx);
10678            for selection in &selections {
10679                let settings = buffer.language_settings_at(selection.start, cx);
10680                let tab_size = settings.tab_size.get();
10681                let mut rows = selection.spanned_rows(false, &display_map);
10682
10683                // Avoid re-outdenting a row that has already been outdented by a
10684                // previous selection.
10685                if let Some(last_row) = last_outdent
10686                    && last_row == rows.start
10687                {
10688                    rows.start = rows.start.next_row();
10689                }
10690                let has_multiple_rows = rows.len() > 1;
10691                for row in rows.iter_rows() {
10692                    let indent_size = snapshot.indent_size_for_line(row);
10693                    if indent_size.len > 0 {
10694                        let deletion_len = match indent_size.kind {
10695                            IndentKind::Space => {
10696                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10697                                if columns_to_prev_tab_stop == 0 {
10698                                    tab_size
10699                                } else {
10700                                    columns_to_prev_tab_stop
10701                                }
10702                            }
10703                            IndentKind::Tab => 1,
10704                        };
10705                        let start = if has_multiple_rows
10706                            || deletion_len > selection.start.column
10707                            || indent_size.len < selection.start.column
10708                        {
10709                            0
10710                        } else {
10711                            selection.start.column - deletion_len
10712                        };
10713                        deletion_ranges.push(
10714                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10715                        );
10716                        last_outdent = Some(row);
10717                    }
10718                }
10719            }
10720        }
10721
10722        self.transact(window, cx, |this, window, cx| {
10723            this.buffer.update(cx, |buffer, cx| {
10724                let empty_str: Arc<str> = Arc::default();
10725                buffer.edit(
10726                    deletion_ranges
10727                        .into_iter()
10728                        .map(|range| (range, empty_str.clone())),
10729                    None,
10730                    cx,
10731                );
10732            });
10733            let selections = this
10734                .selections
10735                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10736            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10737        });
10738    }
10739
10740    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10741        if self.read_only(cx) {
10742            return;
10743        }
10744        if self.mode.is_single_line() {
10745            cx.propagate();
10746            return;
10747        }
10748
10749        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10750        let selections = self
10751            .selections
10752            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10753            .into_iter()
10754            .map(|s| s.range());
10755
10756        self.transact(window, cx, |this, window, cx| {
10757            this.buffer.update(cx, |buffer, cx| {
10758                buffer.autoindent_ranges(selections, cx);
10759            });
10760            let selections = this
10761                .selections
10762                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10763            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10764        });
10765    }
10766
10767    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10768        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10769        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10770        let selections = self.selections.all::<Point>(&display_map);
10771
10772        let mut new_cursors = Vec::new();
10773        let mut edit_ranges = Vec::new();
10774        let mut selections = selections.iter().peekable();
10775        while let Some(selection) = selections.next() {
10776            let mut rows = selection.spanned_rows(false, &display_map);
10777
10778            // Accumulate contiguous regions of rows that we want to delete.
10779            while let Some(next_selection) = selections.peek() {
10780                let next_rows = next_selection.spanned_rows(false, &display_map);
10781                if next_rows.start <= rows.end {
10782                    rows.end = next_rows.end;
10783                    selections.next().unwrap();
10784                } else {
10785                    break;
10786                }
10787            }
10788
10789            let buffer = display_map.buffer_snapshot();
10790            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10791            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10792                // If there's a line after the range, delete the \n from the end of the row range
10793                (
10794                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10795                    rows.end,
10796                )
10797            } else {
10798                // If there isn't a line after the range, delete the \n from the line before the
10799                // start of the row range
10800                edit_start = edit_start.saturating_sub_usize(1);
10801                (buffer.len(), rows.start.previous_row())
10802            };
10803
10804            let text_layout_details = self.text_layout_details(window);
10805            let x = display_map.x_for_display_point(
10806                selection.head().to_display_point(&display_map),
10807                &text_layout_details,
10808            );
10809            let row = Point::new(target_row.0, 0)
10810                .to_display_point(&display_map)
10811                .row();
10812            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10813
10814            new_cursors.push((
10815                selection.id,
10816                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10817                SelectionGoal::None,
10818            ));
10819            edit_ranges.push(edit_start..edit_end);
10820        }
10821
10822        self.transact(window, cx, |this, window, cx| {
10823            let buffer = this.buffer.update(cx, |buffer, cx| {
10824                let empty_str: Arc<str> = Arc::default();
10825                buffer.edit(
10826                    edit_ranges
10827                        .into_iter()
10828                        .map(|range| (range, empty_str.clone())),
10829                    None,
10830                    cx,
10831                );
10832                buffer.snapshot(cx)
10833            });
10834            let new_selections = new_cursors
10835                .into_iter()
10836                .map(|(id, cursor, goal)| {
10837                    let cursor = cursor.to_point(&buffer);
10838                    Selection {
10839                        id,
10840                        start: cursor,
10841                        end: cursor,
10842                        reversed: false,
10843                        goal,
10844                    }
10845                })
10846                .collect();
10847
10848            this.change_selections(Default::default(), window, cx, |s| {
10849                s.select(new_selections);
10850            });
10851        });
10852    }
10853
10854    pub fn join_lines_impl(
10855        &mut self,
10856        insert_whitespace: bool,
10857        window: &mut Window,
10858        cx: &mut Context<Self>,
10859    ) {
10860        if self.read_only(cx) {
10861            return;
10862        }
10863        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10864        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10865            let start = MultiBufferRow(selection.start.row);
10866            // Treat single line selections as if they include the next line. Otherwise this action
10867            // would do nothing for single line selections individual cursors.
10868            let end = if selection.start.row == selection.end.row {
10869                MultiBufferRow(selection.start.row + 1)
10870            } else {
10871                MultiBufferRow(selection.end.row)
10872            };
10873
10874            if let Some(last_row_range) = row_ranges.last_mut()
10875                && start <= last_row_range.end
10876            {
10877                last_row_range.end = end;
10878                continue;
10879            }
10880            row_ranges.push(start..end);
10881        }
10882
10883        let snapshot = self.buffer.read(cx).snapshot(cx);
10884        let mut cursor_positions = Vec::new();
10885        for row_range in &row_ranges {
10886            let anchor = snapshot.anchor_before(Point::new(
10887                row_range.end.previous_row().0,
10888                snapshot.line_len(row_range.end.previous_row()),
10889            ));
10890            cursor_positions.push(anchor..anchor);
10891        }
10892
10893        self.transact(window, cx, |this, window, cx| {
10894            for row_range in row_ranges.into_iter().rev() {
10895                for row in row_range.iter_rows().rev() {
10896                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10897                    let next_line_row = row.next_row();
10898                    let indent = snapshot.indent_size_for_line(next_line_row);
10899                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10900
10901                    let replace =
10902                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10903                            " "
10904                        } else {
10905                            ""
10906                        };
10907
10908                    this.buffer.update(cx, |buffer, cx| {
10909                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10910                    });
10911                }
10912            }
10913
10914            this.change_selections(Default::default(), window, cx, |s| {
10915                s.select_anchor_ranges(cursor_positions)
10916            });
10917        });
10918    }
10919
10920    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10921        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10922        self.join_lines_impl(true, window, cx);
10923    }
10924
10925    pub fn sort_lines_case_sensitive(
10926        &mut self,
10927        _: &SortLinesCaseSensitive,
10928        window: &mut Window,
10929        cx: &mut Context<Self>,
10930    ) {
10931        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10932    }
10933
10934    pub fn sort_lines_by_length(
10935        &mut self,
10936        _: &SortLinesByLength,
10937        window: &mut Window,
10938        cx: &mut Context<Self>,
10939    ) {
10940        self.manipulate_immutable_lines(window, cx, |lines| {
10941            lines.sort_by_key(|&line| line.chars().count())
10942        })
10943    }
10944
10945    pub fn sort_lines_case_insensitive(
10946        &mut self,
10947        _: &SortLinesCaseInsensitive,
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.to_lowercase())
10953        })
10954    }
10955
10956    pub fn unique_lines_case_insensitive(
10957        &mut self,
10958        _: &UniqueLinesCaseInsensitive,
10959        window: &mut Window,
10960        cx: &mut Context<Self>,
10961    ) {
10962        self.manipulate_immutable_lines(window, cx, |lines| {
10963            let mut seen = HashSet::default();
10964            lines.retain(|line| seen.insert(line.to_lowercase()));
10965        })
10966    }
10967
10968    pub fn unique_lines_case_sensitive(
10969        &mut self,
10970        _: &UniqueLinesCaseSensitive,
10971        window: &mut Window,
10972        cx: &mut Context<Self>,
10973    ) {
10974        self.manipulate_immutable_lines(window, cx, |lines| {
10975            let mut seen = HashSet::default();
10976            lines.retain(|line| seen.insert(*line));
10977        })
10978    }
10979
10980    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10981        let snapshot = self.buffer.read(cx).snapshot(cx);
10982        for selection in self.selections.disjoint_anchors_arc().iter() {
10983            if snapshot
10984                .language_at(selection.start)
10985                .and_then(|lang| lang.config().wrap_characters.as_ref())
10986                .is_some()
10987            {
10988                return true;
10989            }
10990        }
10991        false
10992    }
10993
10994    fn wrap_selections_in_tag(
10995        &mut self,
10996        _: &WrapSelectionsInTag,
10997        window: &mut Window,
10998        cx: &mut Context<Self>,
10999    ) {
11000        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11001
11002        let snapshot = self.buffer.read(cx).snapshot(cx);
11003
11004        let mut edits = Vec::new();
11005        let mut boundaries = Vec::new();
11006
11007        for selection in self
11008            .selections
11009            .all_adjusted(&self.display_snapshot(cx))
11010            .iter()
11011        {
11012            let Some(wrap_config) = snapshot
11013                .language_at(selection.start)
11014                .and_then(|lang| lang.config().wrap_characters.clone())
11015            else {
11016                continue;
11017            };
11018
11019            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11020            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11021
11022            let start_before = snapshot.anchor_before(selection.start);
11023            let end_after = snapshot.anchor_after(selection.end);
11024
11025            edits.push((start_before..start_before, open_tag));
11026            edits.push((end_after..end_after, close_tag));
11027
11028            boundaries.push((
11029                start_before,
11030                end_after,
11031                wrap_config.start_prefix.len(),
11032                wrap_config.end_suffix.len(),
11033            ));
11034        }
11035
11036        if edits.is_empty() {
11037            return;
11038        }
11039
11040        self.transact(window, cx, |this, window, cx| {
11041            let buffer = this.buffer.update(cx, |buffer, cx| {
11042                buffer.edit(edits, None, cx);
11043                buffer.snapshot(cx)
11044            });
11045
11046            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11047            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11048                boundaries.into_iter()
11049            {
11050                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11051                let close_offset = end_after
11052                    .to_offset(&buffer)
11053                    .saturating_sub_usize(end_suffix_len);
11054                new_selections.push(open_offset..open_offset);
11055                new_selections.push(close_offset..close_offset);
11056            }
11057
11058            this.change_selections(Default::default(), window, cx, |s| {
11059                s.select_ranges(new_selections);
11060            });
11061
11062            this.request_autoscroll(Autoscroll::fit(), cx);
11063        });
11064    }
11065
11066    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11067        let Some(project) = self.project.clone() else {
11068            return;
11069        };
11070        self.reload(project, window, cx)
11071            .detach_and_notify_err(window, cx);
11072    }
11073
11074    pub fn restore_file(
11075        &mut self,
11076        _: &::git::RestoreFile,
11077        window: &mut Window,
11078        cx: &mut Context<Self>,
11079    ) {
11080        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11081        let mut buffer_ids = HashSet::default();
11082        let snapshot = self.buffer().read(cx).snapshot(cx);
11083        for selection in self
11084            .selections
11085            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11086        {
11087            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11088        }
11089
11090        let buffer = self.buffer().read(cx);
11091        let ranges = buffer_ids
11092            .into_iter()
11093            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11094            .collect::<Vec<_>>();
11095
11096        self.restore_hunks_in_ranges(ranges, window, cx);
11097    }
11098
11099    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11100        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11101        let selections = self
11102            .selections
11103            .all(&self.display_snapshot(cx))
11104            .into_iter()
11105            .map(|s| s.range())
11106            .collect();
11107        self.restore_hunks_in_ranges(selections, window, cx);
11108    }
11109
11110    pub fn restore_hunks_in_ranges(
11111        &mut self,
11112        ranges: Vec<Range<Point>>,
11113        window: &mut Window,
11114        cx: &mut Context<Editor>,
11115    ) {
11116        let mut revert_changes = HashMap::default();
11117        let chunk_by = self
11118            .snapshot(window, cx)
11119            .hunks_for_ranges(ranges)
11120            .into_iter()
11121            .chunk_by(|hunk| hunk.buffer_id);
11122        for (buffer_id, hunks) in &chunk_by {
11123            let hunks = hunks.collect::<Vec<_>>();
11124            for hunk in &hunks {
11125                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11126            }
11127            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11128        }
11129        drop(chunk_by);
11130        if !revert_changes.is_empty() {
11131            self.transact(window, cx, |editor, window, cx| {
11132                editor.restore(revert_changes, window, cx);
11133            });
11134        }
11135    }
11136
11137    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11138        if let Some(status) = self
11139            .addons
11140            .iter()
11141            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11142        {
11143            return Some(status);
11144        }
11145        self.project
11146            .as_ref()?
11147            .read(cx)
11148            .status_for_buffer_id(buffer_id, cx)
11149    }
11150
11151    pub fn open_active_item_in_terminal(
11152        &mut self,
11153        _: &OpenInTerminal,
11154        window: &mut Window,
11155        cx: &mut Context<Self>,
11156    ) {
11157        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11158            let project_path = buffer.read(cx).project_path(cx)?;
11159            let project = self.project()?.read(cx);
11160            let entry = project.entry_for_path(&project_path, cx)?;
11161            let parent = match &entry.canonical_path {
11162                Some(canonical_path) => canonical_path.to_path_buf(),
11163                None => project.absolute_path(&project_path, cx)?,
11164            }
11165            .parent()?
11166            .to_path_buf();
11167            Some(parent)
11168        }) {
11169            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11170        }
11171    }
11172
11173    fn set_breakpoint_context_menu(
11174        &mut self,
11175        display_row: DisplayRow,
11176        position: Option<Anchor>,
11177        clicked_point: gpui::Point<Pixels>,
11178        window: &mut Window,
11179        cx: &mut Context<Self>,
11180    ) {
11181        let source = self
11182            .buffer
11183            .read(cx)
11184            .snapshot(cx)
11185            .anchor_before(Point::new(display_row.0, 0u32));
11186
11187        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11188
11189        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11190            self,
11191            source,
11192            clicked_point,
11193            context_menu,
11194            window,
11195            cx,
11196        );
11197    }
11198
11199    fn add_edit_breakpoint_block(
11200        &mut self,
11201        anchor: Anchor,
11202        breakpoint: &Breakpoint,
11203        edit_action: BreakpointPromptEditAction,
11204        window: &mut Window,
11205        cx: &mut Context<Self>,
11206    ) {
11207        let weak_editor = cx.weak_entity();
11208        let bp_prompt = cx.new(|cx| {
11209            BreakpointPromptEditor::new(
11210                weak_editor,
11211                anchor,
11212                breakpoint.clone(),
11213                edit_action,
11214                window,
11215                cx,
11216            )
11217        });
11218
11219        let height = bp_prompt.update(cx, |this, cx| {
11220            this.prompt
11221                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11222        });
11223        let cloned_prompt = bp_prompt.clone();
11224        let blocks = vec![BlockProperties {
11225            style: BlockStyle::Sticky,
11226            placement: BlockPlacement::Above(anchor),
11227            height: Some(height),
11228            render: Arc::new(move |cx| {
11229                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11230                cloned_prompt.clone().into_any_element()
11231            }),
11232            priority: 0,
11233        }];
11234
11235        let focus_handle = bp_prompt.focus_handle(cx);
11236        window.focus(&focus_handle, cx);
11237
11238        let block_ids = self.insert_blocks(blocks, None, cx);
11239        bp_prompt.update(cx, |prompt, _| {
11240            prompt.add_block_ids(block_ids);
11241        });
11242    }
11243
11244    pub(crate) fn breakpoint_at_row(
11245        &self,
11246        row: u32,
11247        window: &mut Window,
11248        cx: &mut Context<Self>,
11249    ) -> Option<(Anchor, Breakpoint)> {
11250        let snapshot = self.snapshot(window, cx);
11251        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11252
11253        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11254    }
11255
11256    pub(crate) fn breakpoint_at_anchor(
11257        &self,
11258        breakpoint_position: Anchor,
11259        snapshot: &EditorSnapshot,
11260        cx: &mut Context<Self>,
11261    ) -> Option<(Anchor, Breakpoint)> {
11262        let buffer = self
11263            .buffer
11264            .read(cx)
11265            .buffer_for_anchor(breakpoint_position, cx)?;
11266
11267        let enclosing_excerpt = breakpoint_position.excerpt_id;
11268        let buffer_snapshot = buffer.read(cx).snapshot();
11269
11270        let row = buffer_snapshot
11271            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11272            .row;
11273
11274        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11275        let anchor_end = snapshot
11276            .buffer_snapshot()
11277            .anchor_after(Point::new(row, line_len));
11278
11279        self.breakpoint_store
11280            .as_ref()?
11281            .read_with(cx, |breakpoint_store, cx| {
11282                breakpoint_store
11283                    .breakpoints(
11284                        &buffer,
11285                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11286                        &buffer_snapshot,
11287                        cx,
11288                    )
11289                    .next()
11290                    .and_then(|(bp, _)| {
11291                        let breakpoint_row = buffer_snapshot
11292                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11293                            .row;
11294
11295                        if breakpoint_row == row {
11296                            snapshot
11297                                .buffer_snapshot()
11298                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11299                                .map(|position| (position, bp.bp.clone()))
11300                        } else {
11301                            None
11302                        }
11303                    })
11304            })
11305    }
11306
11307    pub fn edit_log_breakpoint(
11308        &mut self,
11309        _: &EditLogBreakpoint,
11310        window: &mut Window,
11311        cx: &mut Context<Self>,
11312    ) {
11313        if self.breakpoint_store.is_none() {
11314            return;
11315        }
11316
11317        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11318            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11319                message: None,
11320                state: BreakpointState::Enabled,
11321                condition: None,
11322                hit_condition: None,
11323            });
11324
11325            self.add_edit_breakpoint_block(
11326                anchor,
11327                &breakpoint,
11328                BreakpointPromptEditAction::Log,
11329                window,
11330                cx,
11331            );
11332        }
11333    }
11334
11335    fn breakpoints_at_cursors(
11336        &self,
11337        window: &mut Window,
11338        cx: &mut Context<Self>,
11339    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11340        let snapshot = self.snapshot(window, cx);
11341        let cursors = self
11342            .selections
11343            .disjoint_anchors_arc()
11344            .iter()
11345            .map(|selection| {
11346                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11347
11348                let breakpoint_position = self
11349                    .breakpoint_at_row(cursor_position.row, window, cx)
11350                    .map(|bp| bp.0)
11351                    .unwrap_or_else(|| {
11352                        snapshot
11353                            .display_snapshot
11354                            .buffer_snapshot()
11355                            .anchor_after(Point::new(cursor_position.row, 0))
11356                    });
11357
11358                let breakpoint = self
11359                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11360                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11361
11362                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11363            })
11364            // 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.
11365            .collect::<HashMap<Anchor, _>>();
11366
11367        cursors.into_iter().collect()
11368    }
11369
11370    pub fn enable_breakpoint(
11371        &mut self,
11372        _: &crate::actions::EnableBreakpoint,
11373        window: &mut Window,
11374        cx: &mut Context<Self>,
11375    ) {
11376        if self.breakpoint_store.is_none() {
11377            return;
11378        }
11379
11380        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11381            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11382                continue;
11383            };
11384            self.edit_breakpoint_at_anchor(
11385                anchor,
11386                breakpoint,
11387                BreakpointEditAction::InvertState,
11388                cx,
11389            );
11390        }
11391    }
11392
11393    pub fn disable_breakpoint(
11394        &mut self,
11395        _: &crate::actions::DisableBreakpoint,
11396        window: &mut Window,
11397        cx: &mut Context<Self>,
11398    ) {
11399        if self.breakpoint_store.is_none() {
11400            return;
11401        }
11402
11403        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11404            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11405                continue;
11406            };
11407            self.edit_breakpoint_at_anchor(
11408                anchor,
11409                breakpoint,
11410                BreakpointEditAction::InvertState,
11411                cx,
11412            );
11413        }
11414    }
11415
11416    pub fn toggle_breakpoint(
11417        &mut self,
11418        _: &crate::actions::ToggleBreakpoint,
11419        window: &mut Window,
11420        cx: &mut Context<Self>,
11421    ) {
11422        if self.breakpoint_store.is_none() {
11423            return;
11424        }
11425
11426        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11427            if let Some(breakpoint) = breakpoint {
11428                self.edit_breakpoint_at_anchor(
11429                    anchor,
11430                    breakpoint,
11431                    BreakpointEditAction::Toggle,
11432                    cx,
11433                );
11434            } else {
11435                self.edit_breakpoint_at_anchor(
11436                    anchor,
11437                    Breakpoint::new_standard(),
11438                    BreakpointEditAction::Toggle,
11439                    cx,
11440                );
11441            }
11442        }
11443    }
11444
11445    pub fn edit_breakpoint_at_anchor(
11446        &mut self,
11447        breakpoint_position: Anchor,
11448        breakpoint: Breakpoint,
11449        edit_action: BreakpointEditAction,
11450        cx: &mut Context<Self>,
11451    ) {
11452        let Some(breakpoint_store) = &self.breakpoint_store else {
11453            return;
11454        };
11455
11456        let Some(buffer) = self
11457            .buffer
11458            .read(cx)
11459            .buffer_for_anchor(breakpoint_position, cx)
11460        else {
11461            return;
11462        };
11463
11464        breakpoint_store.update(cx, |breakpoint_store, cx| {
11465            breakpoint_store.toggle_breakpoint(
11466                buffer,
11467                BreakpointWithPosition {
11468                    position: breakpoint_position.text_anchor,
11469                    bp: breakpoint,
11470                },
11471                edit_action,
11472                cx,
11473            );
11474        });
11475
11476        cx.notify();
11477    }
11478
11479    #[cfg(any(test, feature = "test-support"))]
11480    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11481        self.breakpoint_store.clone()
11482    }
11483
11484    pub fn prepare_restore_change(
11485        &self,
11486        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11487        hunk: &MultiBufferDiffHunk,
11488        cx: &mut App,
11489    ) -> Option<()> {
11490        if hunk.is_created_file() {
11491            return None;
11492        }
11493        let buffer = self.buffer.read(cx);
11494        let diff = buffer.diff_for(hunk.buffer_id)?;
11495        let buffer = buffer.buffer(hunk.buffer_id)?;
11496        let buffer = buffer.read(cx);
11497        let original_text = diff
11498            .read(cx)
11499            .base_text()
11500            .as_rope()
11501            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11502        let buffer_snapshot = buffer.snapshot();
11503        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11504        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11505            probe
11506                .0
11507                .start
11508                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11509                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11510        }) {
11511            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11512            Some(())
11513        } else {
11514            None
11515        }
11516    }
11517
11518    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11519        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11520    }
11521
11522    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11523        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11524    }
11525
11526    pub fn rotate_selections_forward(
11527        &mut self,
11528        _: &RotateSelectionsForward,
11529        window: &mut Window,
11530        cx: &mut Context<Self>,
11531    ) {
11532        self.rotate_selections(window, cx, false)
11533    }
11534
11535    pub fn rotate_selections_backward(
11536        &mut self,
11537        _: &RotateSelectionsBackward,
11538        window: &mut Window,
11539        cx: &mut Context<Self>,
11540    ) {
11541        self.rotate_selections(window, cx, true)
11542    }
11543
11544    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11545        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11546        let display_snapshot = self.display_snapshot(cx);
11547        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11548
11549        if selections.len() < 2 {
11550            return;
11551        }
11552
11553        let (edits, new_selections) = {
11554            let buffer = self.buffer.read(cx).read(cx);
11555            let has_selections = selections.iter().any(|s| !s.is_empty());
11556            if has_selections {
11557                let mut selected_texts: Vec<String> = selections
11558                    .iter()
11559                    .map(|selection| {
11560                        buffer
11561                            .text_for_range(selection.start..selection.end)
11562                            .collect()
11563                    })
11564                    .collect();
11565
11566                if reverse {
11567                    selected_texts.rotate_left(1);
11568                } else {
11569                    selected_texts.rotate_right(1);
11570                }
11571
11572                let mut offset_delta: i64 = 0;
11573                let mut new_selections = Vec::new();
11574                let edits: Vec<_> = selections
11575                    .iter()
11576                    .zip(selected_texts.iter())
11577                    .map(|(selection, new_text)| {
11578                        let old_len = (selection.end.0 - selection.start.0) as i64;
11579                        let new_len = new_text.len() as i64;
11580                        let adjusted_start =
11581                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11582                        let adjusted_end =
11583                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11584
11585                        new_selections.push(Selection {
11586                            id: selection.id,
11587                            start: adjusted_start,
11588                            end: adjusted_end,
11589                            reversed: selection.reversed,
11590                            goal: selection.goal,
11591                        });
11592
11593                        offset_delta += new_len - old_len;
11594                        (selection.start..selection.end, new_text.clone())
11595                    })
11596                    .collect();
11597                (edits, new_selections)
11598            } else {
11599                let mut all_rows: Vec<u32> = selections
11600                    .iter()
11601                    .map(|selection| buffer.offset_to_point(selection.start).row)
11602                    .collect();
11603                all_rows.sort_unstable();
11604                all_rows.dedup();
11605
11606                if all_rows.len() < 2 {
11607                    return;
11608                }
11609
11610                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11611                    .iter()
11612                    .map(|&row| {
11613                        let start = Point::new(row, 0);
11614                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11615                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11616                    })
11617                    .collect();
11618
11619                let mut line_texts: Vec<String> = line_ranges
11620                    .iter()
11621                    .map(|range| buffer.text_for_range(range.clone()).collect())
11622                    .collect();
11623
11624                if reverse {
11625                    line_texts.rotate_left(1);
11626                } else {
11627                    line_texts.rotate_right(1);
11628                }
11629
11630                let edits = line_ranges
11631                    .iter()
11632                    .zip(line_texts.iter())
11633                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11634                    .collect();
11635
11636                let num_rows = all_rows.len();
11637                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11638                    .iter()
11639                    .enumerate()
11640                    .map(|(i, &row)| (row, i))
11641                    .collect();
11642
11643                // Compute new line start offsets after rotation (handles CRLF)
11644                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11645                let first_line_start = line_ranges[0].start.0;
11646                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11647                for text in line_texts.iter().take(num_rows - 1) {
11648                    let prev_start = *new_line_starts.last().unwrap();
11649                    new_line_starts.push(prev_start + text.len() + newline_len);
11650                }
11651
11652                let new_selections = selections
11653                    .iter()
11654                    .map(|selection| {
11655                        let point = buffer.offset_to_point(selection.start);
11656                        let old_index = row_to_index[&point.row];
11657                        let new_index = if reverse {
11658                            (old_index + num_rows - 1) % num_rows
11659                        } else {
11660                            (old_index + 1) % num_rows
11661                        };
11662                        let new_offset =
11663                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11664                        Selection {
11665                            id: selection.id,
11666                            start: new_offset,
11667                            end: new_offset,
11668                            reversed: selection.reversed,
11669                            goal: selection.goal,
11670                        }
11671                    })
11672                    .collect();
11673
11674                (edits, new_selections)
11675            }
11676        };
11677
11678        self.transact(window, cx, |this, window, cx| {
11679            this.buffer.update(cx, |buffer, cx| {
11680                buffer.edit(edits, None, cx);
11681            });
11682            this.change_selections(Default::default(), window, cx, |s| {
11683                s.select(new_selections);
11684            });
11685        });
11686    }
11687
11688    fn manipulate_lines<M>(
11689        &mut self,
11690        window: &mut Window,
11691        cx: &mut Context<Self>,
11692        mut manipulate: M,
11693    ) where
11694        M: FnMut(&str) -> LineManipulationResult,
11695    {
11696        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11697
11698        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11699        let buffer = self.buffer.read(cx).snapshot(cx);
11700
11701        let mut edits = Vec::new();
11702
11703        let selections = self.selections.all::<Point>(&display_map);
11704        let mut selections = selections.iter().peekable();
11705        let mut contiguous_row_selections = Vec::new();
11706        let mut new_selections = Vec::new();
11707        let mut added_lines = 0;
11708        let mut removed_lines = 0;
11709
11710        while let Some(selection) = selections.next() {
11711            let (start_row, end_row) = consume_contiguous_rows(
11712                &mut contiguous_row_selections,
11713                selection,
11714                &display_map,
11715                &mut selections,
11716            );
11717
11718            let start_point = Point::new(start_row.0, 0);
11719            let end_point = Point::new(
11720                end_row.previous_row().0,
11721                buffer.line_len(end_row.previous_row()),
11722            );
11723            let text = buffer
11724                .text_for_range(start_point..end_point)
11725                .collect::<String>();
11726
11727            let LineManipulationResult {
11728                new_text,
11729                line_count_before,
11730                line_count_after,
11731            } = manipulate(&text);
11732
11733            edits.push((start_point..end_point, new_text));
11734
11735            // Selections must change based on added and removed line count
11736            let start_row =
11737                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11738            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11739            new_selections.push(Selection {
11740                id: selection.id,
11741                start: start_row,
11742                end: end_row,
11743                goal: SelectionGoal::None,
11744                reversed: selection.reversed,
11745            });
11746
11747            if line_count_after > line_count_before {
11748                added_lines += line_count_after - line_count_before;
11749            } else if line_count_before > line_count_after {
11750                removed_lines += line_count_before - line_count_after;
11751            }
11752        }
11753
11754        self.transact(window, cx, |this, window, cx| {
11755            let buffer = this.buffer.update(cx, |buffer, cx| {
11756                buffer.edit(edits, None, cx);
11757                buffer.snapshot(cx)
11758            });
11759
11760            // Recalculate offsets on newly edited buffer
11761            let new_selections = new_selections
11762                .iter()
11763                .map(|s| {
11764                    let start_point = Point::new(s.start.0, 0);
11765                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11766                    Selection {
11767                        id: s.id,
11768                        start: buffer.point_to_offset(start_point),
11769                        end: buffer.point_to_offset(end_point),
11770                        goal: s.goal,
11771                        reversed: s.reversed,
11772                    }
11773                })
11774                .collect();
11775
11776            this.change_selections(Default::default(), window, cx, |s| {
11777                s.select(new_selections);
11778            });
11779
11780            this.request_autoscroll(Autoscroll::fit(), cx);
11781        });
11782    }
11783
11784    fn manipulate_immutable_lines<Fn>(
11785        &mut self,
11786        window: &mut Window,
11787        cx: &mut Context<Self>,
11788        mut callback: Fn,
11789    ) where
11790        Fn: FnMut(&mut Vec<&str>),
11791    {
11792        self.manipulate_lines(window, cx, |text| {
11793            let mut lines: Vec<&str> = text.split('\n').collect();
11794            let line_count_before = lines.len();
11795
11796            callback(&mut lines);
11797
11798            LineManipulationResult {
11799                new_text: lines.join("\n"),
11800                line_count_before,
11801                line_count_after: lines.len(),
11802            }
11803        });
11804    }
11805
11806    fn manipulate_mutable_lines<Fn>(
11807        &mut self,
11808        window: &mut Window,
11809        cx: &mut Context<Self>,
11810        mut callback: Fn,
11811    ) where
11812        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11813    {
11814        self.manipulate_lines(window, cx, |text| {
11815            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11816            let line_count_before = lines.len();
11817
11818            callback(&mut lines);
11819
11820            LineManipulationResult {
11821                new_text: lines.join("\n"),
11822                line_count_before,
11823                line_count_after: lines.len(),
11824            }
11825        });
11826    }
11827
11828    pub fn convert_indentation_to_spaces(
11829        &mut self,
11830        _: &ConvertIndentationToSpaces,
11831        window: &mut Window,
11832        cx: &mut Context<Self>,
11833    ) {
11834        let settings = self.buffer.read(cx).language_settings(cx);
11835        let tab_size = settings.tab_size.get() as usize;
11836
11837        self.manipulate_mutable_lines(window, cx, |lines| {
11838            // Allocates a reasonably sized scratch buffer once for the whole loop
11839            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11840            // Avoids recomputing spaces that could be inserted many times
11841            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11842                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11843                .collect();
11844
11845            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11846                let mut chars = line.as_ref().chars();
11847                let mut col = 0;
11848                let mut changed = false;
11849
11850                for ch in chars.by_ref() {
11851                    match ch {
11852                        ' ' => {
11853                            reindented_line.push(' ');
11854                            col += 1;
11855                        }
11856                        '\t' => {
11857                            // \t are converted to spaces depending on the current column
11858                            let spaces_len = tab_size - (col % tab_size);
11859                            reindented_line.extend(&space_cache[spaces_len - 1]);
11860                            col += spaces_len;
11861                            changed = true;
11862                        }
11863                        _ => {
11864                            // If we dont append before break, the character is consumed
11865                            reindented_line.push(ch);
11866                            break;
11867                        }
11868                    }
11869                }
11870
11871                if !changed {
11872                    reindented_line.clear();
11873                    continue;
11874                }
11875                // Append the rest of the line and replace old reference with new one
11876                reindented_line.extend(chars);
11877                *line = Cow::Owned(reindented_line.clone());
11878                reindented_line.clear();
11879            }
11880        });
11881    }
11882
11883    pub fn convert_indentation_to_tabs(
11884        &mut self,
11885        _: &ConvertIndentationToTabs,
11886        window: &mut Window,
11887        cx: &mut Context<Self>,
11888    ) {
11889        let settings = self.buffer.read(cx).language_settings(cx);
11890        let tab_size = settings.tab_size.get() as usize;
11891
11892        self.manipulate_mutable_lines(window, cx, |lines| {
11893            // Allocates a reasonably sized buffer once for the whole loop
11894            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11895            // Avoids recomputing spaces that could be inserted many times
11896            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11897                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11898                .collect();
11899
11900            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11901                let mut chars = line.chars();
11902                let mut spaces_count = 0;
11903                let mut first_non_indent_char = None;
11904                let mut changed = false;
11905
11906                for ch in chars.by_ref() {
11907                    match ch {
11908                        ' ' => {
11909                            // Keep track of spaces. Append \t when we reach tab_size
11910                            spaces_count += 1;
11911                            changed = true;
11912                            if spaces_count == tab_size {
11913                                reindented_line.push('\t');
11914                                spaces_count = 0;
11915                            }
11916                        }
11917                        '\t' => {
11918                            reindented_line.push('\t');
11919                            spaces_count = 0;
11920                        }
11921                        _ => {
11922                            // Dont append it yet, we might have remaining spaces
11923                            first_non_indent_char = Some(ch);
11924                            break;
11925                        }
11926                    }
11927                }
11928
11929                if !changed {
11930                    reindented_line.clear();
11931                    continue;
11932                }
11933                // Remaining spaces that didn't make a full tab stop
11934                if spaces_count > 0 {
11935                    reindented_line.extend(&space_cache[spaces_count - 1]);
11936                }
11937                // If we consume an extra character that was not indentation, add it back
11938                if let Some(extra_char) = first_non_indent_char {
11939                    reindented_line.push(extra_char);
11940                }
11941                // Append the rest of the line and replace old reference with new one
11942                reindented_line.extend(chars);
11943                *line = Cow::Owned(reindented_line.clone());
11944                reindented_line.clear();
11945            }
11946        });
11947    }
11948
11949    pub fn convert_to_upper_case(
11950        &mut self,
11951        _: &ConvertToUpperCase,
11952        window: &mut Window,
11953        cx: &mut Context<Self>,
11954    ) {
11955        self.manipulate_text(window, cx, |text| text.to_uppercase())
11956    }
11957
11958    pub fn convert_to_lower_case(
11959        &mut self,
11960        _: &ConvertToLowerCase,
11961        window: &mut Window,
11962        cx: &mut Context<Self>,
11963    ) {
11964        self.manipulate_text(window, cx, |text| text.to_lowercase())
11965    }
11966
11967    pub fn convert_to_title_case(
11968        &mut self,
11969        _: &ConvertToTitleCase,
11970        window: &mut Window,
11971        cx: &mut Context<Self>,
11972    ) {
11973        self.manipulate_text(window, cx, |text| {
11974            text.split('\n')
11975                .map(|line| line.to_case(Case::Title))
11976                .join("\n")
11977        })
11978    }
11979
11980    pub fn convert_to_snake_case(
11981        &mut self,
11982        _: &ConvertToSnakeCase,
11983        window: &mut Window,
11984        cx: &mut Context<Self>,
11985    ) {
11986        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11987    }
11988
11989    pub fn convert_to_kebab_case(
11990        &mut self,
11991        _: &ConvertToKebabCase,
11992        window: &mut Window,
11993        cx: &mut Context<Self>,
11994    ) {
11995        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11996    }
11997
11998    pub fn convert_to_upper_camel_case(
11999        &mut self,
12000        _: &ConvertToUpperCamelCase,
12001        window: &mut Window,
12002        cx: &mut Context<Self>,
12003    ) {
12004        self.manipulate_text(window, cx, |text| {
12005            text.split('\n')
12006                .map(|line| line.to_case(Case::UpperCamel))
12007                .join("\n")
12008        })
12009    }
12010
12011    pub fn convert_to_lower_camel_case(
12012        &mut self,
12013        _: &ConvertToLowerCamelCase,
12014        window: &mut Window,
12015        cx: &mut Context<Self>,
12016    ) {
12017        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
12018    }
12019
12020    pub fn convert_to_opposite_case(
12021        &mut self,
12022        _: &ConvertToOppositeCase,
12023        window: &mut Window,
12024        cx: &mut Context<Self>,
12025    ) {
12026        self.manipulate_text(window, cx, |text| {
12027            text.chars()
12028                .fold(String::with_capacity(text.len()), |mut t, c| {
12029                    if c.is_uppercase() {
12030                        t.extend(c.to_lowercase());
12031                    } else {
12032                        t.extend(c.to_uppercase());
12033                    }
12034                    t
12035                })
12036        })
12037    }
12038
12039    pub fn convert_to_sentence_case(
12040        &mut self,
12041        _: &ConvertToSentenceCase,
12042        window: &mut Window,
12043        cx: &mut Context<Self>,
12044    ) {
12045        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12046    }
12047
12048    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12049        self.manipulate_text(window, cx, |text| {
12050            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12051            if has_upper_case_characters {
12052                text.to_lowercase()
12053            } else {
12054                text.to_uppercase()
12055            }
12056        })
12057    }
12058
12059    pub fn convert_to_rot13(
12060        &mut self,
12061        _: &ConvertToRot13,
12062        window: &mut Window,
12063        cx: &mut Context<Self>,
12064    ) {
12065        self.manipulate_text(window, cx, |text| {
12066            text.chars()
12067                .map(|c| match c {
12068                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12069                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12070                    _ => c,
12071                })
12072                .collect()
12073        })
12074    }
12075
12076    pub fn convert_to_rot47(
12077        &mut self,
12078        _: &ConvertToRot47,
12079        window: &mut Window,
12080        cx: &mut Context<Self>,
12081    ) {
12082        self.manipulate_text(window, cx, |text| {
12083            text.chars()
12084                .map(|c| {
12085                    let code_point = c as u32;
12086                    if code_point >= 33 && code_point <= 126 {
12087                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12088                    }
12089                    c
12090                })
12091                .collect()
12092        })
12093    }
12094
12095    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12096    where
12097        Fn: FnMut(&str) -> String,
12098    {
12099        let buffer = self.buffer.read(cx).snapshot(cx);
12100
12101        let mut new_selections = Vec::new();
12102        let mut edits = Vec::new();
12103        let mut selection_adjustment = 0isize;
12104
12105        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12106            let selection_is_empty = selection.is_empty();
12107
12108            let (start, end) = if selection_is_empty {
12109                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12110                (word_range.start, word_range.end)
12111            } else {
12112                (
12113                    buffer.point_to_offset(selection.start),
12114                    buffer.point_to_offset(selection.end),
12115                )
12116            };
12117
12118            let text = buffer.text_for_range(start..end).collect::<String>();
12119            let old_length = text.len() as isize;
12120            let text = callback(&text);
12121
12122            new_selections.push(Selection {
12123                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12124                end: MultiBufferOffset(
12125                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12126                ),
12127                goal: SelectionGoal::None,
12128                id: selection.id,
12129                reversed: selection.reversed,
12130            });
12131
12132            selection_adjustment += old_length - text.len() as isize;
12133
12134            edits.push((start..end, text));
12135        }
12136
12137        self.transact(window, cx, |this, window, cx| {
12138            this.buffer.update(cx, |buffer, cx| {
12139                buffer.edit(edits, None, cx);
12140            });
12141
12142            this.change_selections(Default::default(), window, cx, |s| {
12143                s.select(new_selections);
12144            });
12145
12146            this.request_autoscroll(Autoscroll::fit(), cx);
12147        });
12148    }
12149
12150    pub fn move_selection_on_drop(
12151        &mut self,
12152        selection: &Selection<Anchor>,
12153        target: DisplayPoint,
12154        is_cut: bool,
12155        window: &mut Window,
12156        cx: &mut Context<Self>,
12157    ) {
12158        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12159        let buffer = display_map.buffer_snapshot();
12160        let mut edits = Vec::new();
12161        let insert_point = display_map
12162            .clip_point(target, Bias::Left)
12163            .to_point(&display_map);
12164        let text = buffer
12165            .text_for_range(selection.start..selection.end)
12166            .collect::<String>();
12167        if is_cut {
12168            edits.push(((selection.start..selection.end), String::new()));
12169        }
12170        let insert_anchor = buffer.anchor_before(insert_point);
12171        edits.push(((insert_anchor..insert_anchor), text));
12172        let last_edit_start = insert_anchor.bias_left(buffer);
12173        let last_edit_end = insert_anchor.bias_right(buffer);
12174        self.transact(window, cx, |this, window, cx| {
12175            this.buffer.update(cx, |buffer, cx| {
12176                buffer.edit(edits, None, cx);
12177            });
12178            this.change_selections(Default::default(), window, cx, |s| {
12179                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12180            });
12181        });
12182    }
12183
12184    pub fn clear_selection_drag_state(&mut self) {
12185        self.selection_drag_state = SelectionDragState::None;
12186    }
12187
12188    pub fn duplicate(
12189        &mut self,
12190        upwards: bool,
12191        whole_lines: bool,
12192        window: &mut Window,
12193        cx: &mut Context<Self>,
12194    ) {
12195        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12196
12197        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12198        let buffer = display_map.buffer_snapshot();
12199        let selections = self.selections.all::<Point>(&display_map);
12200
12201        let mut edits = Vec::new();
12202        let mut selections_iter = selections.iter().peekable();
12203        while let Some(selection) = selections_iter.next() {
12204            let mut rows = selection.spanned_rows(false, &display_map);
12205            // duplicate line-wise
12206            if whole_lines || selection.start == selection.end {
12207                // Avoid duplicating the same lines twice.
12208                while let Some(next_selection) = selections_iter.peek() {
12209                    let next_rows = next_selection.spanned_rows(false, &display_map);
12210                    if next_rows.start < rows.end {
12211                        rows.end = next_rows.end;
12212                        selections_iter.next().unwrap();
12213                    } else {
12214                        break;
12215                    }
12216                }
12217
12218                // Copy the text from the selected row region and splice it either at the start
12219                // or end of the region.
12220                let start = Point::new(rows.start.0, 0);
12221                let end = Point::new(
12222                    rows.end.previous_row().0,
12223                    buffer.line_len(rows.end.previous_row()),
12224                );
12225
12226                let mut text = buffer.text_for_range(start..end).collect::<String>();
12227
12228                let insert_location = if upwards {
12229                    // When duplicating upward, we need to insert before the current line.
12230                    // If we're on the last line and it doesn't end with a newline,
12231                    // we need to add a newline before the duplicated content.
12232                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12233                        && buffer.max_point().column > 0
12234                        && !text.ends_with('\n');
12235
12236                    if needs_leading_newline {
12237                        text.insert(0, '\n');
12238                        end
12239                    } else {
12240                        text.push('\n');
12241                        Point::new(rows.start.0, 0)
12242                    }
12243                } else {
12244                    text.push('\n');
12245                    start
12246                };
12247                edits.push((insert_location..insert_location, text));
12248            } else {
12249                // duplicate character-wise
12250                let start = selection.start;
12251                let end = selection.end;
12252                let text = buffer.text_for_range(start..end).collect::<String>();
12253                edits.push((selection.end..selection.end, text));
12254            }
12255        }
12256
12257        self.transact(window, cx, |this, window, cx| {
12258            this.buffer.update(cx, |buffer, cx| {
12259                buffer.edit(edits, None, cx);
12260            });
12261
12262            // When duplicating upward with whole lines, move the cursor to the duplicated line
12263            if upwards && whole_lines {
12264                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12265
12266                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12267                    let mut new_ranges = Vec::new();
12268                    let selections = s.all::<Point>(&display_map);
12269                    let mut selections_iter = selections.iter().peekable();
12270
12271                    while let Some(first_selection) = selections_iter.next() {
12272                        // Group contiguous selections together to find the total row span
12273                        let mut group_selections = vec![first_selection];
12274                        let mut rows = first_selection.spanned_rows(false, &display_map);
12275
12276                        while let Some(next_selection) = selections_iter.peek() {
12277                            let next_rows = next_selection.spanned_rows(false, &display_map);
12278                            if next_rows.start < rows.end {
12279                                rows.end = next_rows.end;
12280                                group_selections.push(selections_iter.next().unwrap());
12281                            } else {
12282                                break;
12283                            }
12284                        }
12285
12286                        let row_count = rows.end.0 - rows.start.0;
12287
12288                        // Move all selections in this group up by the total number of duplicated rows
12289                        for selection in group_selections {
12290                            let new_start = Point::new(
12291                                selection.start.row.saturating_sub(row_count),
12292                                selection.start.column,
12293                            );
12294
12295                            let new_end = Point::new(
12296                                selection.end.row.saturating_sub(row_count),
12297                                selection.end.column,
12298                            );
12299
12300                            new_ranges.push(new_start..new_end);
12301                        }
12302                    }
12303
12304                    s.select_ranges(new_ranges);
12305                });
12306            }
12307
12308            this.request_autoscroll(Autoscroll::fit(), cx);
12309        });
12310    }
12311
12312    pub fn duplicate_line_up(
12313        &mut self,
12314        _: &DuplicateLineUp,
12315        window: &mut Window,
12316        cx: &mut Context<Self>,
12317    ) {
12318        self.duplicate(true, true, window, cx);
12319    }
12320
12321    pub fn duplicate_line_down(
12322        &mut self,
12323        _: &DuplicateLineDown,
12324        window: &mut Window,
12325        cx: &mut Context<Self>,
12326    ) {
12327        self.duplicate(false, true, window, cx);
12328    }
12329
12330    pub fn duplicate_selection(
12331        &mut self,
12332        _: &DuplicateSelection,
12333        window: &mut Window,
12334        cx: &mut Context<Self>,
12335    ) {
12336        self.duplicate(false, false, window, cx);
12337    }
12338
12339    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12340        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12341        if self.mode.is_single_line() {
12342            cx.propagate();
12343            return;
12344        }
12345
12346        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12347        let buffer = self.buffer.read(cx).snapshot(cx);
12348
12349        let mut edits = Vec::new();
12350        let mut unfold_ranges = Vec::new();
12351        let mut refold_creases = Vec::new();
12352
12353        let selections = self.selections.all::<Point>(&display_map);
12354        let mut selections = selections.iter().peekable();
12355        let mut contiguous_row_selections = Vec::new();
12356        let mut new_selections = Vec::new();
12357
12358        while let Some(selection) = selections.next() {
12359            // Find all the selections that span a contiguous row range
12360            let (start_row, end_row) = consume_contiguous_rows(
12361                &mut contiguous_row_selections,
12362                selection,
12363                &display_map,
12364                &mut selections,
12365            );
12366
12367            // Move the text spanned by the row range to be before the line preceding the row range
12368            if start_row.0 > 0 {
12369                let range_to_move = Point::new(
12370                    start_row.previous_row().0,
12371                    buffer.line_len(start_row.previous_row()),
12372                )
12373                    ..Point::new(
12374                        end_row.previous_row().0,
12375                        buffer.line_len(end_row.previous_row()),
12376                    );
12377                let insertion_point = display_map
12378                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12379                    .0;
12380
12381                // Don't move lines across excerpts
12382                if buffer
12383                    .excerpt_containing(insertion_point..range_to_move.end)
12384                    .is_some()
12385                {
12386                    let text = buffer
12387                        .text_for_range(range_to_move.clone())
12388                        .flat_map(|s| s.chars())
12389                        .skip(1)
12390                        .chain(['\n'])
12391                        .collect::<String>();
12392
12393                    edits.push((
12394                        buffer.anchor_after(range_to_move.start)
12395                            ..buffer.anchor_before(range_to_move.end),
12396                        String::new(),
12397                    ));
12398                    let insertion_anchor = buffer.anchor_after(insertion_point);
12399                    edits.push((insertion_anchor..insertion_anchor, text));
12400
12401                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12402
12403                    // Move selections up
12404                    new_selections.extend(contiguous_row_selections.drain(..).map(
12405                        |mut selection| {
12406                            selection.start.row -= row_delta;
12407                            selection.end.row -= row_delta;
12408                            selection
12409                        },
12410                    ));
12411
12412                    // Move folds up
12413                    unfold_ranges.push(range_to_move.clone());
12414                    for fold in display_map.folds_in_range(
12415                        buffer.anchor_before(range_to_move.start)
12416                            ..buffer.anchor_after(range_to_move.end),
12417                    ) {
12418                        let mut start = fold.range.start.to_point(&buffer);
12419                        let mut end = fold.range.end.to_point(&buffer);
12420                        start.row -= row_delta;
12421                        end.row -= row_delta;
12422                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12423                    }
12424                }
12425            }
12426
12427            // If we didn't move line(s), preserve the existing selections
12428            new_selections.append(&mut contiguous_row_selections);
12429        }
12430
12431        self.transact(window, cx, |this, window, cx| {
12432            this.unfold_ranges(&unfold_ranges, true, true, cx);
12433            this.buffer.update(cx, |buffer, cx| {
12434                for (range, text) in edits {
12435                    buffer.edit([(range, text)], None, cx);
12436                }
12437            });
12438            this.fold_creases(refold_creases, true, window, cx);
12439            this.change_selections(Default::default(), window, cx, |s| {
12440                s.select(new_selections);
12441            })
12442        });
12443    }
12444
12445    pub fn move_line_down(
12446        &mut self,
12447        _: &MoveLineDown,
12448        window: &mut Window,
12449        cx: &mut Context<Self>,
12450    ) {
12451        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12452        if self.mode.is_single_line() {
12453            cx.propagate();
12454            return;
12455        }
12456
12457        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12458        let buffer = self.buffer.read(cx).snapshot(cx);
12459
12460        let mut edits = Vec::new();
12461        let mut unfold_ranges = Vec::new();
12462        let mut refold_creases = Vec::new();
12463
12464        let selections = self.selections.all::<Point>(&display_map);
12465        let mut selections = selections.iter().peekable();
12466        let mut contiguous_row_selections = Vec::new();
12467        let mut new_selections = Vec::new();
12468
12469        while let Some(selection) = selections.next() {
12470            // Find all the selections that span a contiguous row range
12471            let (start_row, end_row) = consume_contiguous_rows(
12472                &mut contiguous_row_selections,
12473                selection,
12474                &display_map,
12475                &mut selections,
12476            );
12477
12478            // Move the text spanned by the row range to be after the last line of the row range
12479            if end_row.0 <= buffer.max_point().row {
12480                let range_to_move =
12481                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12482                let insertion_point = display_map
12483                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12484                    .0;
12485
12486                // Don't move lines across excerpt boundaries
12487                if buffer
12488                    .excerpt_containing(range_to_move.start..insertion_point)
12489                    .is_some()
12490                {
12491                    let mut text = String::from("\n");
12492                    text.extend(buffer.text_for_range(range_to_move.clone()));
12493                    text.pop(); // Drop trailing newline
12494                    edits.push((
12495                        buffer.anchor_after(range_to_move.start)
12496                            ..buffer.anchor_before(range_to_move.end),
12497                        String::new(),
12498                    ));
12499                    let insertion_anchor = buffer.anchor_after(insertion_point);
12500                    edits.push((insertion_anchor..insertion_anchor, text));
12501
12502                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12503
12504                    // Move selections down
12505                    new_selections.extend(contiguous_row_selections.drain(..).map(
12506                        |mut selection| {
12507                            selection.start.row += row_delta;
12508                            selection.end.row += row_delta;
12509                            selection
12510                        },
12511                    ));
12512
12513                    // Move folds down
12514                    unfold_ranges.push(range_to_move.clone());
12515                    for fold in display_map.folds_in_range(
12516                        buffer.anchor_before(range_to_move.start)
12517                            ..buffer.anchor_after(range_to_move.end),
12518                    ) {
12519                        let mut start = fold.range.start.to_point(&buffer);
12520                        let mut end = fold.range.end.to_point(&buffer);
12521                        start.row += row_delta;
12522                        end.row += row_delta;
12523                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12524                    }
12525                }
12526            }
12527
12528            // If we didn't move line(s), preserve the existing selections
12529            new_selections.append(&mut contiguous_row_selections);
12530        }
12531
12532        self.transact(window, cx, |this, window, cx| {
12533            this.unfold_ranges(&unfold_ranges, true, true, cx);
12534            this.buffer.update(cx, |buffer, cx| {
12535                for (range, text) in edits {
12536                    buffer.edit([(range, text)], None, cx);
12537                }
12538            });
12539            this.fold_creases(refold_creases, true, window, cx);
12540            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12541        });
12542    }
12543
12544    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12545        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12546        let text_layout_details = &self.text_layout_details(window);
12547        self.transact(window, cx, |this, window, cx| {
12548            let edits = this.change_selections(Default::default(), window, cx, |s| {
12549                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12550                s.move_with(|display_map, selection| {
12551                    if !selection.is_empty() {
12552                        return;
12553                    }
12554
12555                    let mut head = selection.head();
12556                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12557                    if head.column() == display_map.line_len(head.row()) {
12558                        transpose_offset = display_map
12559                            .buffer_snapshot()
12560                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12561                    }
12562
12563                    if transpose_offset == MultiBufferOffset(0) {
12564                        return;
12565                    }
12566
12567                    *head.column_mut() += 1;
12568                    head = display_map.clip_point(head, Bias::Right);
12569                    let goal = SelectionGoal::HorizontalPosition(
12570                        display_map
12571                            .x_for_display_point(head, text_layout_details)
12572                            .into(),
12573                    );
12574                    selection.collapse_to(head, goal);
12575
12576                    let transpose_start = display_map
12577                        .buffer_snapshot()
12578                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12579                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12580                        let transpose_end = display_map
12581                            .buffer_snapshot()
12582                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12583                        if let Some(ch) = display_map
12584                            .buffer_snapshot()
12585                            .chars_at(transpose_start)
12586                            .next()
12587                        {
12588                            edits.push((transpose_start..transpose_offset, String::new()));
12589                            edits.push((transpose_end..transpose_end, ch.to_string()));
12590                        }
12591                    }
12592                });
12593                edits
12594            });
12595            this.buffer
12596                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12597            let selections = this
12598                .selections
12599                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12600            this.change_selections(Default::default(), window, cx, |s| {
12601                s.select(selections);
12602            });
12603        });
12604    }
12605
12606    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12607        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12608        if self.mode.is_single_line() {
12609            cx.propagate();
12610            return;
12611        }
12612
12613        self.rewrap_impl(RewrapOptions::default(), cx)
12614    }
12615
12616    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12617        let buffer = self.buffer.read(cx).snapshot(cx);
12618        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12619
12620        #[derive(Clone, Debug, PartialEq)]
12621        enum CommentFormat {
12622            /// single line comment, with prefix for line
12623            Line(String),
12624            /// single line within a block comment, with prefix for line
12625            BlockLine(String),
12626            /// a single line of a block comment that includes the initial delimiter
12627            BlockCommentWithStart(BlockCommentConfig),
12628            /// a single line of a block comment that includes the ending delimiter
12629            BlockCommentWithEnd(BlockCommentConfig),
12630        }
12631
12632        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12633        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12634            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12635                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12636                .peekable();
12637
12638            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12639                row
12640            } else {
12641                return Vec::new();
12642            };
12643
12644            let language_settings = buffer.language_settings_at(selection.head(), cx);
12645            let language_scope = buffer.language_scope_at(selection.head());
12646
12647            let indent_and_prefix_for_row =
12648                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12649                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12650                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12651                        &language_scope
12652                    {
12653                        let indent_end = Point::new(row, indent.len);
12654                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12655                        let line_text_after_indent = buffer
12656                            .text_for_range(indent_end..line_end)
12657                            .collect::<String>();
12658
12659                        let is_within_comment_override = buffer
12660                            .language_scope_at(indent_end)
12661                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12662                        let comment_delimiters = if is_within_comment_override {
12663                            // we are within a comment syntax node, but we don't
12664                            // yet know what kind of comment: block, doc or line
12665                            match (
12666                                language_scope.documentation_comment(),
12667                                language_scope.block_comment(),
12668                            ) {
12669                                (Some(config), _) | (_, Some(config))
12670                                    if buffer.contains_str_at(indent_end, &config.start) =>
12671                                {
12672                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12673                                }
12674                                (Some(config), _) | (_, Some(config))
12675                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12676                                {
12677                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12678                                }
12679                                (Some(config), _) | (_, Some(config))
12680                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12681                                {
12682                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12683                                }
12684                                (_, _) => language_scope
12685                                    .line_comment_prefixes()
12686                                    .iter()
12687                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12688                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12689                            }
12690                        } else {
12691                            // we not in an overridden comment node, but we may
12692                            // be within a non-overridden line comment node
12693                            language_scope
12694                                .line_comment_prefixes()
12695                                .iter()
12696                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12697                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12698                        };
12699
12700                        let rewrap_prefix = language_scope
12701                            .rewrap_prefixes()
12702                            .iter()
12703                            .find_map(|prefix_regex| {
12704                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12705                                    if mat.start() == 0 {
12706                                        Some(mat.as_str().to_string())
12707                                    } else {
12708                                        None
12709                                    }
12710                                })
12711                            })
12712                            .flatten();
12713                        (comment_delimiters, rewrap_prefix)
12714                    } else {
12715                        (None, None)
12716                    };
12717                    (indent, comment_prefix, rewrap_prefix)
12718                };
12719
12720            let mut ranges = Vec::new();
12721            let from_empty_selection = selection.is_empty();
12722
12723            let mut current_range_start = first_row;
12724            let mut prev_row = first_row;
12725            let (
12726                mut current_range_indent,
12727                mut current_range_comment_delimiters,
12728                mut current_range_rewrap_prefix,
12729            ) = indent_and_prefix_for_row(first_row);
12730
12731            for row in non_blank_rows_iter.skip(1) {
12732                let has_paragraph_break = row > prev_row + 1;
12733
12734                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12735                    indent_and_prefix_for_row(row);
12736
12737                let has_indent_change = row_indent != current_range_indent;
12738                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12739
12740                let has_boundary_change = has_comment_change
12741                    || row_rewrap_prefix.is_some()
12742                    || (has_indent_change && current_range_comment_delimiters.is_some());
12743
12744                if has_paragraph_break || has_boundary_change {
12745                    ranges.push((
12746                        language_settings.clone(),
12747                        Point::new(current_range_start, 0)
12748                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12749                        current_range_indent,
12750                        current_range_comment_delimiters.clone(),
12751                        current_range_rewrap_prefix.clone(),
12752                        from_empty_selection,
12753                    ));
12754                    current_range_start = row;
12755                    current_range_indent = row_indent;
12756                    current_range_comment_delimiters = row_comment_delimiters;
12757                    current_range_rewrap_prefix = row_rewrap_prefix;
12758                }
12759                prev_row = row;
12760            }
12761
12762            ranges.push((
12763                language_settings.clone(),
12764                Point::new(current_range_start, 0)
12765                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12766                current_range_indent,
12767                current_range_comment_delimiters,
12768                current_range_rewrap_prefix,
12769                from_empty_selection,
12770            ));
12771
12772            ranges
12773        });
12774
12775        let mut edits = Vec::new();
12776        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12777
12778        for (
12779            language_settings,
12780            wrap_range,
12781            mut indent_size,
12782            comment_prefix,
12783            rewrap_prefix,
12784            from_empty_selection,
12785        ) in wrap_ranges
12786        {
12787            let mut start_row = wrap_range.start.row;
12788            let mut end_row = wrap_range.end.row;
12789
12790            // Skip selections that overlap with a range that has already been rewrapped.
12791            let selection_range = start_row..end_row;
12792            if rewrapped_row_ranges
12793                .iter()
12794                .any(|range| range.overlaps(&selection_range))
12795            {
12796                continue;
12797            }
12798
12799            let tab_size = language_settings.tab_size;
12800
12801            let (line_prefix, inside_comment) = match &comment_prefix {
12802                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12803                    (Some(prefix.as_str()), true)
12804                }
12805                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12806                    (Some(prefix.as_ref()), true)
12807                }
12808                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12809                    start: _,
12810                    end: _,
12811                    prefix,
12812                    tab_size,
12813                })) => {
12814                    indent_size.len += tab_size;
12815                    (Some(prefix.as_ref()), true)
12816                }
12817                None => (None, false),
12818            };
12819            let indent_prefix = indent_size.chars().collect::<String>();
12820            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12821
12822            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12823                RewrapBehavior::InComments => inside_comment,
12824                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12825                RewrapBehavior::Anywhere => true,
12826            };
12827
12828            let should_rewrap = options.override_language_settings
12829                || allow_rewrap_based_on_language
12830                || self.hard_wrap.is_some();
12831            if !should_rewrap {
12832                continue;
12833            }
12834
12835            if from_empty_selection {
12836                'expand_upwards: while start_row > 0 {
12837                    let prev_row = start_row - 1;
12838                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12839                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12840                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12841                    {
12842                        start_row = prev_row;
12843                    } else {
12844                        break 'expand_upwards;
12845                    }
12846                }
12847
12848                'expand_downwards: while end_row < buffer.max_point().row {
12849                    let next_row = end_row + 1;
12850                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12851                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12852                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12853                    {
12854                        end_row = next_row;
12855                    } else {
12856                        break 'expand_downwards;
12857                    }
12858                }
12859            }
12860
12861            let start = Point::new(start_row, 0);
12862            let start_offset = ToOffset::to_offset(&start, &buffer);
12863            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12864            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12865            let mut first_line_delimiter = None;
12866            let mut last_line_delimiter = None;
12867            let Some(lines_without_prefixes) = selection_text
12868                .lines()
12869                .enumerate()
12870                .map(|(ix, line)| {
12871                    let line_trimmed = line.trim_start();
12872                    if rewrap_prefix.is_some() && ix > 0 {
12873                        Ok(line_trimmed)
12874                    } else if let Some(
12875                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12876                            start,
12877                            prefix,
12878                            end,
12879                            tab_size,
12880                        })
12881                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12882                            start,
12883                            prefix,
12884                            end,
12885                            tab_size,
12886                        }),
12887                    ) = &comment_prefix
12888                    {
12889                        let line_trimmed = line_trimmed
12890                            .strip_prefix(start.as_ref())
12891                            .map(|s| {
12892                                let mut indent_size = indent_size;
12893                                indent_size.len -= tab_size;
12894                                let indent_prefix: String = indent_size.chars().collect();
12895                                first_line_delimiter = Some((indent_prefix, start));
12896                                s.trim_start()
12897                            })
12898                            .unwrap_or(line_trimmed);
12899                        let line_trimmed = line_trimmed
12900                            .strip_suffix(end.as_ref())
12901                            .map(|s| {
12902                                last_line_delimiter = Some(end);
12903                                s.trim_end()
12904                            })
12905                            .unwrap_or(line_trimmed);
12906                        let line_trimmed = line_trimmed
12907                            .strip_prefix(prefix.as_ref())
12908                            .unwrap_or(line_trimmed);
12909                        Ok(line_trimmed)
12910                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12911                        line_trimmed.strip_prefix(prefix).with_context(|| {
12912                            format!("line did not start with prefix {prefix:?}: {line:?}")
12913                        })
12914                    } else {
12915                        line_trimmed
12916                            .strip_prefix(&line_prefix.trim_start())
12917                            .with_context(|| {
12918                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12919                            })
12920                    }
12921                })
12922                .collect::<Result<Vec<_>, _>>()
12923                .log_err()
12924            else {
12925                continue;
12926            };
12927
12928            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12929                buffer
12930                    .language_settings_at(Point::new(start_row, 0), cx)
12931                    .preferred_line_length as usize
12932            });
12933
12934            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12935                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12936            } else {
12937                line_prefix.clone()
12938            };
12939
12940            let wrapped_text = {
12941                let mut wrapped_text = wrap_with_prefix(
12942                    line_prefix,
12943                    subsequent_lines_prefix,
12944                    lines_without_prefixes.join("\n"),
12945                    wrap_column,
12946                    tab_size,
12947                    options.preserve_existing_whitespace,
12948                );
12949
12950                if let Some((indent, delimiter)) = first_line_delimiter {
12951                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12952                }
12953                if let Some(last_line) = last_line_delimiter {
12954                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12955                }
12956
12957                wrapped_text
12958            };
12959
12960            // TODO: should always use char-based diff while still supporting cursor behavior that
12961            // matches vim.
12962            let mut diff_options = DiffOptions::default();
12963            if options.override_language_settings {
12964                diff_options.max_word_diff_len = 0;
12965                diff_options.max_word_diff_line_count = 0;
12966            } else {
12967                diff_options.max_word_diff_len = usize::MAX;
12968                diff_options.max_word_diff_line_count = usize::MAX;
12969            }
12970
12971            for (old_range, new_text) in
12972                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12973            {
12974                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12975                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12976                edits.push((edit_start..edit_end, new_text));
12977            }
12978
12979            rewrapped_row_ranges.push(start_row..=end_row);
12980        }
12981
12982        self.buffer
12983            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12984    }
12985
12986    pub fn cut_common(
12987        &mut self,
12988        cut_no_selection_line: bool,
12989        window: &mut Window,
12990        cx: &mut Context<Self>,
12991    ) -> ClipboardItem {
12992        let mut text = String::new();
12993        let buffer = self.buffer.read(cx).snapshot(cx);
12994        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12995        let mut clipboard_selections = Vec::with_capacity(selections.len());
12996        {
12997            let max_point = buffer.max_point();
12998            let mut is_first = true;
12999            let mut prev_selection_was_entire_line = false;
13000            for selection in &mut selections {
13001                let is_entire_line =
13002                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13003                if is_entire_line {
13004                    selection.start = Point::new(selection.start.row, 0);
13005                    if !selection.is_empty() && selection.end.column == 0 {
13006                        selection.end = cmp::min(max_point, selection.end);
13007                    } else {
13008                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13009                    }
13010                    selection.goal = SelectionGoal::None;
13011                }
13012                if is_first {
13013                    is_first = false;
13014                } else if !prev_selection_was_entire_line {
13015                    text += "\n";
13016                }
13017                prev_selection_was_entire_line = is_entire_line;
13018                let mut len = 0;
13019                for chunk in buffer.text_for_range(selection.start..selection.end) {
13020                    text.push_str(chunk);
13021                    len += chunk.len();
13022                }
13023
13024                clipboard_selections.push(ClipboardSelection::for_buffer(
13025                    len,
13026                    is_entire_line,
13027                    selection.range(),
13028                    &buffer,
13029                    self.project.as_ref(),
13030                    cx,
13031                ));
13032            }
13033        }
13034
13035        self.transact(window, cx, |this, window, cx| {
13036            this.change_selections(Default::default(), window, cx, |s| {
13037                s.select(selections);
13038            });
13039            this.insert("", window, cx);
13040        });
13041        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13042    }
13043
13044    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13045        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13046        let item = self.cut_common(true, window, cx);
13047        cx.write_to_clipboard(item);
13048    }
13049
13050    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13051        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13052        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13053            s.move_with(|snapshot, sel| {
13054                if sel.is_empty() {
13055                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13056                }
13057                if sel.is_empty() {
13058                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13059                }
13060            });
13061        });
13062        let item = self.cut_common(false, window, cx);
13063        cx.set_global(KillRing(item))
13064    }
13065
13066    pub fn kill_ring_yank(
13067        &mut self,
13068        _: &KillRingYank,
13069        window: &mut Window,
13070        cx: &mut Context<Self>,
13071    ) {
13072        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13073        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13074            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13075                (kill_ring.text().to_string(), kill_ring.metadata_json())
13076            } else {
13077                return;
13078            }
13079        } else {
13080            return;
13081        };
13082        self.do_paste(&text, metadata, false, window, cx);
13083    }
13084
13085    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13086        self.do_copy(true, cx);
13087    }
13088
13089    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13090        self.do_copy(false, cx);
13091    }
13092
13093    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13094        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13095        let buffer = self.buffer.read(cx).read(cx);
13096        let mut text = String::new();
13097
13098        let mut clipboard_selections = Vec::with_capacity(selections.len());
13099        {
13100            let max_point = buffer.max_point();
13101            let mut is_first = true;
13102            let mut prev_selection_was_entire_line = false;
13103            for selection in &selections {
13104                let mut start = selection.start;
13105                let mut end = selection.end;
13106                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13107                let mut add_trailing_newline = false;
13108                if is_entire_line {
13109                    start = Point::new(start.row, 0);
13110                    let next_line_start = Point::new(end.row + 1, 0);
13111                    if next_line_start <= max_point {
13112                        end = next_line_start;
13113                    } else {
13114                        // We're on the last line without a trailing newline.
13115                        // Copy to the end of the line and add a newline afterwards.
13116                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13117                        add_trailing_newline = true;
13118                    }
13119                }
13120
13121                let mut trimmed_selections = Vec::new();
13122                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13123                    let row = MultiBufferRow(start.row);
13124                    let first_indent = buffer.indent_size_for_line(row);
13125                    if first_indent.len == 0 || start.column > first_indent.len {
13126                        trimmed_selections.push(start..end);
13127                    } else {
13128                        trimmed_selections.push(
13129                            Point::new(row.0, first_indent.len)
13130                                ..Point::new(row.0, buffer.line_len(row)),
13131                        );
13132                        for row in start.row + 1..=end.row {
13133                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13134                            if row == end.row {
13135                                line_len = end.column;
13136                            }
13137                            if line_len == 0 {
13138                                trimmed_selections
13139                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13140                                continue;
13141                            }
13142                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13143                            if row_indent_size.len >= first_indent.len {
13144                                trimmed_selections.push(
13145                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13146                                );
13147                            } else {
13148                                trimmed_selections.clear();
13149                                trimmed_selections.push(start..end);
13150                                break;
13151                            }
13152                        }
13153                    }
13154                } else {
13155                    trimmed_selections.push(start..end);
13156                }
13157
13158                for trimmed_range in trimmed_selections {
13159                    if is_first {
13160                        is_first = false;
13161                    } else if !prev_selection_was_entire_line {
13162                        text += "\n";
13163                    }
13164                    prev_selection_was_entire_line = is_entire_line;
13165                    let mut len = 0;
13166                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13167                        text.push_str(chunk);
13168                        len += chunk.len();
13169                    }
13170                    if add_trailing_newline {
13171                        text.push('\n');
13172                        len += 1;
13173                    }
13174                    clipboard_selections.push(ClipboardSelection::for_buffer(
13175                        len,
13176                        is_entire_line,
13177                        trimmed_range,
13178                        &buffer,
13179                        self.project.as_ref(),
13180                        cx,
13181                    ));
13182                }
13183            }
13184        }
13185
13186        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13187            text,
13188            clipboard_selections,
13189        ));
13190    }
13191
13192    pub fn do_paste(
13193        &mut self,
13194        text: &String,
13195        clipboard_selections: Option<Vec<ClipboardSelection>>,
13196        handle_entire_lines: bool,
13197        window: &mut Window,
13198        cx: &mut Context<Self>,
13199    ) {
13200        if self.read_only(cx) {
13201            return;
13202        }
13203
13204        let clipboard_text = Cow::Borrowed(text.as_str());
13205
13206        self.transact(window, cx, |this, window, cx| {
13207            let had_active_edit_prediction = this.has_active_edit_prediction();
13208            let display_map = this.display_snapshot(cx);
13209            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13210            let cursor_offset = this
13211                .selections
13212                .last::<MultiBufferOffset>(&display_map)
13213                .head();
13214
13215            if let Some(mut clipboard_selections) = clipboard_selections {
13216                let all_selections_were_entire_line =
13217                    clipboard_selections.iter().all(|s| s.is_entire_line);
13218                let first_selection_indent_column =
13219                    clipboard_selections.first().map(|s| s.first_line_indent);
13220                if clipboard_selections.len() != old_selections.len() {
13221                    clipboard_selections.drain(..);
13222                }
13223                let mut auto_indent_on_paste = true;
13224
13225                this.buffer.update(cx, |buffer, cx| {
13226                    let snapshot = buffer.read(cx);
13227                    auto_indent_on_paste = snapshot
13228                        .language_settings_at(cursor_offset, cx)
13229                        .auto_indent_on_paste;
13230
13231                    let mut start_offset = 0;
13232                    let mut edits = Vec::new();
13233                    let mut original_indent_columns = Vec::new();
13234                    for (ix, selection) in old_selections.iter().enumerate() {
13235                        let to_insert;
13236                        let entire_line;
13237                        let original_indent_column;
13238                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13239                            let end_offset = start_offset + clipboard_selection.len;
13240                            to_insert = &clipboard_text[start_offset..end_offset];
13241                            entire_line = clipboard_selection.is_entire_line;
13242                            start_offset = if entire_line {
13243                                end_offset
13244                            } else {
13245                                end_offset + 1
13246                            };
13247                            original_indent_column = Some(clipboard_selection.first_line_indent);
13248                        } else {
13249                            to_insert = &*clipboard_text;
13250                            entire_line = all_selections_were_entire_line;
13251                            original_indent_column = first_selection_indent_column
13252                        }
13253
13254                        let (range, to_insert) =
13255                            if selection.is_empty() && handle_entire_lines && entire_line {
13256                                // If the corresponding selection was empty when this slice of the
13257                                // clipboard text was written, then the entire line containing the
13258                                // selection was copied. If this selection is also currently empty,
13259                                // then paste the line before the current line of the buffer.
13260                                let column = selection.start.to_point(&snapshot).column as usize;
13261                                let line_start = selection.start - column;
13262                                (line_start..line_start, Cow::Borrowed(to_insert))
13263                            } else {
13264                                let language = snapshot.language_at(selection.head());
13265                                let range = selection.range();
13266                                if let Some(language) = language
13267                                    && language.name() == "Markdown".into()
13268                                {
13269                                    edit_for_markdown_paste(
13270                                        &snapshot,
13271                                        range,
13272                                        to_insert,
13273                                        url::Url::parse(to_insert).ok(),
13274                                    )
13275                                } else {
13276                                    (range, Cow::Borrowed(to_insert))
13277                                }
13278                            };
13279
13280                        edits.push((range, to_insert));
13281                        original_indent_columns.push(original_indent_column);
13282                    }
13283                    drop(snapshot);
13284
13285                    buffer.edit(
13286                        edits,
13287                        if auto_indent_on_paste {
13288                            Some(AutoindentMode::Block {
13289                                original_indent_columns,
13290                            })
13291                        } else {
13292                            None
13293                        },
13294                        cx,
13295                    );
13296                });
13297
13298                let selections = this
13299                    .selections
13300                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13301                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13302            } else {
13303                let url = url::Url::parse(&clipboard_text).ok();
13304
13305                let auto_indent_mode = if !clipboard_text.is_empty() {
13306                    Some(AutoindentMode::Block {
13307                        original_indent_columns: Vec::new(),
13308                    })
13309                } else {
13310                    None
13311                };
13312
13313                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13314                    let snapshot = buffer.snapshot(cx);
13315
13316                    let anchors = old_selections
13317                        .iter()
13318                        .map(|s| {
13319                            let anchor = snapshot.anchor_after(s.head());
13320                            s.map(|_| anchor)
13321                        })
13322                        .collect::<Vec<_>>();
13323
13324                    let mut edits = Vec::new();
13325
13326                    for selection in old_selections.iter() {
13327                        let language = snapshot.language_at(selection.head());
13328                        let range = selection.range();
13329
13330                        let (edit_range, edit_text) = if let Some(language) = language
13331                            && language.name() == "Markdown".into()
13332                        {
13333                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13334                        } else {
13335                            (range, clipboard_text.clone())
13336                        };
13337
13338                        edits.push((edit_range, edit_text));
13339                    }
13340
13341                    drop(snapshot);
13342                    buffer.edit(edits, auto_indent_mode, cx);
13343
13344                    anchors
13345                });
13346
13347                this.change_selections(Default::default(), window, cx, |s| {
13348                    s.select_anchors(selection_anchors);
13349                });
13350            }
13351
13352            //   🤔                 |    ..     | show_in_menu |
13353            // | ..                  |   true        true
13354            // | had_edit_prediction |   false       true
13355
13356            let trigger_in_words =
13357                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13358
13359            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13360        });
13361    }
13362
13363    pub fn diff_clipboard_with_selection(
13364        &mut self,
13365        _: &DiffClipboardWithSelection,
13366        window: &mut Window,
13367        cx: &mut Context<Self>,
13368    ) {
13369        let selections = self
13370            .selections
13371            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13372
13373        if selections.is_empty() {
13374            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13375            return;
13376        };
13377
13378        let clipboard_text = match cx.read_from_clipboard() {
13379            Some(item) => match item.entries().first() {
13380                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13381                _ => None,
13382            },
13383            None => None,
13384        };
13385
13386        let Some(clipboard_text) = clipboard_text else {
13387            log::warn!("Clipboard doesn't contain text.");
13388            return;
13389        };
13390
13391        window.dispatch_action(
13392            Box::new(DiffClipboardWithSelectionData {
13393                clipboard_text,
13394                editor: cx.entity(),
13395            }),
13396            cx,
13397        );
13398    }
13399
13400    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13401        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13402        if let Some(item) = cx.read_from_clipboard() {
13403            let entries = item.entries();
13404
13405            match entries.first() {
13406                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13407                // of all the pasted entries.
13408                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13409                    .do_paste(
13410                        clipboard_string.text(),
13411                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13412                        true,
13413                        window,
13414                        cx,
13415                    ),
13416                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13417            }
13418        }
13419    }
13420
13421    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13422        if self.read_only(cx) {
13423            return;
13424        }
13425
13426        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13427
13428        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13429            if let Some((selections, _)) =
13430                self.selection_history.transaction(transaction_id).cloned()
13431            {
13432                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13433                    s.select_anchors(selections.to_vec());
13434                });
13435            } else {
13436                log::error!(
13437                    "No entry in selection_history found for undo. \
13438                     This may correspond to a bug where undo does not update the selection. \
13439                     If this is occurring, please add details to \
13440                     https://github.com/zed-industries/zed/issues/22692"
13441                );
13442            }
13443            self.request_autoscroll(Autoscroll::fit(), cx);
13444            self.unmark_text(window, cx);
13445            self.refresh_edit_prediction(true, false, window, cx);
13446            cx.emit(EditorEvent::Edited { transaction_id });
13447            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13448        }
13449    }
13450
13451    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13452        if self.read_only(cx) {
13453            return;
13454        }
13455
13456        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13457
13458        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13459            if let Some((_, Some(selections))) =
13460                self.selection_history.transaction(transaction_id).cloned()
13461            {
13462                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13463                    s.select_anchors(selections.to_vec());
13464                });
13465            } else {
13466                log::error!(
13467                    "No entry in selection_history found for redo. \
13468                     This may correspond to a bug where undo does not update the selection. \
13469                     If this is occurring, please add details to \
13470                     https://github.com/zed-industries/zed/issues/22692"
13471                );
13472            }
13473            self.request_autoscroll(Autoscroll::fit(), cx);
13474            self.unmark_text(window, cx);
13475            self.refresh_edit_prediction(true, false, window, cx);
13476            cx.emit(EditorEvent::Edited { transaction_id });
13477        }
13478    }
13479
13480    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13481        self.buffer
13482            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13483    }
13484
13485    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13486        self.buffer
13487            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13488    }
13489
13490    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13491        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13492        self.change_selections(Default::default(), window, cx, |s| {
13493            s.move_with(|map, selection| {
13494                let cursor = if selection.is_empty() {
13495                    movement::left(map, selection.start)
13496                } else {
13497                    selection.start
13498                };
13499                selection.collapse_to(cursor, SelectionGoal::None);
13500            });
13501        })
13502    }
13503
13504    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13505        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13506        self.change_selections(Default::default(), window, cx, |s| {
13507            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13508        })
13509    }
13510
13511    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13512        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13513        self.change_selections(Default::default(), window, cx, |s| {
13514            s.move_with(|map, selection| {
13515                let cursor = if selection.is_empty() {
13516                    movement::right(map, selection.end)
13517                } else {
13518                    selection.end
13519                };
13520                selection.collapse_to(cursor, SelectionGoal::None)
13521            });
13522        })
13523    }
13524
13525    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13526        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13527        self.change_selections(Default::default(), window, cx, |s| {
13528            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13529        });
13530    }
13531
13532    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13533        if self.take_rename(true, window, cx).is_some() {
13534            return;
13535        }
13536
13537        if self.mode.is_single_line() {
13538            cx.propagate();
13539            return;
13540        }
13541
13542        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13543
13544        let text_layout_details = &self.text_layout_details(window);
13545        let selection_count = self.selections.count();
13546        let first_selection = self.selections.first_anchor();
13547
13548        self.change_selections(Default::default(), window, cx, |s| {
13549            s.move_with(|map, selection| {
13550                if !selection.is_empty() {
13551                    selection.goal = SelectionGoal::None;
13552                }
13553                let (cursor, goal) = movement::up(
13554                    map,
13555                    selection.start,
13556                    selection.goal,
13557                    false,
13558                    text_layout_details,
13559                );
13560                selection.collapse_to(cursor, goal);
13561            });
13562        });
13563
13564        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13565        {
13566            cx.propagate();
13567        }
13568    }
13569
13570    pub fn move_up_by_lines(
13571        &mut self,
13572        action: &MoveUpByLines,
13573        window: &mut Window,
13574        cx: &mut Context<Self>,
13575    ) {
13576        if self.take_rename(true, window, cx).is_some() {
13577            return;
13578        }
13579
13580        if self.mode.is_single_line() {
13581            cx.propagate();
13582            return;
13583        }
13584
13585        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13586
13587        let text_layout_details = &self.text_layout_details(window);
13588
13589        self.change_selections(Default::default(), window, cx, |s| {
13590            s.move_with(|map, selection| {
13591                if !selection.is_empty() {
13592                    selection.goal = SelectionGoal::None;
13593                }
13594                let (cursor, goal) = movement::up_by_rows(
13595                    map,
13596                    selection.start,
13597                    action.lines,
13598                    selection.goal,
13599                    false,
13600                    text_layout_details,
13601                );
13602                selection.collapse_to(cursor, goal);
13603            });
13604        })
13605    }
13606
13607    pub fn move_down_by_lines(
13608        &mut self,
13609        action: &MoveDownByLines,
13610        window: &mut Window,
13611        cx: &mut Context<Self>,
13612    ) {
13613        if self.take_rename(true, window, cx).is_some() {
13614            return;
13615        }
13616
13617        if self.mode.is_single_line() {
13618            cx.propagate();
13619            return;
13620        }
13621
13622        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13623
13624        let text_layout_details = &self.text_layout_details(window);
13625
13626        self.change_selections(Default::default(), window, cx, |s| {
13627            s.move_with(|map, selection| {
13628                if !selection.is_empty() {
13629                    selection.goal = SelectionGoal::None;
13630                }
13631                let (cursor, goal) = movement::down_by_rows(
13632                    map,
13633                    selection.start,
13634                    action.lines,
13635                    selection.goal,
13636                    false,
13637                    text_layout_details,
13638                );
13639                selection.collapse_to(cursor, goal);
13640            });
13641        })
13642    }
13643
13644    pub fn select_down_by_lines(
13645        &mut self,
13646        action: &SelectDownByLines,
13647        window: &mut Window,
13648        cx: &mut Context<Self>,
13649    ) {
13650        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13651        let text_layout_details = &self.text_layout_details(window);
13652        self.change_selections(Default::default(), window, cx, |s| {
13653            s.move_heads_with(|map, head, goal| {
13654                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13655            })
13656        })
13657    }
13658
13659    pub fn select_up_by_lines(
13660        &mut self,
13661        action: &SelectUpByLines,
13662        window: &mut Window,
13663        cx: &mut Context<Self>,
13664    ) {
13665        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13666        let text_layout_details = &self.text_layout_details(window);
13667        self.change_selections(Default::default(), window, cx, |s| {
13668            s.move_heads_with(|map, head, goal| {
13669                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13670            })
13671        })
13672    }
13673
13674    pub fn select_page_up(
13675        &mut self,
13676        _: &SelectPageUp,
13677        window: &mut Window,
13678        cx: &mut Context<Self>,
13679    ) {
13680        let Some(row_count) = self.visible_row_count() else {
13681            return;
13682        };
13683
13684        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13685
13686        let text_layout_details = &self.text_layout_details(window);
13687
13688        self.change_selections(Default::default(), window, cx, |s| {
13689            s.move_heads_with(|map, head, goal| {
13690                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13691            })
13692        })
13693    }
13694
13695    pub fn move_page_up(
13696        &mut self,
13697        action: &MovePageUp,
13698        window: &mut Window,
13699        cx: &mut Context<Self>,
13700    ) {
13701        if self.take_rename(true, window, cx).is_some() {
13702            return;
13703        }
13704
13705        if self
13706            .context_menu
13707            .borrow_mut()
13708            .as_mut()
13709            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13710            .unwrap_or(false)
13711        {
13712            return;
13713        }
13714
13715        if matches!(self.mode, EditorMode::SingleLine) {
13716            cx.propagate();
13717            return;
13718        }
13719
13720        let Some(row_count) = self.visible_row_count() else {
13721            return;
13722        };
13723
13724        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13725
13726        let effects = if action.center_cursor {
13727            SelectionEffects::scroll(Autoscroll::center())
13728        } else {
13729            SelectionEffects::default()
13730        };
13731
13732        let text_layout_details = &self.text_layout_details(window);
13733
13734        self.change_selections(effects, window, cx, |s| {
13735            s.move_with(|map, selection| {
13736                if !selection.is_empty() {
13737                    selection.goal = SelectionGoal::None;
13738                }
13739                let (cursor, goal) = movement::up_by_rows(
13740                    map,
13741                    selection.end,
13742                    row_count,
13743                    selection.goal,
13744                    false,
13745                    text_layout_details,
13746                );
13747                selection.collapse_to(cursor, goal);
13748            });
13749        });
13750    }
13751
13752    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13753        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13754        let text_layout_details = &self.text_layout_details(window);
13755        self.change_selections(Default::default(), window, cx, |s| {
13756            s.move_heads_with(|map, head, goal| {
13757                movement::up(map, head, goal, false, text_layout_details)
13758            })
13759        })
13760    }
13761
13762    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13763        self.take_rename(true, window, cx);
13764
13765        if self.mode.is_single_line() {
13766            cx.propagate();
13767            return;
13768        }
13769
13770        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13771
13772        let text_layout_details = &self.text_layout_details(window);
13773        let selection_count = self.selections.count();
13774        let first_selection = self.selections.first_anchor();
13775
13776        self.change_selections(Default::default(), window, cx, |s| {
13777            s.move_with(|map, selection| {
13778                if !selection.is_empty() {
13779                    selection.goal = SelectionGoal::None;
13780                }
13781                let (cursor, goal) = movement::down(
13782                    map,
13783                    selection.end,
13784                    selection.goal,
13785                    false,
13786                    text_layout_details,
13787                );
13788                selection.collapse_to(cursor, goal);
13789            });
13790        });
13791
13792        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13793        {
13794            cx.propagate();
13795        }
13796    }
13797
13798    pub fn select_page_down(
13799        &mut self,
13800        _: &SelectPageDown,
13801        window: &mut Window,
13802        cx: &mut Context<Self>,
13803    ) {
13804        let Some(row_count) = self.visible_row_count() else {
13805            return;
13806        };
13807
13808        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13809
13810        let text_layout_details = &self.text_layout_details(window);
13811
13812        self.change_selections(Default::default(), window, cx, |s| {
13813            s.move_heads_with(|map, head, goal| {
13814                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13815            })
13816        })
13817    }
13818
13819    pub fn move_page_down(
13820        &mut self,
13821        action: &MovePageDown,
13822        window: &mut Window,
13823        cx: &mut Context<Self>,
13824    ) {
13825        if self.take_rename(true, window, cx).is_some() {
13826            return;
13827        }
13828
13829        if self
13830            .context_menu
13831            .borrow_mut()
13832            .as_mut()
13833            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13834            .unwrap_or(false)
13835        {
13836            return;
13837        }
13838
13839        if matches!(self.mode, EditorMode::SingleLine) {
13840            cx.propagate();
13841            return;
13842        }
13843
13844        let Some(row_count) = self.visible_row_count() else {
13845            return;
13846        };
13847
13848        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13849
13850        let effects = if action.center_cursor {
13851            SelectionEffects::scroll(Autoscroll::center())
13852        } else {
13853            SelectionEffects::default()
13854        };
13855
13856        let text_layout_details = &self.text_layout_details(window);
13857        self.change_selections(effects, window, cx, |s| {
13858            s.move_with(|map, selection| {
13859                if !selection.is_empty() {
13860                    selection.goal = SelectionGoal::None;
13861                }
13862                let (cursor, goal) = movement::down_by_rows(
13863                    map,
13864                    selection.end,
13865                    row_count,
13866                    selection.goal,
13867                    false,
13868                    text_layout_details,
13869                );
13870                selection.collapse_to(cursor, goal);
13871            });
13872        });
13873    }
13874
13875    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13876        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13877        let text_layout_details = &self.text_layout_details(window);
13878        self.change_selections(Default::default(), window, cx, |s| {
13879            s.move_heads_with(|map, head, goal| {
13880                movement::down(map, head, goal, false, text_layout_details)
13881            })
13882        });
13883    }
13884
13885    pub fn context_menu_first(
13886        &mut self,
13887        _: &ContextMenuFirst,
13888        window: &mut Window,
13889        cx: &mut Context<Self>,
13890    ) {
13891        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13892            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13893        }
13894    }
13895
13896    pub fn context_menu_prev(
13897        &mut self,
13898        _: &ContextMenuPrevious,
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_prev(self.completion_provider.as_deref(), window, cx);
13904        }
13905    }
13906
13907    pub fn context_menu_next(
13908        &mut self,
13909        _: &ContextMenuNext,
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_next(self.completion_provider.as_deref(), window, cx);
13915        }
13916    }
13917
13918    pub fn context_menu_last(
13919        &mut self,
13920        _: &ContextMenuLast,
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_last(self.completion_provider.as_deref(), window, cx);
13926        }
13927    }
13928
13929    pub fn signature_help_prev(
13930        &mut self,
13931        _: &SignatureHelpPrevious,
13932        _: &mut Window,
13933        cx: &mut Context<Self>,
13934    ) {
13935        if let Some(popover) = self.signature_help_state.popover_mut() {
13936            if popover.current_signature == 0 {
13937                popover.current_signature = popover.signatures.len() - 1;
13938            } else {
13939                popover.current_signature -= 1;
13940            }
13941            cx.notify();
13942        }
13943    }
13944
13945    pub fn signature_help_next(
13946        &mut self,
13947        _: &SignatureHelpNext,
13948        _: &mut Window,
13949        cx: &mut Context<Self>,
13950    ) {
13951        if let Some(popover) = self.signature_help_state.popover_mut() {
13952            if popover.current_signature + 1 == popover.signatures.len() {
13953                popover.current_signature = 0;
13954            } else {
13955                popover.current_signature += 1;
13956            }
13957            cx.notify();
13958        }
13959    }
13960
13961    pub fn move_to_previous_word_start(
13962        &mut self,
13963        _: &MoveToPreviousWordStart,
13964        window: &mut Window,
13965        cx: &mut Context<Self>,
13966    ) {
13967        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13968        self.change_selections(Default::default(), window, cx, |s| {
13969            s.move_cursors_with(|map, head, _| {
13970                (
13971                    movement::previous_word_start(map, head),
13972                    SelectionGoal::None,
13973                )
13974            });
13975        })
13976    }
13977
13978    pub fn move_to_previous_subword_start(
13979        &mut self,
13980        _: &MoveToPreviousSubwordStart,
13981        window: &mut Window,
13982        cx: &mut Context<Self>,
13983    ) {
13984        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13985        self.change_selections(Default::default(), window, cx, |s| {
13986            s.move_cursors_with(|map, head, _| {
13987                (
13988                    movement::previous_subword_start(map, head),
13989                    SelectionGoal::None,
13990                )
13991            });
13992        })
13993    }
13994
13995    pub fn select_to_previous_word_start(
13996        &mut self,
13997        _: &SelectToPreviousWordStart,
13998        window: &mut Window,
13999        cx: &mut Context<Self>,
14000    ) {
14001        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14002        self.change_selections(Default::default(), window, cx, |s| {
14003            s.move_heads_with(|map, head, _| {
14004                (
14005                    movement::previous_word_start(map, head),
14006                    SelectionGoal::None,
14007                )
14008            });
14009        })
14010    }
14011
14012    pub fn select_to_previous_subword_start(
14013        &mut self,
14014        _: &SelectToPreviousSubwordStart,
14015        window: &mut Window,
14016        cx: &mut Context<Self>,
14017    ) {
14018        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14019        self.change_selections(Default::default(), window, cx, |s| {
14020            s.move_heads_with(|map, head, _| {
14021                (
14022                    movement::previous_subword_start(map, head),
14023                    SelectionGoal::None,
14024                )
14025            });
14026        })
14027    }
14028
14029    pub fn delete_to_previous_word_start(
14030        &mut self,
14031        action: &DeleteToPreviousWordStart,
14032        window: &mut Window,
14033        cx: &mut Context<Self>,
14034    ) {
14035        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14036        self.transact(window, cx, |this, window, cx| {
14037            this.select_autoclose_pair(window, cx);
14038            this.change_selections(Default::default(), window, cx, |s| {
14039                s.move_with(|map, selection| {
14040                    if selection.is_empty() {
14041                        let mut cursor = if action.ignore_newlines {
14042                            movement::previous_word_start(map, selection.head())
14043                        } else {
14044                            movement::previous_word_start_or_newline(map, selection.head())
14045                        };
14046                        cursor = movement::adjust_greedy_deletion(
14047                            map,
14048                            selection.head(),
14049                            cursor,
14050                            action.ignore_brackets,
14051                        );
14052                        selection.set_head(cursor, SelectionGoal::None);
14053                    }
14054                });
14055            });
14056            this.insert("", window, cx);
14057        });
14058    }
14059
14060    pub fn delete_to_previous_subword_start(
14061        &mut self,
14062        _: &DeleteToPreviousSubwordStart,
14063        window: &mut Window,
14064        cx: &mut Context<Self>,
14065    ) {
14066        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14067        self.transact(window, cx, |this, window, cx| {
14068            this.select_autoclose_pair(window, cx);
14069            this.change_selections(Default::default(), window, cx, |s| {
14070                s.move_with(|map, selection| {
14071                    if selection.is_empty() {
14072                        let mut cursor = movement::previous_subword_start(map, selection.head());
14073                        cursor =
14074                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14075                        selection.set_head(cursor, SelectionGoal::None);
14076                    }
14077                });
14078            });
14079            this.insert("", window, cx);
14080        });
14081    }
14082
14083    pub fn move_to_next_word_end(
14084        &mut self,
14085        _: &MoveToNextWordEnd,
14086        window: &mut Window,
14087        cx: &mut Context<Self>,
14088    ) {
14089        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14090        self.change_selections(Default::default(), window, cx, |s| {
14091            s.move_cursors_with(|map, head, _| {
14092                (movement::next_word_end(map, head), SelectionGoal::None)
14093            });
14094        })
14095    }
14096
14097    pub fn move_to_next_subword_end(
14098        &mut self,
14099        _: &MoveToNextSubwordEnd,
14100        window: &mut Window,
14101        cx: &mut Context<Self>,
14102    ) {
14103        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14104        self.change_selections(Default::default(), window, cx, |s| {
14105            s.move_cursors_with(|map, head, _| {
14106                (movement::next_subword_end(map, head), SelectionGoal::None)
14107            });
14108        })
14109    }
14110
14111    pub fn select_to_next_word_end(
14112        &mut self,
14113        _: &SelectToNextWordEnd,
14114        window: &mut Window,
14115        cx: &mut Context<Self>,
14116    ) {
14117        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14118        self.change_selections(Default::default(), window, cx, |s| {
14119            s.move_heads_with(|map, head, _| {
14120                (movement::next_word_end(map, head), SelectionGoal::None)
14121            });
14122        })
14123    }
14124
14125    pub fn select_to_next_subword_end(
14126        &mut self,
14127        _: &SelectToNextSubwordEnd,
14128        window: &mut Window,
14129        cx: &mut Context<Self>,
14130    ) {
14131        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14132        self.change_selections(Default::default(), window, cx, |s| {
14133            s.move_heads_with(|map, head, _| {
14134                (movement::next_subword_end(map, head), SelectionGoal::None)
14135            });
14136        })
14137    }
14138
14139    pub fn delete_to_next_word_end(
14140        &mut self,
14141        action: &DeleteToNextWordEnd,
14142        window: &mut Window,
14143        cx: &mut Context<Self>,
14144    ) {
14145        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14146        self.transact(window, cx, |this, window, cx| {
14147            this.change_selections(Default::default(), window, cx, |s| {
14148                s.move_with(|map, selection| {
14149                    if selection.is_empty() {
14150                        let mut cursor = if action.ignore_newlines {
14151                            movement::next_word_end(map, selection.head())
14152                        } else {
14153                            movement::next_word_end_or_newline(map, selection.head())
14154                        };
14155                        cursor = movement::adjust_greedy_deletion(
14156                            map,
14157                            selection.head(),
14158                            cursor,
14159                            action.ignore_brackets,
14160                        );
14161                        selection.set_head(cursor, SelectionGoal::None);
14162                    }
14163                });
14164            });
14165            this.insert("", window, cx);
14166        });
14167    }
14168
14169    pub fn delete_to_next_subword_end(
14170        &mut self,
14171        _: &DeleteToNextSubwordEnd,
14172        window: &mut Window,
14173        cx: &mut Context<Self>,
14174    ) {
14175        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14176        self.transact(window, cx, |this, window, cx| {
14177            this.change_selections(Default::default(), window, cx, |s| {
14178                s.move_with(|map, selection| {
14179                    if selection.is_empty() {
14180                        let mut cursor = movement::next_subword_end(map, selection.head());
14181                        cursor =
14182                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14183                        selection.set_head(cursor, SelectionGoal::None);
14184                    }
14185                });
14186            });
14187            this.insert("", window, cx);
14188        });
14189    }
14190
14191    pub fn move_to_beginning_of_line(
14192        &mut self,
14193        action: &MoveToBeginningOfLine,
14194        window: &mut Window,
14195        cx: &mut Context<Self>,
14196    ) {
14197        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14198        self.change_selections(Default::default(), window, cx, |s| {
14199            s.move_cursors_with(|map, head, _| {
14200                (
14201                    movement::indented_line_beginning(
14202                        map,
14203                        head,
14204                        action.stop_at_soft_wraps,
14205                        action.stop_at_indent,
14206                    ),
14207                    SelectionGoal::None,
14208                )
14209            });
14210        })
14211    }
14212
14213    pub fn select_to_beginning_of_line(
14214        &mut self,
14215        action: &SelectToBeginningOfLine,
14216        window: &mut Window,
14217        cx: &mut Context<Self>,
14218    ) {
14219        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14220        self.change_selections(Default::default(), window, cx, |s| {
14221            s.move_heads_with(|map, head, _| {
14222                (
14223                    movement::indented_line_beginning(
14224                        map,
14225                        head,
14226                        action.stop_at_soft_wraps,
14227                        action.stop_at_indent,
14228                    ),
14229                    SelectionGoal::None,
14230                )
14231            });
14232        });
14233    }
14234
14235    pub fn delete_to_beginning_of_line(
14236        &mut self,
14237        action: &DeleteToBeginningOfLine,
14238        window: &mut Window,
14239        cx: &mut Context<Self>,
14240    ) {
14241        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14242        self.transact(window, cx, |this, window, cx| {
14243            this.change_selections(Default::default(), window, cx, |s| {
14244                s.move_with(|_, selection| {
14245                    selection.reversed = true;
14246                });
14247            });
14248
14249            this.select_to_beginning_of_line(
14250                &SelectToBeginningOfLine {
14251                    stop_at_soft_wraps: false,
14252                    stop_at_indent: action.stop_at_indent,
14253                },
14254                window,
14255                cx,
14256            );
14257            this.backspace(&Backspace, window, cx);
14258        });
14259    }
14260
14261    pub fn move_to_end_of_line(
14262        &mut self,
14263        action: &MoveToEndOfLine,
14264        window: &mut Window,
14265        cx: &mut Context<Self>,
14266    ) {
14267        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14268        self.change_selections(Default::default(), window, cx, |s| {
14269            s.move_cursors_with(|map, head, _| {
14270                (
14271                    movement::line_end(map, head, action.stop_at_soft_wraps),
14272                    SelectionGoal::None,
14273                )
14274            });
14275        })
14276    }
14277
14278    pub fn select_to_end_of_line(
14279        &mut self,
14280        action: &SelectToEndOfLine,
14281        window: &mut Window,
14282        cx: &mut Context<Self>,
14283    ) {
14284        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14285        self.change_selections(Default::default(), window, cx, |s| {
14286            s.move_heads_with(|map, head, _| {
14287                (
14288                    movement::line_end(map, head, action.stop_at_soft_wraps),
14289                    SelectionGoal::None,
14290                )
14291            });
14292        })
14293    }
14294
14295    pub fn delete_to_end_of_line(
14296        &mut self,
14297        _: &DeleteToEndOfLine,
14298        window: &mut Window,
14299        cx: &mut Context<Self>,
14300    ) {
14301        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14302        self.transact(window, cx, |this, window, cx| {
14303            this.select_to_end_of_line(
14304                &SelectToEndOfLine {
14305                    stop_at_soft_wraps: false,
14306                },
14307                window,
14308                cx,
14309            );
14310            this.delete(&Delete, window, cx);
14311        });
14312    }
14313
14314    pub fn cut_to_end_of_line(
14315        &mut self,
14316        action: &CutToEndOfLine,
14317        window: &mut Window,
14318        cx: &mut Context<Self>,
14319    ) {
14320        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14321        self.transact(window, cx, |this, window, cx| {
14322            this.select_to_end_of_line(
14323                &SelectToEndOfLine {
14324                    stop_at_soft_wraps: false,
14325                },
14326                window,
14327                cx,
14328            );
14329            if !action.stop_at_newlines {
14330                this.change_selections(Default::default(), window, cx, |s| {
14331                    s.move_with(|_, sel| {
14332                        if sel.is_empty() {
14333                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14334                        }
14335                    });
14336                });
14337            }
14338            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14339            let item = this.cut_common(false, window, cx);
14340            cx.write_to_clipboard(item);
14341        });
14342    }
14343
14344    pub fn move_to_start_of_paragraph(
14345        &mut self,
14346        _: &MoveToStartOfParagraph,
14347        window: &mut Window,
14348        cx: &mut Context<Self>,
14349    ) {
14350        if matches!(self.mode, EditorMode::SingleLine) {
14351            cx.propagate();
14352            return;
14353        }
14354        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14355        self.change_selections(Default::default(), window, cx, |s| {
14356            s.move_with(|map, selection| {
14357                selection.collapse_to(
14358                    movement::start_of_paragraph(map, selection.head(), 1),
14359                    SelectionGoal::None,
14360                )
14361            });
14362        })
14363    }
14364
14365    pub fn move_to_end_of_paragraph(
14366        &mut self,
14367        _: &MoveToEndOfParagraph,
14368        window: &mut Window,
14369        cx: &mut Context<Self>,
14370    ) {
14371        if matches!(self.mode, EditorMode::SingleLine) {
14372            cx.propagate();
14373            return;
14374        }
14375        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14376        self.change_selections(Default::default(), window, cx, |s| {
14377            s.move_with(|map, selection| {
14378                selection.collapse_to(
14379                    movement::end_of_paragraph(map, selection.head(), 1),
14380                    SelectionGoal::None,
14381                )
14382            });
14383        })
14384    }
14385
14386    pub fn select_to_start_of_paragraph(
14387        &mut self,
14388        _: &SelectToStartOfParagraph,
14389        window: &mut Window,
14390        cx: &mut Context<Self>,
14391    ) {
14392        if matches!(self.mode, EditorMode::SingleLine) {
14393            cx.propagate();
14394            return;
14395        }
14396        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14397        self.change_selections(Default::default(), window, cx, |s| {
14398            s.move_heads_with(|map, head, _| {
14399                (
14400                    movement::start_of_paragraph(map, head, 1),
14401                    SelectionGoal::None,
14402                )
14403            });
14404        })
14405    }
14406
14407    pub fn select_to_end_of_paragraph(
14408        &mut self,
14409        _: &SelectToEndOfParagraph,
14410        window: &mut Window,
14411        cx: &mut Context<Self>,
14412    ) {
14413        if matches!(self.mode, EditorMode::SingleLine) {
14414            cx.propagate();
14415            return;
14416        }
14417        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14418        self.change_selections(Default::default(), window, cx, |s| {
14419            s.move_heads_with(|map, head, _| {
14420                (
14421                    movement::end_of_paragraph(map, head, 1),
14422                    SelectionGoal::None,
14423                )
14424            });
14425        })
14426    }
14427
14428    pub fn move_to_start_of_excerpt(
14429        &mut self,
14430        _: &MoveToStartOfExcerpt,
14431        window: &mut Window,
14432        cx: &mut Context<Self>,
14433    ) {
14434        if matches!(self.mode, EditorMode::SingleLine) {
14435            cx.propagate();
14436            return;
14437        }
14438        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14439        self.change_selections(Default::default(), window, cx, |s| {
14440            s.move_with(|map, selection| {
14441                selection.collapse_to(
14442                    movement::start_of_excerpt(
14443                        map,
14444                        selection.head(),
14445                        workspace::searchable::Direction::Prev,
14446                    ),
14447                    SelectionGoal::None,
14448                )
14449            });
14450        })
14451    }
14452
14453    pub fn move_to_start_of_next_excerpt(
14454        &mut self,
14455        _: &MoveToStartOfNextExcerpt,
14456        window: &mut Window,
14457        cx: &mut Context<Self>,
14458    ) {
14459        if matches!(self.mode, EditorMode::SingleLine) {
14460            cx.propagate();
14461            return;
14462        }
14463
14464        self.change_selections(Default::default(), window, cx, |s| {
14465            s.move_with(|map, selection| {
14466                selection.collapse_to(
14467                    movement::start_of_excerpt(
14468                        map,
14469                        selection.head(),
14470                        workspace::searchable::Direction::Next,
14471                    ),
14472                    SelectionGoal::None,
14473                )
14474            });
14475        })
14476    }
14477
14478    pub fn move_to_end_of_excerpt(
14479        &mut self,
14480        _: &MoveToEndOfExcerpt,
14481        window: &mut Window,
14482        cx: &mut Context<Self>,
14483    ) {
14484        if matches!(self.mode, EditorMode::SingleLine) {
14485            cx.propagate();
14486            return;
14487        }
14488        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14489        self.change_selections(Default::default(), window, cx, |s| {
14490            s.move_with(|map, selection| {
14491                selection.collapse_to(
14492                    movement::end_of_excerpt(
14493                        map,
14494                        selection.head(),
14495                        workspace::searchable::Direction::Next,
14496                    ),
14497                    SelectionGoal::None,
14498                )
14499            });
14500        })
14501    }
14502
14503    pub fn move_to_end_of_previous_excerpt(
14504        &mut self,
14505        _: &MoveToEndOfPreviousExcerpt,
14506        window: &mut Window,
14507        cx: &mut Context<Self>,
14508    ) {
14509        if matches!(self.mode, EditorMode::SingleLine) {
14510            cx.propagate();
14511            return;
14512        }
14513        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14514        self.change_selections(Default::default(), window, cx, |s| {
14515            s.move_with(|map, selection| {
14516                selection.collapse_to(
14517                    movement::end_of_excerpt(
14518                        map,
14519                        selection.head(),
14520                        workspace::searchable::Direction::Prev,
14521                    ),
14522                    SelectionGoal::None,
14523                )
14524            });
14525        })
14526    }
14527
14528    pub fn select_to_start_of_excerpt(
14529        &mut self,
14530        _: &SelectToStartOfExcerpt,
14531        window: &mut Window,
14532        cx: &mut Context<Self>,
14533    ) {
14534        if matches!(self.mode, EditorMode::SingleLine) {
14535            cx.propagate();
14536            return;
14537        }
14538        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14539        self.change_selections(Default::default(), window, cx, |s| {
14540            s.move_heads_with(|map, head, _| {
14541                (
14542                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14543                    SelectionGoal::None,
14544                )
14545            });
14546        })
14547    }
14548
14549    pub fn select_to_start_of_next_excerpt(
14550        &mut self,
14551        _: &SelectToStartOfNextExcerpt,
14552        window: &mut Window,
14553        cx: &mut Context<Self>,
14554    ) {
14555        if matches!(self.mode, EditorMode::SingleLine) {
14556            cx.propagate();
14557            return;
14558        }
14559        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14560        self.change_selections(Default::default(), window, cx, |s| {
14561            s.move_heads_with(|map, head, _| {
14562                (
14563                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14564                    SelectionGoal::None,
14565                )
14566            });
14567        })
14568    }
14569
14570    pub fn select_to_end_of_excerpt(
14571        &mut self,
14572        _: &SelectToEndOfExcerpt,
14573        window: &mut Window,
14574        cx: &mut Context<Self>,
14575    ) {
14576        if matches!(self.mode, EditorMode::SingleLine) {
14577            cx.propagate();
14578            return;
14579        }
14580        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14581        self.change_selections(Default::default(), window, cx, |s| {
14582            s.move_heads_with(|map, head, _| {
14583                (
14584                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14585                    SelectionGoal::None,
14586                )
14587            });
14588        })
14589    }
14590
14591    pub fn select_to_end_of_previous_excerpt(
14592        &mut self,
14593        _: &SelectToEndOfPreviousExcerpt,
14594        window: &mut Window,
14595        cx: &mut Context<Self>,
14596    ) {
14597        if matches!(self.mode, EditorMode::SingleLine) {
14598            cx.propagate();
14599            return;
14600        }
14601        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14602        self.change_selections(Default::default(), window, cx, |s| {
14603            s.move_heads_with(|map, head, _| {
14604                (
14605                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14606                    SelectionGoal::None,
14607                )
14608            });
14609        })
14610    }
14611
14612    pub fn move_to_beginning(
14613        &mut self,
14614        _: &MoveToBeginning,
14615        window: &mut Window,
14616        cx: &mut Context<Self>,
14617    ) {
14618        if matches!(self.mode, EditorMode::SingleLine) {
14619            cx.propagate();
14620            return;
14621        }
14622        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14623        self.change_selections(Default::default(), window, cx, |s| {
14624            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14625        });
14626    }
14627
14628    pub fn select_to_beginning(
14629        &mut self,
14630        _: &SelectToBeginning,
14631        window: &mut Window,
14632        cx: &mut Context<Self>,
14633    ) {
14634        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14635        selection.set_head(Point::zero(), SelectionGoal::None);
14636        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14637        self.change_selections(Default::default(), window, cx, |s| {
14638            s.select(vec![selection]);
14639        });
14640    }
14641
14642    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14643        if matches!(self.mode, EditorMode::SingleLine) {
14644            cx.propagate();
14645            return;
14646        }
14647        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14648        let cursor = self.buffer.read(cx).read(cx).len();
14649        self.change_selections(Default::default(), window, cx, |s| {
14650            s.select_ranges(vec![cursor..cursor])
14651        });
14652    }
14653
14654    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14655        self.nav_history = nav_history;
14656    }
14657
14658    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14659        self.nav_history.as_ref()
14660    }
14661
14662    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14663        self.push_to_nav_history(
14664            self.selections.newest_anchor().head(),
14665            None,
14666            false,
14667            true,
14668            cx,
14669        );
14670    }
14671
14672    fn push_to_nav_history(
14673        &mut self,
14674        cursor_anchor: Anchor,
14675        new_position: Option<Point>,
14676        is_deactivate: bool,
14677        always: bool,
14678        cx: &mut Context<Self>,
14679    ) {
14680        if let Some(nav_history) = self.nav_history.as_mut() {
14681            let buffer = self.buffer.read(cx).read(cx);
14682            let cursor_position = cursor_anchor.to_point(&buffer);
14683            let scroll_state = self.scroll_manager.anchor();
14684            let scroll_top_row = scroll_state.top_row(&buffer);
14685            drop(buffer);
14686
14687            if let Some(new_position) = new_position {
14688                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14689                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14690                    return;
14691                }
14692            }
14693
14694            nav_history.push(
14695                Some(NavigationData {
14696                    cursor_anchor,
14697                    cursor_position,
14698                    scroll_anchor: scroll_state,
14699                    scroll_top_row,
14700                }),
14701                cx,
14702            );
14703            cx.emit(EditorEvent::PushedToNavHistory {
14704                anchor: cursor_anchor,
14705                is_deactivate,
14706            })
14707        }
14708    }
14709
14710    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14711        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14712        let buffer = self.buffer.read(cx).snapshot(cx);
14713        let mut selection = self
14714            .selections
14715            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14716        selection.set_head(buffer.len(), SelectionGoal::None);
14717        self.change_selections(Default::default(), window, cx, |s| {
14718            s.select(vec![selection]);
14719        });
14720    }
14721
14722    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14723        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14724        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14725            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14726        });
14727    }
14728
14729    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14730        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14731        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14732        let mut selections = self.selections.all::<Point>(&display_map);
14733        let max_point = display_map.buffer_snapshot().max_point();
14734        for selection in &mut selections {
14735            let rows = selection.spanned_rows(true, &display_map);
14736            selection.start = Point::new(rows.start.0, 0);
14737            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14738            selection.reversed = false;
14739        }
14740        self.change_selections(Default::default(), window, cx, |s| {
14741            s.select(selections);
14742        });
14743    }
14744
14745    pub fn split_selection_into_lines(
14746        &mut self,
14747        action: &SplitSelectionIntoLines,
14748        window: &mut Window,
14749        cx: &mut Context<Self>,
14750    ) {
14751        let selections = self
14752            .selections
14753            .all::<Point>(&self.display_snapshot(cx))
14754            .into_iter()
14755            .map(|selection| selection.start..selection.end)
14756            .collect::<Vec<_>>();
14757        self.unfold_ranges(&selections, true, true, cx);
14758
14759        let mut new_selection_ranges = Vec::new();
14760        {
14761            let buffer = self.buffer.read(cx).read(cx);
14762            for selection in selections {
14763                for row in selection.start.row..selection.end.row {
14764                    let line_start = Point::new(row, 0);
14765                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14766
14767                    if action.keep_selections {
14768                        // Keep the selection range for each line
14769                        let selection_start = if row == selection.start.row {
14770                            selection.start
14771                        } else {
14772                            line_start
14773                        };
14774                        new_selection_ranges.push(selection_start..line_end);
14775                    } else {
14776                        // Collapse to cursor at end of line
14777                        new_selection_ranges.push(line_end..line_end);
14778                    }
14779                }
14780
14781                let is_multiline_selection = selection.start.row != selection.end.row;
14782                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14783                // so this action feels more ergonomic when paired with other selection operations
14784                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14785                if !should_skip_last {
14786                    if action.keep_selections {
14787                        if is_multiline_selection {
14788                            let line_start = Point::new(selection.end.row, 0);
14789                            new_selection_ranges.push(line_start..selection.end);
14790                        } else {
14791                            new_selection_ranges.push(selection.start..selection.end);
14792                        }
14793                    } else {
14794                        new_selection_ranges.push(selection.end..selection.end);
14795                    }
14796                }
14797            }
14798        }
14799        self.change_selections(Default::default(), window, cx, |s| {
14800            s.select_ranges(new_selection_ranges);
14801        });
14802    }
14803
14804    pub fn add_selection_above(
14805        &mut self,
14806        action: &AddSelectionAbove,
14807        window: &mut Window,
14808        cx: &mut Context<Self>,
14809    ) {
14810        self.add_selection(true, action.skip_soft_wrap, window, cx);
14811    }
14812
14813    pub fn add_selection_below(
14814        &mut self,
14815        action: &AddSelectionBelow,
14816        window: &mut Window,
14817        cx: &mut Context<Self>,
14818    ) {
14819        self.add_selection(false, action.skip_soft_wrap, window, cx);
14820    }
14821
14822    fn add_selection(
14823        &mut self,
14824        above: bool,
14825        skip_soft_wrap: bool,
14826        window: &mut Window,
14827        cx: &mut Context<Self>,
14828    ) {
14829        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14830
14831        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14832        let all_selections = self.selections.all::<Point>(&display_map);
14833        let text_layout_details = self.text_layout_details(window);
14834
14835        let (mut columnar_selections, new_selections_to_columnarize) = {
14836            if let Some(state) = self.add_selections_state.as_ref() {
14837                let columnar_selection_ids: HashSet<_> = state
14838                    .groups
14839                    .iter()
14840                    .flat_map(|group| group.stack.iter())
14841                    .copied()
14842                    .collect();
14843
14844                all_selections
14845                    .into_iter()
14846                    .partition(|s| columnar_selection_ids.contains(&s.id))
14847            } else {
14848                (Vec::new(), all_selections)
14849            }
14850        };
14851
14852        let mut state = self
14853            .add_selections_state
14854            .take()
14855            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14856
14857        for selection in new_selections_to_columnarize {
14858            let range = selection.display_range(&display_map).sorted();
14859            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14860            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14861            let positions = start_x.min(end_x)..start_x.max(end_x);
14862            let mut stack = Vec::new();
14863            for row in range.start.row().0..=range.end.row().0 {
14864                if let Some(selection) = self.selections.build_columnar_selection(
14865                    &display_map,
14866                    DisplayRow(row),
14867                    &positions,
14868                    selection.reversed,
14869                    &text_layout_details,
14870                ) {
14871                    stack.push(selection.id);
14872                    columnar_selections.push(selection);
14873                }
14874            }
14875            if !stack.is_empty() {
14876                if above {
14877                    stack.reverse();
14878                }
14879                state.groups.push(AddSelectionsGroup { above, stack });
14880            }
14881        }
14882
14883        let mut final_selections = Vec::new();
14884        let end_row = if above {
14885            DisplayRow(0)
14886        } else {
14887            display_map.max_point().row()
14888        };
14889
14890        let mut last_added_item_per_group = HashMap::default();
14891        for group in state.groups.iter_mut() {
14892            if let Some(last_id) = group.stack.last() {
14893                last_added_item_per_group.insert(*last_id, group);
14894            }
14895        }
14896
14897        for selection in columnar_selections {
14898            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14899                if above == group.above {
14900                    let range = selection.display_range(&display_map).sorted();
14901                    debug_assert_eq!(range.start.row(), range.end.row());
14902                    let mut row = range.start.row();
14903                    let positions =
14904                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14905                            Pixels::from(start)..Pixels::from(end)
14906                        } else {
14907                            let start_x =
14908                                display_map.x_for_display_point(range.start, &text_layout_details);
14909                            let end_x =
14910                                display_map.x_for_display_point(range.end, &text_layout_details);
14911                            start_x.min(end_x)..start_x.max(end_x)
14912                        };
14913
14914                    let mut maybe_new_selection = None;
14915                    let direction = if above { -1 } else { 1 };
14916
14917                    while row != end_row {
14918                        if skip_soft_wrap {
14919                            row = display_map
14920                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14921                                .row();
14922                        } else if above {
14923                            row.0 -= 1;
14924                        } else {
14925                            row.0 += 1;
14926                        }
14927
14928                        if let Some(new_selection) = self.selections.build_columnar_selection(
14929                            &display_map,
14930                            row,
14931                            &positions,
14932                            selection.reversed,
14933                            &text_layout_details,
14934                        ) {
14935                            maybe_new_selection = Some(new_selection);
14936                            break;
14937                        }
14938                    }
14939
14940                    if let Some(new_selection) = maybe_new_selection {
14941                        group.stack.push(new_selection.id);
14942                        if above {
14943                            final_selections.push(new_selection);
14944                            final_selections.push(selection);
14945                        } else {
14946                            final_selections.push(selection);
14947                            final_selections.push(new_selection);
14948                        }
14949                    } else {
14950                        final_selections.push(selection);
14951                    }
14952                } else {
14953                    group.stack.pop();
14954                }
14955            } else {
14956                final_selections.push(selection);
14957            }
14958        }
14959
14960        self.change_selections(Default::default(), window, cx, |s| {
14961            s.select(final_selections);
14962        });
14963
14964        let final_selection_ids: HashSet<_> = self
14965            .selections
14966            .all::<Point>(&display_map)
14967            .iter()
14968            .map(|s| s.id)
14969            .collect();
14970        state.groups.retain_mut(|group| {
14971            // selections might get merged above so we remove invalid items from stacks
14972            group.stack.retain(|id| final_selection_ids.contains(id));
14973
14974            // single selection in stack can be treated as initial state
14975            group.stack.len() > 1
14976        });
14977
14978        if !state.groups.is_empty() {
14979            self.add_selections_state = Some(state);
14980        }
14981    }
14982
14983    pub fn insert_snippet_at_selections(
14984        &mut self,
14985        action: &InsertSnippet,
14986        window: &mut Window,
14987        cx: &mut Context<Self>,
14988    ) {
14989        self.try_insert_snippet_at_selections(action, window, cx)
14990            .log_err();
14991    }
14992
14993    fn try_insert_snippet_at_selections(
14994        &mut self,
14995        action: &InsertSnippet,
14996        window: &mut Window,
14997        cx: &mut Context<Self>,
14998    ) -> Result<()> {
14999        let insertion_ranges = self
15000            .selections
15001            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15002            .into_iter()
15003            .map(|selection| selection.range())
15004            .collect_vec();
15005
15006        let snippet = if let Some(snippet_body) = &action.snippet {
15007            if action.language.is_none() && action.name.is_none() {
15008                Snippet::parse(snippet_body)?
15009            } else {
15010                bail!("`snippet` is mutually exclusive with `language` and `name`")
15011            }
15012        } else if let Some(name) = &action.name {
15013            let project = self.project().context("no project")?;
15014            let snippet_store = project.read(cx).snippets().read(cx);
15015            let snippet = snippet_store
15016                .snippets_for(action.language.clone(), cx)
15017                .into_iter()
15018                .find(|snippet| snippet.name == *name)
15019                .context("snippet not found")?;
15020            Snippet::parse(&snippet.body)?
15021        } else {
15022            // todo(andrew): open modal to select snippet
15023            bail!("`name` or `snippet` is required")
15024        };
15025
15026        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15027    }
15028
15029    fn select_match_ranges(
15030        &mut self,
15031        range: Range<MultiBufferOffset>,
15032        reversed: bool,
15033        replace_newest: bool,
15034        auto_scroll: Option<Autoscroll>,
15035        window: &mut Window,
15036        cx: &mut Context<Editor>,
15037    ) {
15038        self.unfold_ranges(
15039            std::slice::from_ref(&range),
15040            false,
15041            auto_scroll.is_some(),
15042            cx,
15043        );
15044        let effects = if let Some(scroll) = auto_scroll {
15045            SelectionEffects::scroll(scroll)
15046        } else {
15047            SelectionEffects::no_scroll()
15048        };
15049        self.change_selections(effects, window, cx, |s| {
15050            if replace_newest {
15051                s.delete(s.newest_anchor().id);
15052            }
15053            if reversed {
15054                s.insert_range(range.end..range.start);
15055            } else {
15056                s.insert_range(range);
15057            }
15058        });
15059    }
15060
15061    pub fn select_next_match_internal(
15062        &mut self,
15063        display_map: &DisplaySnapshot,
15064        replace_newest: bool,
15065        autoscroll: Option<Autoscroll>,
15066        window: &mut Window,
15067        cx: &mut Context<Self>,
15068    ) -> Result<()> {
15069        let buffer = display_map.buffer_snapshot();
15070        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15071        if let Some(mut select_next_state) = self.select_next_state.take() {
15072            let query = &select_next_state.query;
15073            if !select_next_state.done {
15074                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15075                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15076                let mut next_selected_range = None;
15077
15078                let bytes_after_last_selection =
15079                    buffer.bytes_in_range(last_selection.end..buffer.len());
15080                let bytes_before_first_selection =
15081                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15082                let query_matches = query
15083                    .stream_find_iter(bytes_after_last_selection)
15084                    .map(|result| (last_selection.end, result))
15085                    .chain(
15086                        query
15087                            .stream_find_iter(bytes_before_first_selection)
15088                            .map(|result| (MultiBufferOffset(0), result)),
15089                    );
15090
15091                for (start_offset, query_match) in query_matches {
15092                    let query_match = query_match.unwrap(); // can only fail due to I/O
15093                    let offset_range =
15094                        start_offset + query_match.start()..start_offset + query_match.end();
15095
15096                    if !select_next_state.wordwise
15097                        || (!buffer.is_inside_word(offset_range.start, None)
15098                            && !buffer.is_inside_word(offset_range.end, None))
15099                    {
15100                        let idx = selections
15101                            .partition_point(|selection| selection.end <= offset_range.start);
15102                        let overlaps = selections
15103                            .get(idx)
15104                            .map_or(false, |selection| selection.start < offset_range.end);
15105
15106                        if !overlaps {
15107                            next_selected_range = Some(offset_range);
15108                            break;
15109                        }
15110                    }
15111                }
15112
15113                if let Some(next_selected_range) = next_selected_range {
15114                    self.select_match_ranges(
15115                        next_selected_range,
15116                        last_selection.reversed,
15117                        replace_newest,
15118                        autoscroll,
15119                        window,
15120                        cx,
15121                    );
15122                } else {
15123                    select_next_state.done = true;
15124                }
15125            }
15126
15127            self.select_next_state = Some(select_next_state);
15128        } else {
15129            let mut only_carets = true;
15130            let mut same_text_selected = true;
15131            let mut selected_text = None;
15132
15133            let mut selections_iter = selections.iter().peekable();
15134            while let Some(selection) = selections_iter.next() {
15135                if selection.start != selection.end {
15136                    only_carets = false;
15137                }
15138
15139                if same_text_selected {
15140                    if selected_text.is_none() {
15141                        selected_text =
15142                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15143                    }
15144
15145                    if let Some(next_selection) = selections_iter.peek() {
15146                        if next_selection.len() == selection.len() {
15147                            let next_selected_text = buffer
15148                                .text_for_range(next_selection.range())
15149                                .collect::<String>();
15150                            if Some(next_selected_text) != selected_text {
15151                                same_text_selected = false;
15152                                selected_text = None;
15153                            }
15154                        } else {
15155                            same_text_selected = false;
15156                            selected_text = None;
15157                        }
15158                    }
15159                }
15160            }
15161
15162            if only_carets {
15163                for selection in &mut selections {
15164                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15165                    selection.start = word_range.start;
15166                    selection.end = word_range.end;
15167                    selection.goal = SelectionGoal::None;
15168                    selection.reversed = false;
15169                    self.select_match_ranges(
15170                        selection.start..selection.end,
15171                        selection.reversed,
15172                        replace_newest,
15173                        autoscroll,
15174                        window,
15175                        cx,
15176                    );
15177                }
15178
15179                if selections.len() == 1 {
15180                    let selection = selections
15181                        .last()
15182                        .expect("ensured that there's only one selection");
15183                    let query = buffer
15184                        .text_for_range(selection.start..selection.end)
15185                        .collect::<String>();
15186                    let is_empty = query.is_empty();
15187                    let select_state = SelectNextState {
15188                        query: self.build_query(&[query], cx)?,
15189                        wordwise: true,
15190                        done: is_empty,
15191                    };
15192                    self.select_next_state = Some(select_state);
15193                } else {
15194                    self.select_next_state = None;
15195                }
15196            } else if let Some(selected_text) = selected_text {
15197                self.select_next_state = Some(SelectNextState {
15198                    query: self.build_query(&[selected_text], cx)?,
15199                    wordwise: false,
15200                    done: false,
15201                });
15202                self.select_next_match_internal(
15203                    display_map,
15204                    replace_newest,
15205                    autoscroll,
15206                    window,
15207                    cx,
15208                )?;
15209            }
15210        }
15211        Ok(())
15212    }
15213
15214    pub fn select_all_matches(
15215        &mut self,
15216        _action: &SelectAllMatches,
15217        window: &mut Window,
15218        cx: &mut Context<Self>,
15219    ) -> Result<()> {
15220        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15221
15222        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15223
15224        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15225        let Some(select_next_state) = self.select_next_state.as_mut() else {
15226            return Ok(());
15227        };
15228        if select_next_state.done {
15229            return Ok(());
15230        }
15231
15232        let mut new_selections = Vec::new();
15233
15234        let reversed = self
15235            .selections
15236            .oldest::<MultiBufferOffset>(&display_map)
15237            .reversed;
15238        let buffer = display_map.buffer_snapshot();
15239        let query_matches = select_next_state
15240            .query
15241            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15242
15243        for query_match in query_matches.into_iter() {
15244            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15245            let offset_range = if reversed {
15246                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15247            } else {
15248                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15249            };
15250
15251            if !select_next_state.wordwise
15252                || (!buffer.is_inside_word(offset_range.start, None)
15253                    && !buffer.is_inside_word(offset_range.end, None))
15254            {
15255                new_selections.push(offset_range.start..offset_range.end);
15256            }
15257        }
15258
15259        select_next_state.done = true;
15260
15261        if new_selections.is_empty() {
15262            log::error!("bug: new_selections is empty in select_all_matches");
15263            return Ok(());
15264        }
15265
15266        self.unfold_ranges(&new_selections.clone(), false, false, cx);
15267        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15268            selections.select_ranges(new_selections)
15269        });
15270
15271        Ok(())
15272    }
15273
15274    pub fn select_next(
15275        &mut self,
15276        action: &SelectNext,
15277        window: &mut Window,
15278        cx: &mut Context<Self>,
15279    ) -> Result<()> {
15280        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15281        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15282        self.select_next_match_internal(
15283            &display_map,
15284            action.replace_newest,
15285            Some(Autoscroll::newest()),
15286            window,
15287            cx,
15288        )?;
15289        Ok(())
15290    }
15291
15292    pub fn select_previous(
15293        &mut self,
15294        action: &SelectPrevious,
15295        window: &mut Window,
15296        cx: &mut Context<Self>,
15297    ) -> Result<()> {
15298        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15299        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15300        let buffer = display_map.buffer_snapshot();
15301        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15302        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15303            let query = &select_prev_state.query;
15304            if !select_prev_state.done {
15305                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15306                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15307                let mut next_selected_range = None;
15308                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15309                let bytes_before_last_selection =
15310                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15311                let bytes_after_first_selection =
15312                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15313                let query_matches = query
15314                    .stream_find_iter(bytes_before_last_selection)
15315                    .map(|result| (last_selection.start, result))
15316                    .chain(
15317                        query
15318                            .stream_find_iter(bytes_after_first_selection)
15319                            .map(|result| (buffer.len(), result)),
15320                    );
15321                for (end_offset, query_match) in query_matches {
15322                    let query_match = query_match.unwrap(); // can only fail due to I/O
15323                    let offset_range =
15324                        end_offset - query_match.end()..end_offset - query_match.start();
15325
15326                    if !select_prev_state.wordwise
15327                        || (!buffer.is_inside_word(offset_range.start, None)
15328                            && !buffer.is_inside_word(offset_range.end, None))
15329                    {
15330                        next_selected_range = Some(offset_range);
15331                        break;
15332                    }
15333                }
15334
15335                if let Some(next_selected_range) = next_selected_range {
15336                    self.select_match_ranges(
15337                        next_selected_range,
15338                        last_selection.reversed,
15339                        action.replace_newest,
15340                        Some(Autoscroll::newest()),
15341                        window,
15342                        cx,
15343                    );
15344                } else {
15345                    select_prev_state.done = true;
15346                }
15347            }
15348
15349            self.select_prev_state = Some(select_prev_state);
15350        } else {
15351            let mut only_carets = true;
15352            let mut same_text_selected = true;
15353            let mut selected_text = None;
15354
15355            let mut selections_iter = selections.iter().peekable();
15356            while let Some(selection) = selections_iter.next() {
15357                if selection.start != selection.end {
15358                    only_carets = false;
15359                }
15360
15361                if same_text_selected {
15362                    if selected_text.is_none() {
15363                        selected_text =
15364                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15365                    }
15366
15367                    if let Some(next_selection) = selections_iter.peek() {
15368                        if next_selection.len() == selection.len() {
15369                            let next_selected_text = buffer
15370                                .text_for_range(next_selection.range())
15371                                .collect::<String>();
15372                            if Some(next_selected_text) != selected_text {
15373                                same_text_selected = false;
15374                                selected_text = None;
15375                            }
15376                        } else {
15377                            same_text_selected = false;
15378                            selected_text = None;
15379                        }
15380                    }
15381                }
15382            }
15383
15384            if only_carets {
15385                for selection in &mut selections {
15386                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15387                    selection.start = word_range.start;
15388                    selection.end = word_range.end;
15389                    selection.goal = SelectionGoal::None;
15390                    selection.reversed = false;
15391                    self.select_match_ranges(
15392                        selection.start..selection.end,
15393                        selection.reversed,
15394                        action.replace_newest,
15395                        Some(Autoscroll::newest()),
15396                        window,
15397                        cx,
15398                    );
15399                }
15400                if selections.len() == 1 {
15401                    let selection = selections
15402                        .last()
15403                        .expect("ensured that there's only one selection");
15404                    let query = buffer
15405                        .text_for_range(selection.start..selection.end)
15406                        .collect::<String>();
15407                    let is_empty = query.is_empty();
15408                    let select_state = SelectNextState {
15409                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15410                        wordwise: true,
15411                        done: is_empty,
15412                    };
15413                    self.select_prev_state = Some(select_state);
15414                } else {
15415                    self.select_prev_state = None;
15416                }
15417            } else if let Some(selected_text) = selected_text {
15418                self.select_prev_state = Some(SelectNextState {
15419                    query: self
15420                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15421                    wordwise: false,
15422                    done: false,
15423                });
15424                self.select_previous(action, window, cx)?;
15425            }
15426        }
15427        Ok(())
15428    }
15429
15430    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15431    /// setting the case sensitivity based on the global
15432    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15433    /// editor's settings.
15434    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15435    where
15436        I: IntoIterator<Item = P>,
15437        P: AsRef<[u8]>,
15438    {
15439        let case_sensitive = self
15440            .select_next_is_case_sensitive
15441            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
15442
15443        let mut builder = AhoCorasickBuilder::new();
15444        builder.ascii_case_insensitive(!case_sensitive);
15445        builder.build(patterns)
15446    }
15447
15448    pub fn find_next_match(
15449        &mut self,
15450        _: &FindNextMatch,
15451        window: &mut Window,
15452        cx: &mut Context<Self>,
15453    ) -> Result<()> {
15454        let selections = self.selections.disjoint_anchors_arc();
15455        match selections.first() {
15456            Some(first) if selections.len() >= 2 => {
15457                self.change_selections(Default::default(), window, cx, |s| {
15458                    s.select_ranges([first.range()]);
15459                });
15460            }
15461            _ => self.select_next(
15462                &SelectNext {
15463                    replace_newest: true,
15464                },
15465                window,
15466                cx,
15467            )?,
15468        }
15469        Ok(())
15470    }
15471
15472    pub fn find_previous_match(
15473        &mut self,
15474        _: &FindPreviousMatch,
15475        window: &mut Window,
15476        cx: &mut Context<Self>,
15477    ) -> Result<()> {
15478        let selections = self.selections.disjoint_anchors_arc();
15479        match selections.last() {
15480            Some(last) if selections.len() >= 2 => {
15481                self.change_selections(Default::default(), window, cx, |s| {
15482                    s.select_ranges([last.range()]);
15483                });
15484            }
15485            _ => self.select_previous(
15486                &SelectPrevious {
15487                    replace_newest: true,
15488                },
15489                window,
15490                cx,
15491            )?,
15492        }
15493        Ok(())
15494    }
15495
15496    pub fn toggle_comments(
15497        &mut self,
15498        action: &ToggleComments,
15499        window: &mut Window,
15500        cx: &mut Context<Self>,
15501    ) {
15502        if self.read_only(cx) {
15503            return;
15504        }
15505        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15506        let text_layout_details = &self.text_layout_details(window);
15507        self.transact(window, cx, |this, window, cx| {
15508            let mut selections = this
15509                .selections
15510                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15511            let mut edits = Vec::new();
15512            let mut selection_edit_ranges = Vec::new();
15513            let mut last_toggled_row = None;
15514            let snapshot = this.buffer.read(cx).read(cx);
15515            let empty_str: Arc<str> = Arc::default();
15516            let mut suffixes_inserted = Vec::new();
15517            let ignore_indent = action.ignore_indent;
15518
15519            fn comment_prefix_range(
15520                snapshot: &MultiBufferSnapshot,
15521                row: MultiBufferRow,
15522                comment_prefix: &str,
15523                comment_prefix_whitespace: &str,
15524                ignore_indent: bool,
15525            ) -> Range<Point> {
15526                let indent_size = if ignore_indent {
15527                    0
15528                } else {
15529                    snapshot.indent_size_for_line(row).len
15530                };
15531
15532                let start = Point::new(row.0, indent_size);
15533
15534                let mut line_bytes = snapshot
15535                    .bytes_in_range(start..snapshot.max_point())
15536                    .flatten()
15537                    .copied();
15538
15539                // If this line currently begins with the line comment prefix, then record
15540                // the range containing the prefix.
15541                if line_bytes
15542                    .by_ref()
15543                    .take(comment_prefix.len())
15544                    .eq(comment_prefix.bytes())
15545                {
15546                    // Include any whitespace that matches the comment prefix.
15547                    let matching_whitespace_len = line_bytes
15548                        .zip(comment_prefix_whitespace.bytes())
15549                        .take_while(|(a, b)| a == b)
15550                        .count() as u32;
15551                    let end = Point::new(
15552                        start.row,
15553                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15554                    );
15555                    start..end
15556                } else {
15557                    start..start
15558                }
15559            }
15560
15561            fn comment_suffix_range(
15562                snapshot: &MultiBufferSnapshot,
15563                row: MultiBufferRow,
15564                comment_suffix: &str,
15565                comment_suffix_has_leading_space: bool,
15566            ) -> Range<Point> {
15567                let end = Point::new(row.0, snapshot.line_len(row));
15568                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15569
15570                let mut line_end_bytes = snapshot
15571                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15572                    .flatten()
15573                    .copied();
15574
15575                let leading_space_len = if suffix_start_column > 0
15576                    && line_end_bytes.next() == Some(b' ')
15577                    && comment_suffix_has_leading_space
15578                {
15579                    1
15580                } else {
15581                    0
15582                };
15583
15584                // If this line currently begins with the line comment prefix, then record
15585                // the range containing the prefix.
15586                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15587                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15588                    start..end
15589                } else {
15590                    end..end
15591                }
15592            }
15593
15594            // TODO: Handle selections that cross excerpts
15595            for selection in &mut selections {
15596                let start_column = snapshot
15597                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15598                    .len;
15599                let language = if let Some(language) =
15600                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15601                {
15602                    language
15603                } else {
15604                    continue;
15605                };
15606
15607                selection_edit_ranges.clear();
15608
15609                // If multiple selections contain a given row, avoid processing that
15610                // row more than once.
15611                let mut start_row = MultiBufferRow(selection.start.row);
15612                if last_toggled_row == Some(start_row) {
15613                    start_row = start_row.next_row();
15614                }
15615                let end_row =
15616                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15617                        MultiBufferRow(selection.end.row - 1)
15618                    } else {
15619                        MultiBufferRow(selection.end.row)
15620                    };
15621                last_toggled_row = Some(end_row);
15622
15623                if start_row > end_row {
15624                    continue;
15625                }
15626
15627                // If the language has line comments, toggle those.
15628                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15629
15630                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15631                if ignore_indent {
15632                    full_comment_prefixes = full_comment_prefixes
15633                        .into_iter()
15634                        .map(|s| Arc::from(s.trim_end()))
15635                        .collect();
15636                }
15637
15638                if !full_comment_prefixes.is_empty() {
15639                    let first_prefix = full_comment_prefixes
15640                        .first()
15641                        .expect("prefixes is non-empty");
15642                    let prefix_trimmed_lengths = full_comment_prefixes
15643                        .iter()
15644                        .map(|p| p.trim_end_matches(' ').len())
15645                        .collect::<SmallVec<[usize; 4]>>();
15646
15647                    let mut all_selection_lines_are_comments = true;
15648
15649                    for row in start_row.0..=end_row.0 {
15650                        let row = MultiBufferRow(row);
15651                        if start_row < end_row && snapshot.is_line_blank(row) {
15652                            continue;
15653                        }
15654
15655                        let prefix_range = full_comment_prefixes
15656                            .iter()
15657                            .zip(prefix_trimmed_lengths.iter().copied())
15658                            .map(|(prefix, trimmed_prefix_len)| {
15659                                comment_prefix_range(
15660                                    snapshot.deref(),
15661                                    row,
15662                                    &prefix[..trimmed_prefix_len],
15663                                    &prefix[trimmed_prefix_len..],
15664                                    ignore_indent,
15665                                )
15666                            })
15667                            .max_by_key(|range| range.end.column - range.start.column)
15668                            .expect("prefixes is non-empty");
15669
15670                        if prefix_range.is_empty() {
15671                            all_selection_lines_are_comments = false;
15672                        }
15673
15674                        selection_edit_ranges.push(prefix_range);
15675                    }
15676
15677                    if all_selection_lines_are_comments {
15678                        edits.extend(
15679                            selection_edit_ranges
15680                                .iter()
15681                                .cloned()
15682                                .map(|range| (range, empty_str.clone())),
15683                        );
15684                    } else {
15685                        let min_column = selection_edit_ranges
15686                            .iter()
15687                            .map(|range| range.start.column)
15688                            .min()
15689                            .unwrap_or(0);
15690                        edits.extend(selection_edit_ranges.iter().map(|range| {
15691                            let position = Point::new(range.start.row, min_column);
15692                            (position..position, first_prefix.clone())
15693                        }));
15694                    }
15695                } else if let Some(BlockCommentConfig {
15696                    start: full_comment_prefix,
15697                    end: comment_suffix,
15698                    ..
15699                }) = language.block_comment()
15700                {
15701                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15702                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15703                    let prefix_range = comment_prefix_range(
15704                        snapshot.deref(),
15705                        start_row,
15706                        comment_prefix,
15707                        comment_prefix_whitespace,
15708                        ignore_indent,
15709                    );
15710                    let suffix_range = comment_suffix_range(
15711                        snapshot.deref(),
15712                        end_row,
15713                        comment_suffix.trim_start_matches(' '),
15714                        comment_suffix.starts_with(' '),
15715                    );
15716
15717                    if prefix_range.is_empty() || suffix_range.is_empty() {
15718                        edits.push((
15719                            prefix_range.start..prefix_range.start,
15720                            full_comment_prefix.clone(),
15721                        ));
15722                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15723                        suffixes_inserted.push((end_row, comment_suffix.len()));
15724                    } else {
15725                        edits.push((prefix_range, empty_str.clone()));
15726                        edits.push((suffix_range, empty_str.clone()));
15727                    }
15728                } else {
15729                    continue;
15730                }
15731            }
15732
15733            drop(snapshot);
15734            this.buffer.update(cx, |buffer, cx| {
15735                buffer.edit(edits, None, cx);
15736            });
15737
15738            // Adjust selections so that they end before any comment suffixes that
15739            // were inserted.
15740            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15741            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15742            let snapshot = this.buffer.read(cx).read(cx);
15743            for selection in &mut selections {
15744                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15745                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15746                        Ordering::Less => {
15747                            suffixes_inserted.next();
15748                            continue;
15749                        }
15750                        Ordering::Greater => break,
15751                        Ordering::Equal => {
15752                            if selection.end.column == snapshot.line_len(row) {
15753                                if selection.is_empty() {
15754                                    selection.start.column -= suffix_len as u32;
15755                                }
15756                                selection.end.column -= suffix_len as u32;
15757                            }
15758                            break;
15759                        }
15760                    }
15761                }
15762            }
15763
15764            drop(snapshot);
15765            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15766
15767            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15768            let selections_on_single_row = selections.windows(2).all(|selections| {
15769                selections[0].start.row == selections[1].start.row
15770                    && selections[0].end.row == selections[1].end.row
15771                    && selections[0].start.row == selections[0].end.row
15772            });
15773            let selections_selecting = selections
15774                .iter()
15775                .any(|selection| selection.start != selection.end);
15776            let advance_downwards = action.advance_downwards
15777                && selections_on_single_row
15778                && !selections_selecting
15779                && !matches!(this.mode, EditorMode::SingleLine);
15780
15781            if advance_downwards {
15782                let snapshot = this.buffer.read(cx).snapshot(cx);
15783
15784                this.change_selections(Default::default(), window, cx, |s| {
15785                    s.move_cursors_with(|display_snapshot, display_point, _| {
15786                        let mut point = display_point.to_point(display_snapshot);
15787                        point.row += 1;
15788                        point = snapshot.clip_point(point, Bias::Left);
15789                        let display_point = point.to_display_point(display_snapshot);
15790                        let goal = SelectionGoal::HorizontalPosition(
15791                            display_snapshot
15792                                .x_for_display_point(display_point, text_layout_details)
15793                                .into(),
15794                        );
15795                        (display_point, goal)
15796                    })
15797                });
15798            }
15799        });
15800    }
15801
15802    pub fn select_enclosing_symbol(
15803        &mut self,
15804        _: &SelectEnclosingSymbol,
15805        window: &mut Window,
15806        cx: &mut Context<Self>,
15807    ) {
15808        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15809
15810        let buffer = self.buffer.read(cx).snapshot(cx);
15811        let old_selections = self
15812            .selections
15813            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15814            .into_boxed_slice();
15815
15816        fn update_selection(
15817            selection: &Selection<MultiBufferOffset>,
15818            buffer_snap: &MultiBufferSnapshot,
15819        ) -> Option<Selection<MultiBufferOffset>> {
15820            let cursor = selection.head();
15821            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15822            for symbol in symbols.iter().rev() {
15823                let start = symbol.range.start.to_offset(buffer_snap);
15824                let end = symbol.range.end.to_offset(buffer_snap);
15825                let new_range = start..end;
15826                if start < selection.start || end > selection.end {
15827                    return Some(Selection {
15828                        id: selection.id,
15829                        start: new_range.start,
15830                        end: new_range.end,
15831                        goal: SelectionGoal::None,
15832                        reversed: selection.reversed,
15833                    });
15834                }
15835            }
15836            None
15837        }
15838
15839        let mut selected_larger_symbol = false;
15840        let new_selections = old_selections
15841            .iter()
15842            .map(|selection| match update_selection(selection, &buffer) {
15843                Some(new_selection) => {
15844                    if new_selection.range() != selection.range() {
15845                        selected_larger_symbol = true;
15846                    }
15847                    new_selection
15848                }
15849                None => selection.clone(),
15850            })
15851            .collect::<Vec<_>>();
15852
15853        if selected_larger_symbol {
15854            self.change_selections(Default::default(), window, cx, |s| {
15855                s.select(new_selections);
15856            });
15857        }
15858    }
15859
15860    pub fn select_larger_syntax_node(
15861        &mut self,
15862        _: &SelectLargerSyntaxNode,
15863        window: &mut Window,
15864        cx: &mut Context<Self>,
15865    ) {
15866        let Some(visible_row_count) = self.visible_row_count() else {
15867            return;
15868        };
15869        let old_selections: Box<[_]> = self
15870            .selections
15871            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15872            .into();
15873        if old_selections.is_empty() {
15874            return;
15875        }
15876
15877        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15878
15879        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15880        let buffer = self.buffer.read(cx).snapshot(cx);
15881
15882        let mut selected_larger_node = false;
15883        let mut new_selections = old_selections
15884            .iter()
15885            .map(|selection| {
15886                let old_range = selection.start..selection.end;
15887
15888                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15889                    // manually select word at selection
15890                    if ["string_content", "inline"].contains(&node.kind()) {
15891                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15892                        // ignore if word is already selected
15893                        if !word_range.is_empty() && old_range != word_range {
15894                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15895                            // only select word if start and end point belongs to same word
15896                            if word_range == last_word_range {
15897                                selected_larger_node = true;
15898                                return Selection {
15899                                    id: selection.id,
15900                                    start: word_range.start,
15901                                    end: word_range.end,
15902                                    goal: SelectionGoal::None,
15903                                    reversed: selection.reversed,
15904                                };
15905                            }
15906                        }
15907                    }
15908                }
15909
15910                let mut new_range = old_range.clone();
15911                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15912                    new_range = range;
15913                    if !node.is_named() {
15914                        continue;
15915                    }
15916                    if !display_map.intersects_fold(new_range.start)
15917                        && !display_map.intersects_fold(new_range.end)
15918                    {
15919                        break;
15920                    }
15921                }
15922
15923                selected_larger_node |= new_range != old_range;
15924                Selection {
15925                    id: selection.id,
15926                    start: new_range.start,
15927                    end: new_range.end,
15928                    goal: SelectionGoal::None,
15929                    reversed: selection.reversed,
15930                }
15931            })
15932            .collect::<Vec<_>>();
15933
15934        if !selected_larger_node {
15935            return; // don't put this call in the history
15936        }
15937
15938        // scroll based on transformation done to the last selection created by the user
15939        let (last_old, last_new) = old_selections
15940            .last()
15941            .zip(new_selections.last().cloned())
15942            .expect("old_selections isn't empty");
15943
15944        // revert selection
15945        let is_selection_reversed = {
15946            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15947            new_selections.last_mut().expect("checked above").reversed =
15948                should_newest_selection_be_reversed;
15949            should_newest_selection_be_reversed
15950        };
15951
15952        if selected_larger_node {
15953            self.select_syntax_node_history.disable_clearing = true;
15954            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15955                s.select(new_selections.clone());
15956            });
15957            self.select_syntax_node_history.disable_clearing = false;
15958        }
15959
15960        let start_row = last_new.start.to_display_point(&display_map).row().0;
15961        let end_row = last_new.end.to_display_point(&display_map).row().0;
15962        let selection_height = end_row - start_row + 1;
15963        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15964
15965        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15966        let scroll_behavior = if fits_on_the_screen {
15967            self.request_autoscroll(Autoscroll::fit(), cx);
15968            SelectSyntaxNodeScrollBehavior::FitSelection
15969        } else if is_selection_reversed {
15970            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15971            SelectSyntaxNodeScrollBehavior::CursorTop
15972        } else {
15973            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15974            SelectSyntaxNodeScrollBehavior::CursorBottom
15975        };
15976
15977        self.select_syntax_node_history.push((
15978            old_selections,
15979            scroll_behavior,
15980            is_selection_reversed,
15981        ));
15982    }
15983
15984    pub fn select_smaller_syntax_node(
15985        &mut self,
15986        _: &SelectSmallerSyntaxNode,
15987        window: &mut Window,
15988        cx: &mut Context<Self>,
15989    ) {
15990        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15991
15992        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15993            self.select_syntax_node_history.pop()
15994        {
15995            if let Some(selection) = selections.last_mut() {
15996                selection.reversed = is_selection_reversed;
15997            }
15998
15999            self.select_syntax_node_history.disable_clearing = true;
16000            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16001                s.select(selections.to_vec());
16002            });
16003            self.select_syntax_node_history.disable_clearing = false;
16004
16005            match scroll_behavior {
16006                SelectSyntaxNodeScrollBehavior::CursorTop => {
16007                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16008                }
16009                SelectSyntaxNodeScrollBehavior::FitSelection => {
16010                    self.request_autoscroll(Autoscroll::fit(), cx);
16011                }
16012                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16013                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16014                }
16015            }
16016        }
16017    }
16018
16019    pub fn unwrap_syntax_node(
16020        &mut self,
16021        _: &UnwrapSyntaxNode,
16022        window: &mut Window,
16023        cx: &mut Context<Self>,
16024    ) {
16025        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16026
16027        let buffer = self.buffer.read(cx).snapshot(cx);
16028        let selections = self
16029            .selections
16030            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16031            .into_iter()
16032            // subtracting the offset requires sorting
16033            .sorted_by_key(|i| i.start);
16034
16035        let full_edits = selections
16036            .into_iter()
16037            .filter_map(|selection| {
16038                let child = if selection.is_empty()
16039                    && let Some((_, ancestor_range)) =
16040                        buffer.syntax_ancestor(selection.start..selection.end)
16041                {
16042                    ancestor_range
16043                } else {
16044                    selection.range()
16045                };
16046
16047                let mut parent = child.clone();
16048                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16049                    parent = ancestor_range;
16050                    if parent.start < child.start || parent.end > child.end {
16051                        break;
16052                    }
16053                }
16054
16055                if parent == child {
16056                    return None;
16057                }
16058                let text = buffer.text_for_range(child).collect::<String>();
16059                Some((selection.id, parent, text))
16060            })
16061            .collect::<Vec<_>>();
16062        if full_edits.is_empty() {
16063            return;
16064        }
16065
16066        self.transact(window, cx, |this, window, cx| {
16067            this.buffer.update(cx, |buffer, cx| {
16068                buffer.edit(
16069                    full_edits
16070                        .iter()
16071                        .map(|(_, p, t)| (p.clone(), t.clone()))
16072                        .collect::<Vec<_>>(),
16073                    None,
16074                    cx,
16075                );
16076            });
16077            this.change_selections(Default::default(), window, cx, |s| {
16078                let mut offset = 0;
16079                let mut selections = vec![];
16080                for (id, parent, text) in full_edits {
16081                    let start = parent.start - offset;
16082                    offset += (parent.end - parent.start) - text.len();
16083                    selections.push(Selection {
16084                        id,
16085                        start,
16086                        end: start + text.len(),
16087                        reversed: false,
16088                        goal: Default::default(),
16089                    });
16090                }
16091                s.select(selections);
16092            });
16093        });
16094    }
16095
16096    pub fn select_next_syntax_node(
16097        &mut self,
16098        _: &SelectNextSyntaxNode,
16099        window: &mut Window,
16100        cx: &mut Context<Self>,
16101    ) {
16102        let old_selections: Box<[_]> = self
16103            .selections
16104            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16105            .into();
16106        if old_selections.is_empty() {
16107            return;
16108        }
16109
16110        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16111
16112        let buffer = self.buffer.read(cx).snapshot(cx);
16113        let mut selected_sibling = false;
16114
16115        let new_selections = old_selections
16116            .iter()
16117            .map(|selection| {
16118                let old_range = selection.start..selection.end;
16119
16120                let old_range =
16121                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16122                let excerpt = buffer.excerpt_containing(old_range.clone());
16123
16124                if let Some(mut excerpt) = excerpt
16125                    && let Some(node) = excerpt
16126                        .buffer()
16127                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16128                {
16129                    let new_range = excerpt.map_range_from_buffer(
16130                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16131                    );
16132                    selected_sibling = true;
16133                    Selection {
16134                        id: selection.id,
16135                        start: new_range.start,
16136                        end: new_range.end,
16137                        goal: SelectionGoal::None,
16138                        reversed: selection.reversed,
16139                    }
16140                } else {
16141                    selection.clone()
16142                }
16143            })
16144            .collect::<Vec<_>>();
16145
16146        if selected_sibling {
16147            self.change_selections(
16148                SelectionEffects::scroll(Autoscroll::fit()),
16149                window,
16150                cx,
16151                |s| {
16152                    s.select(new_selections);
16153                },
16154            );
16155        }
16156    }
16157
16158    pub fn select_prev_syntax_node(
16159        &mut self,
16160        _: &SelectPreviousSyntaxNode,
16161        window: &mut Window,
16162        cx: &mut Context<Self>,
16163    ) {
16164        let old_selections: Box<[_]> = self
16165            .selections
16166            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16167            .into();
16168        if old_selections.is_empty() {
16169            return;
16170        }
16171
16172        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16173
16174        let buffer = self.buffer.read(cx).snapshot(cx);
16175        let mut selected_sibling = false;
16176
16177        let new_selections = old_selections
16178            .iter()
16179            .map(|selection| {
16180                let old_range = selection.start..selection.end;
16181                let old_range =
16182                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16183                let excerpt = buffer.excerpt_containing(old_range.clone());
16184
16185                if let Some(mut excerpt) = excerpt
16186                    && let Some(node) = excerpt
16187                        .buffer()
16188                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16189                {
16190                    let new_range = excerpt.map_range_from_buffer(
16191                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16192                    );
16193                    selected_sibling = true;
16194                    Selection {
16195                        id: selection.id,
16196                        start: new_range.start,
16197                        end: new_range.end,
16198                        goal: SelectionGoal::None,
16199                        reversed: selection.reversed,
16200                    }
16201                } else {
16202                    selection.clone()
16203                }
16204            })
16205            .collect::<Vec<_>>();
16206
16207        if selected_sibling {
16208            self.change_selections(
16209                SelectionEffects::scroll(Autoscroll::fit()),
16210                window,
16211                cx,
16212                |s| {
16213                    s.select(new_selections);
16214                },
16215            );
16216        }
16217    }
16218
16219    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16220        if !EditorSettings::get_global(cx).gutter.runnables {
16221            self.clear_tasks();
16222            return Task::ready(());
16223        }
16224        let project = self.project().map(Entity::downgrade);
16225        let task_sources = self.lsp_task_sources(cx);
16226        let multi_buffer = self.buffer.downgrade();
16227        cx.spawn_in(window, async move |editor, cx| {
16228            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16229            let Some(project) = project.and_then(|p| p.upgrade()) else {
16230                return;
16231            };
16232            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16233                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16234            }) else {
16235                return;
16236            };
16237
16238            let hide_runnables = project
16239                .update(cx, |project, _| project.is_via_collab())
16240                .unwrap_or(true);
16241            if hide_runnables {
16242                return;
16243            }
16244            let new_rows =
16245                cx.background_spawn({
16246                    let snapshot = display_snapshot.clone();
16247                    async move {
16248                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16249                    }
16250                })
16251                    .await;
16252            let Ok(lsp_tasks) =
16253                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16254            else {
16255                return;
16256            };
16257            let lsp_tasks = lsp_tasks.await;
16258
16259            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16260                lsp_tasks
16261                    .into_iter()
16262                    .flat_map(|(kind, tasks)| {
16263                        tasks.into_iter().filter_map(move |(location, task)| {
16264                            Some((kind.clone(), location?, task))
16265                        })
16266                    })
16267                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16268                        let buffer = location.target.buffer;
16269                        let buffer_snapshot = buffer.read(cx).snapshot();
16270                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16271                            |(excerpt_id, snapshot, _)| {
16272                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16273                                    display_snapshot
16274                                        .buffer_snapshot()
16275                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16276                                } else {
16277                                    None
16278                                }
16279                            },
16280                        );
16281                        if let Some(offset) = offset {
16282                            let task_buffer_range =
16283                                location.target.range.to_point(&buffer_snapshot);
16284                            let context_buffer_range =
16285                                task_buffer_range.to_offset(&buffer_snapshot);
16286                            let context_range = BufferOffset(context_buffer_range.start)
16287                                ..BufferOffset(context_buffer_range.end);
16288
16289                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16290                                .or_insert_with(|| RunnableTasks {
16291                                    templates: Vec::new(),
16292                                    offset,
16293                                    column: task_buffer_range.start.column,
16294                                    extra_variables: HashMap::default(),
16295                                    context_range,
16296                                })
16297                                .templates
16298                                .push((kind, task.original_task().clone()));
16299                        }
16300
16301                        acc
16302                    })
16303            }) else {
16304                return;
16305            };
16306
16307            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16308                buffer.language_settings(cx).tasks.prefer_lsp
16309            }) else {
16310                return;
16311            };
16312
16313            let rows = Self::runnable_rows(
16314                project,
16315                display_snapshot,
16316                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16317                new_rows,
16318                cx.clone(),
16319            )
16320            .await;
16321            editor
16322                .update(cx, |editor, _| {
16323                    editor.clear_tasks();
16324                    for (key, mut value) in rows {
16325                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16326                            value.templates.extend(lsp_tasks.templates);
16327                        }
16328
16329                        editor.insert_tasks(key, value);
16330                    }
16331                    for (key, value) in lsp_tasks_by_rows {
16332                        editor.insert_tasks(key, value);
16333                    }
16334                })
16335                .ok();
16336        })
16337    }
16338    fn fetch_runnable_ranges(
16339        snapshot: &DisplaySnapshot,
16340        range: Range<Anchor>,
16341    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16342        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16343    }
16344
16345    fn runnable_rows(
16346        project: Entity<Project>,
16347        snapshot: DisplaySnapshot,
16348        prefer_lsp: bool,
16349        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16350        cx: AsyncWindowContext,
16351    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16352        cx.spawn(async move |cx| {
16353            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16354            for (run_range, mut runnable) in runnable_ranges {
16355                let Some(tasks) = cx
16356                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16357                    .ok()
16358                else {
16359                    continue;
16360                };
16361                let mut tasks = tasks.await;
16362
16363                if prefer_lsp {
16364                    tasks.retain(|(task_kind, _)| {
16365                        !matches!(task_kind, TaskSourceKind::Language { .. })
16366                    });
16367                }
16368                if tasks.is_empty() {
16369                    continue;
16370                }
16371
16372                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16373                let Some(row) = snapshot
16374                    .buffer_snapshot()
16375                    .buffer_line_for_row(MultiBufferRow(point.row))
16376                    .map(|(_, range)| range.start.row)
16377                else {
16378                    continue;
16379                };
16380
16381                let context_range =
16382                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16383                runnable_rows.push((
16384                    (runnable.buffer_id, row),
16385                    RunnableTasks {
16386                        templates: tasks,
16387                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16388                        context_range,
16389                        column: point.column,
16390                        extra_variables: runnable.extra_captures,
16391                    },
16392                ));
16393            }
16394            runnable_rows
16395        })
16396    }
16397
16398    fn templates_with_tags(
16399        project: &Entity<Project>,
16400        runnable: &mut Runnable,
16401        cx: &mut App,
16402    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16403        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16404            let (worktree_id, file) = project
16405                .buffer_for_id(runnable.buffer, cx)
16406                .and_then(|buffer| buffer.read(cx).file())
16407                .map(|file| (file.worktree_id(cx), file.clone()))
16408                .unzip();
16409
16410            (
16411                project.task_store().read(cx).task_inventory().cloned(),
16412                worktree_id,
16413                file,
16414            )
16415        });
16416
16417        let tags = mem::take(&mut runnable.tags);
16418        let language = runnable.language.clone();
16419        cx.spawn(async move |cx| {
16420            let mut templates_with_tags = Vec::new();
16421            if let Some(inventory) = inventory {
16422                for RunnableTag(tag) in tags {
16423                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16424                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16425                    }) else {
16426                        return templates_with_tags;
16427                    };
16428                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16429                        move |(_, template)| {
16430                            template.tags.iter().any(|source_tag| source_tag == &tag)
16431                        },
16432                    ));
16433                }
16434            }
16435            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16436
16437            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16438                // Strongest source wins; if we have worktree tag binding, prefer that to
16439                // global and language bindings;
16440                // if we have a global binding, prefer that to language binding.
16441                let first_mismatch = templates_with_tags
16442                    .iter()
16443                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16444                if let Some(index) = first_mismatch {
16445                    templates_with_tags.truncate(index);
16446                }
16447            }
16448
16449            templates_with_tags
16450        })
16451    }
16452
16453    pub fn move_to_enclosing_bracket(
16454        &mut self,
16455        _: &MoveToEnclosingBracket,
16456        window: &mut Window,
16457        cx: &mut Context<Self>,
16458    ) {
16459        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16460        self.change_selections(Default::default(), window, cx, |s| {
16461            s.move_offsets_with(|snapshot, selection| {
16462                let Some(enclosing_bracket_ranges) =
16463                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16464                else {
16465                    return;
16466                };
16467
16468                let mut best_length = usize::MAX;
16469                let mut best_inside = false;
16470                let mut best_in_bracket_range = false;
16471                let mut best_destination = None;
16472                for (open, close) in enclosing_bracket_ranges {
16473                    let close = close.to_inclusive();
16474                    let length = *close.end() - open.start;
16475                    let inside = selection.start >= open.end && selection.end <= *close.start();
16476                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16477                        || close.contains(&selection.head());
16478
16479                    // If best is next to a bracket and current isn't, skip
16480                    if !in_bracket_range && best_in_bracket_range {
16481                        continue;
16482                    }
16483
16484                    // Prefer smaller lengths unless best is inside and current isn't
16485                    if length > best_length && (best_inside || !inside) {
16486                        continue;
16487                    }
16488
16489                    best_length = length;
16490                    best_inside = inside;
16491                    best_in_bracket_range = in_bracket_range;
16492                    best_destination = Some(
16493                        if close.contains(&selection.start) && close.contains(&selection.end) {
16494                            if inside { open.end } else { open.start }
16495                        } else if inside {
16496                            *close.start()
16497                        } else {
16498                            *close.end()
16499                        },
16500                    );
16501                }
16502
16503                if let Some(destination) = best_destination {
16504                    selection.collapse_to(destination, SelectionGoal::None);
16505                }
16506            })
16507        });
16508    }
16509
16510    pub fn undo_selection(
16511        &mut self,
16512        _: &UndoSelection,
16513        window: &mut Window,
16514        cx: &mut Context<Self>,
16515    ) {
16516        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16517        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16518            self.selection_history.mode = SelectionHistoryMode::Undoing;
16519            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16520                this.end_selection(window, cx);
16521                this.change_selections(
16522                    SelectionEffects::scroll(Autoscroll::newest()),
16523                    window,
16524                    cx,
16525                    |s| s.select_anchors(entry.selections.to_vec()),
16526                );
16527            });
16528            self.selection_history.mode = SelectionHistoryMode::Normal;
16529
16530            self.select_next_state = entry.select_next_state;
16531            self.select_prev_state = entry.select_prev_state;
16532            self.add_selections_state = entry.add_selections_state;
16533        }
16534    }
16535
16536    pub fn redo_selection(
16537        &mut self,
16538        _: &RedoSelection,
16539        window: &mut Window,
16540        cx: &mut Context<Self>,
16541    ) {
16542        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16543        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16544            self.selection_history.mode = SelectionHistoryMode::Redoing;
16545            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16546                this.end_selection(window, cx);
16547                this.change_selections(
16548                    SelectionEffects::scroll(Autoscroll::newest()),
16549                    window,
16550                    cx,
16551                    |s| s.select_anchors(entry.selections.to_vec()),
16552                );
16553            });
16554            self.selection_history.mode = SelectionHistoryMode::Normal;
16555
16556            self.select_next_state = entry.select_next_state;
16557            self.select_prev_state = entry.select_prev_state;
16558            self.add_selections_state = entry.add_selections_state;
16559        }
16560    }
16561
16562    pub fn expand_excerpts(
16563        &mut self,
16564        action: &ExpandExcerpts,
16565        _: &mut Window,
16566        cx: &mut Context<Self>,
16567    ) {
16568        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16569    }
16570
16571    pub fn expand_excerpts_down(
16572        &mut self,
16573        action: &ExpandExcerptsDown,
16574        _: &mut Window,
16575        cx: &mut Context<Self>,
16576    ) {
16577        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16578    }
16579
16580    pub fn expand_excerpts_up(
16581        &mut self,
16582        action: &ExpandExcerptsUp,
16583        _: &mut Window,
16584        cx: &mut Context<Self>,
16585    ) {
16586        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16587    }
16588
16589    pub fn expand_excerpts_for_direction(
16590        &mut self,
16591        lines: u32,
16592        direction: ExpandExcerptDirection,
16593
16594        cx: &mut Context<Self>,
16595    ) {
16596        let selections = self.selections.disjoint_anchors_arc();
16597
16598        let lines = if lines == 0 {
16599            EditorSettings::get_global(cx).expand_excerpt_lines
16600        } else {
16601            lines
16602        };
16603
16604        self.buffer.update(cx, |buffer, cx| {
16605            let snapshot = buffer.snapshot(cx);
16606            let mut excerpt_ids = selections
16607                .iter()
16608                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16609                .collect::<Vec<_>>();
16610            excerpt_ids.sort();
16611            excerpt_ids.dedup();
16612            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16613        })
16614    }
16615
16616    pub fn expand_excerpt(
16617        &mut self,
16618        excerpt: ExcerptId,
16619        direction: ExpandExcerptDirection,
16620        window: &mut Window,
16621        cx: &mut Context<Self>,
16622    ) {
16623        let current_scroll_position = self.scroll_position(cx);
16624        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16625        let mut scroll = None;
16626
16627        if direction == ExpandExcerptDirection::Down {
16628            let multi_buffer = self.buffer.read(cx);
16629            let snapshot = multi_buffer.snapshot(cx);
16630            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16631                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16632                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16633            {
16634                let buffer_snapshot = buffer.read(cx).snapshot();
16635                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16636                let last_row = buffer_snapshot.max_point().row;
16637                let lines_below = last_row.saturating_sub(excerpt_end_row);
16638                if lines_below >= lines_to_expand {
16639                    scroll = Some(
16640                        current_scroll_position
16641                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16642                    );
16643                }
16644            }
16645        }
16646        if direction == ExpandExcerptDirection::Up
16647            && self
16648                .buffer
16649                .read(cx)
16650                .snapshot(cx)
16651                .excerpt_before(excerpt)
16652                .is_none()
16653        {
16654            scroll = Some(current_scroll_position);
16655        }
16656
16657        self.buffer.update(cx, |buffer, cx| {
16658            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16659        });
16660
16661        if let Some(new_scroll_position) = scroll {
16662            self.set_scroll_position(new_scroll_position, window, cx);
16663        }
16664    }
16665
16666    pub fn go_to_singleton_buffer_point(
16667        &mut self,
16668        point: Point,
16669        window: &mut Window,
16670        cx: &mut Context<Self>,
16671    ) {
16672        self.go_to_singleton_buffer_range(point..point, window, cx);
16673    }
16674
16675    pub fn go_to_singleton_buffer_range(
16676        &mut self,
16677        range: Range<Point>,
16678        window: &mut Window,
16679        cx: &mut Context<Self>,
16680    ) {
16681        let multibuffer = self.buffer().read(cx);
16682        let Some(buffer) = multibuffer.as_singleton() else {
16683            return;
16684        };
16685        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16686            return;
16687        };
16688        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16689            return;
16690        };
16691        self.change_selections(
16692            SelectionEffects::default().nav_history(true),
16693            window,
16694            cx,
16695            |s| s.select_anchor_ranges([start..end]),
16696        );
16697    }
16698
16699    pub fn go_to_diagnostic(
16700        &mut self,
16701        action: &GoToDiagnostic,
16702        window: &mut Window,
16703        cx: &mut Context<Self>,
16704    ) {
16705        if !self.diagnostics_enabled() {
16706            return;
16707        }
16708        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16709        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16710    }
16711
16712    pub fn go_to_prev_diagnostic(
16713        &mut self,
16714        action: &GoToPreviousDiagnostic,
16715        window: &mut Window,
16716        cx: &mut Context<Self>,
16717    ) {
16718        if !self.diagnostics_enabled() {
16719            return;
16720        }
16721        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16722        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16723    }
16724
16725    pub fn go_to_diagnostic_impl(
16726        &mut self,
16727        direction: Direction,
16728        severity: GoToDiagnosticSeverityFilter,
16729        window: &mut Window,
16730        cx: &mut Context<Self>,
16731    ) {
16732        let buffer = self.buffer.read(cx).snapshot(cx);
16733        let selection = self
16734            .selections
16735            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16736
16737        let mut active_group_id = None;
16738        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16739            && active_group.active_range.start.to_offset(&buffer) == selection.start
16740        {
16741            active_group_id = Some(active_group.group_id);
16742        }
16743
16744        fn filtered<'a>(
16745            severity: GoToDiagnosticSeverityFilter,
16746            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16747        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16748            diagnostics
16749                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16750                .filter(|entry| entry.range.start != entry.range.end)
16751                .filter(|entry| !entry.diagnostic.is_unnecessary)
16752        }
16753
16754        let before = filtered(
16755            severity,
16756            buffer
16757                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16758                .filter(|entry| entry.range.start <= selection.start),
16759        );
16760        let after = filtered(
16761            severity,
16762            buffer
16763                .diagnostics_in_range(selection.start..buffer.len())
16764                .filter(|entry| entry.range.start >= selection.start),
16765        );
16766
16767        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16768        if direction == Direction::Prev {
16769            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16770            {
16771                for diagnostic in prev_diagnostics.into_iter().rev() {
16772                    if diagnostic.range.start != selection.start
16773                        || active_group_id
16774                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16775                    {
16776                        found = Some(diagnostic);
16777                        break 'outer;
16778                    }
16779                }
16780            }
16781        } else {
16782            for diagnostic in after.chain(before) {
16783                if diagnostic.range.start != selection.start
16784                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16785                {
16786                    found = Some(diagnostic);
16787                    break;
16788                }
16789            }
16790        }
16791        let Some(next_diagnostic) = found else {
16792            return;
16793        };
16794
16795        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16796        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16797            return;
16798        };
16799        let snapshot = self.snapshot(window, cx);
16800        if snapshot.intersects_fold(next_diagnostic.range.start) {
16801            self.unfold_ranges(
16802                std::slice::from_ref(&next_diagnostic.range),
16803                true,
16804                false,
16805                cx,
16806            );
16807        }
16808        self.change_selections(Default::default(), window, cx, |s| {
16809            s.select_ranges(vec![
16810                next_diagnostic.range.start..next_diagnostic.range.start,
16811            ])
16812        });
16813        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16814        self.refresh_edit_prediction(false, true, window, cx);
16815    }
16816
16817    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16818        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16819        let snapshot = self.snapshot(window, cx);
16820        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16821        self.go_to_hunk_before_or_after_position(
16822            &snapshot,
16823            selection.head(),
16824            Direction::Next,
16825            window,
16826            cx,
16827        );
16828    }
16829
16830    pub fn go_to_hunk_before_or_after_position(
16831        &mut self,
16832        snapshot: &EditorSnapshot,
16833        position: Point,
16834        direction: Direction,
16835        window: &mut Window,
16836        cx: &mut Context<Editor>,
16837    ) {
16838        let row = if direction == Direction::Next {
16839            self.hunk_after_position(snapshot, position)
16840                .map(|hunk| hunk.row_range.start)
16841        } else {
16842            self.hunk_before_position(snapshot, position)
16843        };
16844
16845        if let Some(row) = row {
16846            let destination = Point::new(row.0, 0);
16847            let autoscroll = Autoscroll::center();
16848
16849            self.unfold_ranges(&[destination..destination], false, false, cx);
16850            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16851                s.select_ranges([destination..destination]);
16852            });
16853        }
16854    }
16855
16856    fn hunk_after_position(
16857        &mut self,
16858        snapshot: &EditorSnapshot,
16859        position: Point,
16860    ) -> Option<MultiBufferDiffHunk> {
16861        snapshot
16862            .buffer_snapshot()
16863            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16864            .find(|hunk| hunk.row_range.start.0 > position.row)
16865            .or_else(|| {
16866                snapshot
16867                    .buffer_snapshot()
16868                    .diff_hunks_in_range(Point::zero()..position)
16869                    .find(|hunk| hunk.row_range.end.0 < position.row)
16870            })
16871    }
16872
16873    fn go_to_prev_hunk(
16874        &mut self,
16875        _: &GoToPreviousHunk,
16876        window: &mut Window,
16877        cx: &mut Context<Self>,
16878    ) {
16879        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16880        let snapshot = self.snapshot(window, cx);
16881        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16882        self.go_to_hunk_before_or_after_position(
16883            &snapshot,
16884            selection.head(),
16885            Direction::Prev,
16886            window,
16887            cx,
16888        );
16889    }
16890
16891    fn hunk_before_position(
16892        &mut self,
16893        snapshot: &EditorSnapshot,
16894        position: Point,
16895    ) -> Option<MultiBufferRow> {
16896        snapshot
16897            .buffer_snapshot()
16898            .diff_hunk_before(position)
16899            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16900    }
16901
16902    fn go_to_next_change(
16903        &mut self,
16904        _: &GoToNextChange,
16905        window: &mut Window,
16906        cx: &mut Context<Self>,
16907    ) {
16908        if let Some(selections) = self
16909            .change_list
16910            .next_change(1, Direction::Next)
16911            .map(|s| s.to_vec())
16912        {
16913            self.change_selections(Default::default(), window, cx, |s| {
16914                let map = s.display_snapshot();
16915                s.select_display_ranges(selections.iter().map(|a| {
16916                    let point = a.to_display_point(&map);
16917                    point..point
16918                }))
16919            })
16920        }
16921    }
16922
16923    fn go_to_previous_change(
16924        &mut self,
16925        _: &GoToPreviousChange,
16926        window: &mut Window,
16927        cx: &mut Context<Self>,
16928    ) {
16929        if let Some(selections) = self
16930            .change_list
16931            .next_change(1, Direction::Prev)
16932            .map(|s| s.to_vec())
16933        {
16934            self.change_selections(Default::default(), window, cx, |s| {
16935                let map = s.display_snapshot();
16936                s.select_display_ranges(selections.iter().map(|a| {
16937                    let point = a.to_display_point(&map);
16938                    point..point
16939                }))
16940            })
16941        }
16942    }
16943
16944    pub fn go_to_next_document_highlight(
16945        &mut self,
16946        _: &GoToNextDocumentHighlight,
16947        window: &mut Window,
16948        cx: &mut Context<Self>,
16949    ) {
16950        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16951    }
16952
16953    pub fn go_to_prev_document_highlight(
16954        &mut self,
16955        _: &GoToPreviousDocumentHighlight,
16956        window: &mut Window,
16957        cx: &mut Context<Self>,
16958    ) {
16959        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16960    }
16961
16962    pub fn go_to_document_highlight_before_or_after_position(
16963        &mut self,
16964        direction: Direction,
16965        window: &mut Window,
16966        cx: &mut Context<Editor>,
16967    ) {
16968        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16969        let snapshot = self.snapshot(window, cx);
16970        let buffer = &snapshot.buffer_snapshot();
16971        let position = self
16972            .selections
16973            .newest::<Point>(&snapshot.display_snapshot)
16974            .head();
16975        let anchor_position = buffer.anchor_after(position);
16976
16977        // Get all document highlights (both read and write)
16978        let mut all_highlights = Vec::new();
16979
16980        if let Some((_, read_highlights)) = self
16981            .background_highlights
16982            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16983        {
16984            all_highlights.extend(read_highlights.iter());
16985        }
16986
16987        if let Some((_, write_highlights)) = self
16988            .background_highlights
16989            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16990        {
16991            all_highlights.extend(write_highlights.iter());
16992        }
16993
16994        if all_highlights.is_empty() {
16995            return;
16996        }
16997
16998        // Sort highlights by position
16999        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17000
17001        let target_highlight = match direction {
17002            Direction::Next => {
17003                // Find the first highlight after the current position
17004                all_highlights
17005                    .iter()
17006                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17007            }
17008            Direction::Prev => {
17009                // Find the last highlight before the current position
17010                all_highlights
17011                    .iter()
17012                    .rev()
17013                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17014            }
17015        };
17016
17017        if let Some(highlight) = target_highlight {
17018            let destination = highlight.start.to_point(buffer);
17019            let autoscroll = Autoscroll::center();
17020
17021            self.unfold_ranges(&[destination..destination], false, false, cx);
17022            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17023                s.select_ranges([destination..destination]);
17024            });
17025        }
17026    }
17027
17028    fn go_to_line<T: 'static>(
17029        &mut self,
17030        position: Anchor,
17031        highlight_color: Option<Hsla>,
17032        window: &mut Window,
17033        cx: &mut Context<Self>,
17034    ) {
17035        let snapshot = self.snapshot(window, cx).display_snapshot;
17036        let position = position.to_point(&snapshot.buffer_snapshot());
17037        let start = snapshot
17038            .buffer_snapshot()
17039            .clip_point(Point::new(position.row, 0), Bias::Left);
17040        let end = start + Point::new(1, 0);
17041        let start = snapshot.buffer_snapshot().anchor_before(start);
17042        let end = snapshot.buffer_snapshot().anchor_before(end);
17043
17044        self.highlight_rows::<T>(
17045            start..end,
17046            highlight_color
17047                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17048            Default::default(),
17049            cx,
17050        );
17051
17052        if self.buffer.read(cx).is_singleton() {
17053            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17054        }
17055    }
17056
17057    pub fn go_to_definition(
17058        &mut self,
17059        _: &GoToDefinition,
17060        window: &mut Window,
17061        cx: &mut Context<Self>,
17062    ) -> Task<Result<Navigated>> {
17063        let definition =
17064            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17065        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17066        cx.spawn_in(window, async move |editor, cx| {
17067            if definition.await? == Navigated::Yes {
17068                return Ok(Navigated::Yes);
17069            }
17070            match fallback_strategy {
17071                GoToDefinitionFallback::None => Ok(Navigated::No),
17072                GoToDefinitionFallback::FindAllReferences => {
17073                    match editor.update_in(cx, |editor, window, cx| {
17074                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17075                    })? {
17076                        Some(references) => references.await,
17077                        None => Ok(Navigated::No),
17078                    }
17079                }
17080            }
17081        })
17082    }
17083
17084    pub fn go_to_declaration(
17085        &mut self,
17086        _: &GoToDeclaration,
17087        window: &mut Window,
17088        cx: &mut Context<Self>,
17089    ) -> Task<Result<Navigated>> {
17090        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17091    }
17092
17093    pub fn go_to_declaration_split(
17094        &mut self,
17095        _: &GoToDeclaration,
17096        window: &mut Window,
17097        cx: &mut Context<Self>,
17098    ) -> Task<Result<Navigated>> {
17099        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17100    }
17101
17102    pub fn go_to_implementation(
17103        &mut self,
17104        _: &GoToImplementation,
17105        window: &mut Window,
17106        cx: &mut Context<Self>,
17107    ) -> Task<Result<Navigated>> {
17108        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17109    }
17110
17111    pub fn go_to_implementation_split(
17112        &mut self,
17113        _: &GoToImplementationSplit,
17114        window: &mut Window,
17115        cx: &mut Context<Self>,
17116    ) -> Task<Result<Navigated>> {
17117        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17118    }
17119
17120    pub fn go_to_type_definition(
17121        &mut self,
17122        _: &GoToTypeDefinition,
17123        window: &mut Window,
17124        cx: &mut Context<Self>,
17125    ) -> Task<Result<Navigated>> {
17126        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17127    }
17128
17129    pub fn go_to_definition_split(
17130        &mut self,
17131        _: &GoToDefinitionSplit,
17132        window: &mut Window,
17133        cx: &mut Context<Self>,
17134    ) -> Task<Result<Navigated>> {
17135        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17136    }
17137
17138    pub fn go_to_type_definition_split(
17139        &mut self,
17140        _: &GoToTypeDefinitionSplit,
17141        window: &mut Window,
17142        cx: &mut Context<Self>,
17143    ) -> Task<Result<Navigated>> {
17144        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17145    }
17146
17147    fn go_to_definition_of_kind(
17148        &mut self,
17149        kind: GotoDefinitionKind,
17150        split: bool,
17151        window: &mut Window,
17152        cx: &mut Context<Self>,
17153    ) -> Task<Result<Navigated>> {
17154        let Some(provider) = self.semantics_provider.clone() else {
17155            return Task::ready(Ok(Navigated::No));
17156        };
17157        let head = self
17158            .selections
17159            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17160            .head();
17161        let buffer = self.buffer.read(cx);
17162        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17163            return Task::ready(Ok(Navigated::No));
17164        };
17165        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17166            return Task::ready(Ok(Navigated::No));
17167        };
17168
17169        cx.spawn_in(window, async move |editor, cx| {
17170            let Some(definitions) = definitions.await? else {
17171                return Ok(Navigated::No);
17172            };
17173            let navigated = editor
17174                .update_in(cx, |editor, window, cx| {
17175                    editor.navigate_to_hover_links(
17176                        Some(kind),
17177                        definitions
17178                            .into_iter()
17179                            .filter(|location| {
17180                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17181                            })
17182                            .map(HoverLink::Text)
17183                            .collect::<Vec<_>>(),
17184                        split,
17185                        window,
17186                        cx,
17187                    )
17188                })?
17189                .await?;
17190            anyhow::Ok(navigated)
17191        })
17192    }
17193
17194    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17195        let selection = self.selections.newest_anchor();
17196        let head = selection.head();
17197        let tail = selection.tail();
17198
17199        let Some((buffer, start_position)) =
17200            self.buffer.read(cx).text_anchor_for_position(head, cx)
17201        else {
17202            return;
17203        };
17204
17205        let end_position = if head != tail {
17206            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17207                return;
17208            };
17209            Some(pos)
17210        } else {
17211            None
17212        };
17213
17214        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17215            let url = if let Some(end_pos) = end_position {
17216                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17217            } else {
17218                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17219            };
17220
17221            if let Some(url) = url {
17222                cx.update(|window, cx| {
17223                    if parse_zed_link(&url, cx).is_some() {
17224                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17225                    } else {
17226                        cx.open_url(&url);
17227                    }
17228                })?;
17229            }
17230
17231            anyhow::Ok(())
17232        });
17233
17234        url_finder.detach();
17235    }
17236
17237    pub fn open_selected_filename(
17238        &mut self,
17239        _: &OpenSelectedFilename,
17240        window: &mut Window,
17241        cx: &mut Context<Self>,
17242    ) {
17243        let Some(workspace) = self.workspace() else {
17244            return;
17245        };
17246
17247        let position = self.selections.newest_anchor().head();
17248
17249        let Some((buffer, buffer_position)) =
17250            self.buffer.read(cx).text_anchor_for_position(position, cx)
17251        else {
17252            return;
17253        };
17254
17255        let project = self.project.clone();
17256
17257        cx.spawn_in(window, async move |_, cx| {
17258            let result = find_file(&buffer, project, buffer_position, cx).await;
17259
17260            if let Some((_, path)) = result {
17261                workspace
17262                    .update_in(cx, |workspace, window, cx| {
17263                        workspace.open_resolved_path(path, window, cx)
17264                    })?
17265                    .await?;
17266            }
17267            anyhow::Ok(())
17268        })
17269        .detach();
17270    }
17271
17272    pub(crate) fn navigate_to_hover_links(
17273        &mut self,
17274        kind: Option<GotoDefinitionKind>,
17275        definitions: Vec<HoverLink>,
17276        split: bool,
17277        window: &mut Window,
17278        cx: &mut Context<Editor>,
17279    ) -> Task<Result<Navigated>> {
17280        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17281        let mut first_url_or_file = None;
17282        let definitions: Vec<_> = definitions
17283            .into_iter()
17284            .filter_map(|def| match def {
17285                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17286                HoverLink::InlayHint(lsp_location, server_id) => {
17287                    let computation =
17288                        self.compute_target_location(lsp_location, server_id, window, cx);
17289                    Some(cx.background_spawn(computation))
17290                }
17291                HoverLink::Url(url) => {
17292                    first_url_or_file = Some(Either::Left(url));
17293                    None
17294                }
17295                HoverLink::File(path) => {
17296                    first_url_or_file = Some(Either::Right(path));
17297                    None
17298                }
17299            })
17300            .collect();
17301
17302        let workspace = self.workspace();
17303
17304        cx.spawn_in(window, async move |editor, cx| {
17305            let locations: Vec<Location> = future::join_all(definitions)
17306                .await
17307                .into_iter()
17308                .filter_map(|location| location.transpose())
17309                .collect::<Result<_>>()
17310                .context("location tasks")?;
17311            let mut locations = cx.update(|_, cx| {
17312                locations
17313                    .into_iter()
17314                    .map(|location| {
17315                        let buffer = location.buffer.read(cx);
17316                        (location.buffer, location.range.to_point(buffer))
17317                    })
17318                    .into_group_map()
17319            })?;
17320            let mut num_locations = 0;
17321            for ranges in locations.values_mut() {
17322                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17323                ranges.dedup();
17324                num_locations += ranges.len();
17325            }
17326
17327            if num_locations > 1 {
17328                let tab_kind = match kind {
17329                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17330                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17331                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17332                    Some(GotoDefinitionKind::Type) => "Types",
17333                };
17334                let title = editor
17335                    .update_in(cx, |_, _, cx| {
17336                        let target = locations
17337                            .iter()
17338                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17339                            .map(|(buffer, location)| {
17340                                buffer
17341                                    .read(cx)
17342                                    .text_for_range(location.clone())
17343                                    .collect::<String>()
17344                            })
17345                            .filter(|text| !text.contains('\n'))
17346                            .unique()
17347                            .take(3)
17348                            .join(", ");
17349                        if target.is_empty() {
17350                            tab_kind.to_owned()
17351                        } else {
17352                            format!("{tab_kind} for {target}")
17353                        }
17354                    })
17355                    .context("buffer title")?;
17356
17357                let Some(workspace) = workspace else {
17358                    return Ok(Navigated::No);
17359                };
17360
17361                let opened = workspace
17362                    .update_in(cx, |workspace, window, cx| {
17363                        let allow_preview = PreviewTabsSettings::get_global(cx)
17364                            .enable_preview_multibuffer_from_code_navigation;
17365                        Self::open_locations_in_multibuffer(
17366                            workspace,
17367                            locations,
17368                            title,
17369                            split,
17370                            allow_preview,
17371                            MultibufferSelectionMode::First,
17372                            window,
17373                            cx,
17374                        )
17375                    })
17376                    .is_ok();
17377
17378                anyhow::Ok(Navigated::from_bool(opened))
17379            } else if num_locations == 0 {
17380                // If there is one url or file, open it directly
17381                match first_url_or_file {
17382                    Some(Either::Left(url)) => {
17383                        cx.update(|window, cx| {
17384                            if parse_zed_link(&url, cx).is_some() {
17385                                window
17386                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17387                            } else {
17388                                cx.open_url(&url);
17389                            }
17390                        })?;
17391                        Ok(Navigated::Yes)
17392                    }
17393                    Some(Either::Right(path)) => {
17394                        // TODO(andrew): respect preview tab settings
17395                        //               `enable_keep_preview_on_code_navigation` and
17396                        //               `enable_preview_file_from_code_navigation`
17397                        let Some(workspace) = workspace else {
17398                            return Ok(Navigated::No);
17399                        };
17400                        workspace
17401                            .update_in(cx, |workspace, window, cx| {
17402                                workspace.open_resolved_path(path, window, cx)
17403                            })?
17404                            .await?;
17405                        Ok(Navigated::Yes)
17406                    }
17407                    None => Ok(Navigated::No),
17408                }
17409            } else {
17410                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17411                let target_range = target_ranges.first().unwrap().clone();
17412
17413                editor.update_in(cx, |editor, window, cx| {
17414                    let range = target_range.to_point(target_buffer.read(cx));
17415                    let range = editor.range_for_match(&range);
17416                    let range = collapse_multiline_range(range);
17417
17418                    if !split
17419                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17420                    {
17421                        editor.go_to_singleton_buffer_range(range, window, cx);
17422                    } else {
17423                        let Some(workspace) = workspace else {
17424                            return Navigated::No;
17425                        };
17426                        let pane = workspace.read(cx).active_pane().clone();
17427                        window.defer(cx, move |window, cx| {
17428                            let target_editor: Entity<Self> =
17429                                workspace.update(cx, |workspace, cx| {
17430                                    let pane = if split {
17431                                        workspace.adjacent_pane(window, cx)
17432                                    } else {
17433                                        workspace.active_pane().clone()
17434                                    };
17435
17436                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17437                                    let keep_old_preview = preview_tabs_settings
17438                                        .enable_keep_preview_on_code_navigation;
17439                                    let allow_new_preview = preview_tabs_settings
17440                                        .enable_preview_file_from_code_navigation;
17441
17442                                    workspace.open_project_item(
17443                                        pane,
17444                                        target_buffer.clone(),
17445                                        true,
17446                                        true,
17447                                        keep_old_preview,
17448                                        allow_new_preview,
17449                                        window,
17450                                        cx,
17451                                    )
17452                                });
17453                            target_editor.update(cx, |target_editor, cx| {
17454                                // When selecting a definition in a different buffer, disable the nav history
17455                                // to avoid creating a history entry at the previous cursor location.
17456                                pane.update(cx, |pane, _| pane.disable_history());
17457                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17458                                pane.update(cx, |pane, _| pane.enable_history());
17459                            });
17460                        });
17461                    }
17462                    Navigated::Yes
17463                })
17464            }
17465        })
17466    }
17467
17468    fn compute_target_location(
17469        &self,
17470        lsp_location: lsp::Location,
17471        server_id: LanguageServerId,
17472        window: &mut Window,
17473        cx: &mut Context<Self>,
17474    ) -> Task<anyhow::Result<Option<Location>>> {
17475        let Some(project) = self.project.clone() else {
17476            return Task::ready(Ok(None));
17477        };
17478
17479        cx.spawn_in(window, async move |editor, cx| {
17480            let location_task = editor.update(cx, |_, cx| {
17481                project.update(cx, |project, cx| {
17482                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17483                })
17484            })?;
17485            let location = Some({
17486                let target_buffer_handle = location_task.await.context("open local buffer")?;
17487                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17488                    let target_start = target_buffer
17489                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17490                    let target_end = target_buffer
17491                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17492                    target_buffer.anchor_after(target_start)
17493                        ..target_buffer.anchor_before(target_end)
17494                })?;
17495                Location {
17496                    buffer: target_buffer_handle,
17497                    range,
17498                }
17499            });
17500            Ok(location)
17501        })
17502    }
17503
17504    fn go_to_next_reference(
17505        &mut self,
17506        _: &GoToNextReference,
17507        window: &mut Window,
17508        cx: &mut Context<Self>,
17509    ) {
17510        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17511        if let Some(task) = task {
17512            task.detach();
17513        };
17514    }
17515
17516    fn go_to_prev_reference(
17517        &mut self,
17518        _: &GoToPreviousReference,
17519        window: &mut Window,
17520        cx: &mut Context<Self>,
17521    ) {
17522        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17523        if let Some(task) = task {
17524            task.detach();
17525        };
17526    }
17527
17528    pub fn go_to_reference_before_or_after_position(
17529        &mut self,
17530        direction: Direction,
17531        count: usize,
17532        window: &mut Window,
17533        cx: &mut Context<Self>,
17534    ) -> Option<Task<Result<()>>> {
17535        let selection = self.selections.newest_anchor();
17536        let head = selection.head();
17537
17538        let multi_buffer = self.buffer.read(cx);
17539
17540        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17541        let workspace = self.workspace()?;
17542        let project = workspace.read(cx).project().clone();
17543        let references =
17544            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17545        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17546            let Some(locations) = references.await? else {
17547                return Ok(());
17548            };
17549
17550            if locations.is_empty() {
17551                // totally normal - the cursor may be on something which is not
17552                // a symbol (e.g. a keyword)
17553                log::info!("no references found under cursor");
17554                return Ok(());
17555            }
17556
17557            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17558
17559            let (locations, current_location_index) =
17560                multi_buffer.update(cx, |multi_buffer, cx| {
17561                    let mut locations = locations
17562                        .into_iter()
17563                        .filter_map(|loc| {
17564                            let start = multi_buffer.buffer_anchor_to_anchor(
17565                                &loc.buffer,
17566                                loc.range.start,
17567                                cx,
17568                            )?;
17569                            let end = multi_buffer.buffer_anchor_to_anchor(
17570                                &loc.buffer,
17571                                loc.range.end,
17572                                cx,
17573                            )?;
17574                            Some(start..end)
17575                        })
17576                        .collect::<Vec<_>>();
17577
17578                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17579                    // There is an O(n) implementation, but given this list will be
17580                    // small (usually <100 items), the extra O(log(n)) factor isn't
17581                    // worth the (surprisingly large amount of) extra complexity.
17582                    locations
17583                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17584
17585                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17586
17587                    let current_location_index = locations.iter().position(|loc| {
17588                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17589                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17590                    });
17591
17592                    (locations, current_location_index)
17593                })?;
17594
17595            let Some(current_location_index) = current_location_index else {
17596                // This indicates something has gone wrong, because we already
17597                // handle the "no references" case above
17598                log::error!(
17599                    "failed to find current reference under cursor. Total references: {}",
17600                    locations.len()
17601                );
17602                return Ok(());
17603            };
17604
17605            let destination_location_index = match direction {
17606                Direction::Next => (current_location_index + count) % locations.len(),
17607                Direction::Prev => {
17608                    (current_location_index + locations.len() - count % locations.len())
17609                        % locations.len()
17610                }
17611            };
17612
17613            // TODO(cameron): is this needed?
17614            // the thinking is to avoid "jumping to the current location" (avoid
17615            // polluting "jumplist" in vim terms)
17616            if current_location_index == destination_location_index {
17617                return Ok(());
17618            }
17619
17620            let Range { start, end } = locations[destination_location_index];
17621
17622            editor.update_in(cx, |editor, window, cx| {
17623                let effects = SelectionEffects::default();
17624
17625                editor.unfold_ranges(&[start..end], false, false, cx);
17626                editor.change_selections(effects, window, cx, |s| {
17627                    s.select_ranges([start..start]);
17628                });
17629            })?;
17630
17631            Ok(())
17632        }))
17633    }
17634
17635    pub fn find_all_references(
17636        &mut self,
17637        action: &FindAllReferences,
17638        window: &mut Window,
17639        cx: &mut Context<Self>,
17640    ) -> Option<Task<Result<Navigated>>> {
17641        let always_open_multibuffer = action.always_open_multibuffer;
17642        let selection = self.selections.newest_anchor();
17643        let multi_buffer = self.buffer.read(cx);
17644        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17645        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
17646        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
17647        let head = selection_offset.head();
17648
17649        let head_anchor = multi_buffer_snapshot.anchor_at(
17650            head,
17651            if head < selection_offset.tail() {
17652                Bias::Right
17653            } else {
17654                Bias::Left
17655            },
17656        );
17657
17658        match self
17659            .find_all_references_task_sources
17660            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17661        {
17662            Ok(_) => {
17663                log::info!(
17664                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17665                );
17666                return None;
17667            }
17668            Err(i) => {
17669                self.find_all_references_task_sources.insert(i, head_anchor);
17670            }
17671        }
17672
17673        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17674        let workspace = self.workspace()?;
17675        let project = workspace.read(cx).project().clone();
17676        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17677        Some(cx.spawn_in(window, async move |editor, cx| {
17678            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17679                if let Ok(i) = editor
17680                    .find_all_references_task_sources
17681                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17682                {
17683                    editor.find_all_references_task_sources.remove(i);
17684                }
17685            });
17686
17687            let Some(locations) = references.await? else {
17688                return anyhow::Ok(Navigated::No);
17689            };
17690            let mut locations = cx.update(|_, cx| {
17691                locations
17692                    .into_iter()
17693                    .map(|location| {
17694                        let buffer = location.buffer.read(cx);
17695                        (location.buffer, location.range.to_point(buffer))
17696                    })
17697                    // if special-casing the single-match case, remove ranges
17698                    // that intersect current selection
17699                    .filter(|(location_buffer, location)| {
17700                        if always_open_multibuffer || &buffer != location_buffer {
17701                            return true;
17702                        }
17703
17704                        !location.contains_inclusive(&selection_point.range())
17705                    })
17706                    .into_group_map()
17707            })?;
17708            if locations.is_empty() {
17709                return anyhow::Ok(Navigated::No);
17710            }
17711            for ranges in locations.values_mut() {
17712                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17713                ranges.dedup();
17714            }
17715            let mut num_locations = 0;
17716            for ranges in locations.values_mut() {
17717                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17718                ranges.dedup();
17719                num_locations += ranges.len();
17720            }
17721
17722            if num_locations == 1 && !always_open_multibuffer {
17723                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17724                let target_range = target_ranges.first().unwrap().clone();
17725
17726                return editor.update_in(cx, |editor, window, cx| {
17727                    let range = target_range.to_point(target_buffer.read(cx));
17728                    let range = editor.range_for_match(&range);
17729                    let range = range.start..range.start;
17730
17731                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
17732                        editor.go_to_singleton_buffer_range(range, window, cx);
17733                    } else {
17734                        let pane = workspace.read(cx).active_pane().clone();
17735                        window.defer(cx, move |window, cx| {
17736                            let target_editor: Entity<Self> =
17737                                workspace.update(cx, |workspace, cx| {
17738                                    let pane = workspace.active_pane().clone();
17739
17740                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17741                                    let keep_old_preview = preview_tabs_settings
17742                                        .enable_keep_preview_on_code_navigation;
17743                                    let allow_new_preview = preview_tabs_settings
17744                                        .enable_preview_file_from_code_navigation;
17745
17746                                    workspace.open_project_item(
17747                                        pane,
17748                                        target_buffer.clone(),
17749                                        true,
17750                                        true,
17751                                        keep_old_preview,
17752                                        allow_new_preview,
17753                                        window,
17754                                        cx,
17755                                    )
17756                                });
17757                            target_editor.update(cx, |target_editor, cx| {
17758                                // When selecting a definition in a different buffer, disable the nav history
17759                                // to avoid creating a history entry at the previous cursor location.
17760                                pane.update(cx, |pane, _| pane.disable_history());
17761                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17762                                pane.update(cx, |pane, _| pane.enable_history());
17763                            });
17764                        });
17765                    }
17766                    Navigated::No
17767                });
17768            }
17769
17770            workspace.update_in(cx, |workspace, window, cx| {
17771                let target = locations
17772                    .iter()
17773                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17774                    .map(|(buffer, location)| {
17775                        buffer
17776                            .read(cx)
17777                            .text_for_range(location.clone())
17778                            .collect::<String>()
17779                    })
17780                    .filter(|text| !text.contains('\n'))
17781                    .unique()
17782                    .take(3)
17783                    .join(", ");
17784                let title = if target.is_empty() {
17785                    "References".to_owned()
17786                } else {
17787                    format!("References to {target}")
17788                };
17789                let allow_preview = PreviewTabsSettings::get_global(cx)
17790                    .enable_preview_multibuffer_from_code_navigation;
17791                Self::open_locations_in_multibuffer(
17792                    workspace,
17793                    locations,
17794                    title,
17795                    false,
17796                    allow_preview,
17797                    MultibufferSelectionMode::First,
17798                    window,
17799                    cx,
17800                );
17801                Navigated::Yes
17802            })
17803        }))
17804    }
17805
17806    /// Opens a multibuffer with the given project locations in it.
17807    pub fn open_locations_in_multibuffer(
17808        workspace: &mut Workspace,
17809        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17810        title: String,
17811        split: bool,
17812        allow_preview: bool,
17813        multibuffer_selection_mode: MultibufferSelectionMode,
17814        window: &mut Window,
17815        cx: &mut Context<Workspace>,
17816    ) {
17817        if locations.is_empty() {
17818            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17819            return;
17820        }
17821
17822        let capability = workspace.project().read(cx).capability();
17823        let mut ranges = <Vec<Range<Anchor>>>::new();
17824
17825        // a key to find existing multibuffer editors with the same set of locations
17826        // to prevent us from opening more and more multibuffer tabs for searches and the like
17827        let mut key = (title.clone(), vec![]);
17828        let excerpt_buffer = cx.new(|cx| {
17829            let key = &mut key.1;
17830            let mut multibuffer = MultiBuffer::new(capability);
17831            for (buffer, mut ranges_for_buffer) in locations {
17832                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17833                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17834                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17835                    PathKey::for_buffer(&buffer, cx),
17836                    buffer.clone(),
17837                    ranges_for_buffer,
17838                    multibuffer_context_lines(cx),
17839                    cx,
17840                );
17841                ranges.extend(new_ranges)
17842            }
17843
17844            multibuffer.with_title(title)
17845        });
17846        let existing = workspace.active_pane().update(cx, |pane, cx| {
17847            pane.items()
17848                .filter_map(|item| item.downcast::<Editor>())
17849                .find(|editor| {
17850                    editor
17851                        .read(cx)
17852                        .lookup_key
17853                        .as_ref()
17854                        .and_then(|it| {
17855                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17856                        })
17857                        .is_some_and(|it| *it == key)
17858                })
17859        });
17860        let was_existing = existing.is_some();
17861        let editor = existing.unwrap_or_else(|| {
17862            cx.new(|cx| {
17863                let mut editor = Editor::for_multibuffer(
17864                    excerpt_buffer,
17865                    Some(workspace.project().clone()),
17866                    window,
17867                    cx,
17868                );
17869                editor.lookup_key = Some(Box::new(key));
17870                editor
17871            })
17872        });
17873        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17874            MultibufferSelectionMode::First => {
17875                if let Some(first_range) = ranges.first() {
17876                    editor.change_selections(
17877                        SelectionEffects::no_scroll(),
17878                        window,
17879                        cx,
17880                        |selections| {
17881                            selections.clear_disjoint();
17882                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17883                        },
17884                    );
17885                }
17886                editor.highlight_background::<Self>(
17887                    &ranges,
17888                    |_, theme| theme.colors().editor_highlighted_line_background,
17889                    cx,
17890                );
17891            }
17892            MultibufferSelectionMode::All => {
17893                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17894                    selections.clear_disjoint();
17895                    selections.select_anchor_ranges(ranges);
17896                });
17897            }
17898        });
17899
17900        let item = Box::new(editor);
17901
17902        let pane = if split {
17903            workspace.adjacent_pane(window, cx)
17904        } else {
17905            workspace.active_pane().clone()
17906        };
17907        let activate_pane = split;
17908
17909        let mut destination_index = None;
17910        pane.update(cx, |pane, cx| {
17911            if allow_preview && !was_existing {
17912                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
17913            }
17914            if was_existing && !allow_preview {
17915                pane.unpreview_item_if_preview(item.item_id());
17916            }
17917            pane.add_item(item, activate_pane, true, destination_index, window, cx);
17918        });
17919    }
17920
17921    pub fn rename(
17922        &mut self,
17923        _: &Rename,
17924        window: &mut Window,
17925        cx: &mut Context<Self>,
17926    ) -> Option<Task<Result<()>>> {
17927        use language::ToOffset as _;
17928
17929        let provider = self.semantics_provider.clone()?;
17930        let selection = self.selections.newest_anchor().clone();
17931        let (cursor_buffer, cursor_buffer_position) = self
17932            .buffer
17933            .read(cx)
17934            .text_anchor_for_position(selection.head(), cx)?;
17935        let (tail_buffer, cursor_buffer_position_end) = self
17936            .buffer
17937            .read(cx)
17938            .text_anchor_for_position(selection.tail(), cx)?;
17939        if tail_buffer != cursor_buffer {
17940            return None;
17941        }
17942
17943        let snapshot = cursor_buffer.read(cx).snapshot();
17944        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17945        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17946        let prepare_rename = provider
17947            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17948            .unwrap_or_else(|| Task::ready(Ok(None)));
17949        drop(snapshot);
17950
17951        Some(cx.spawn_in(window, async move |this, cx| {
17952            let rename_range = if let Some(range) = prepare_rename.await? {
17953                Some(range)
17954            } else {
17955                this.update(cx, |this, cx| {
17956                    let buffer = this.buffer.read(cx).snapshot(cx);
17957                    let mut buffer_highlights = this
17958                        .document_highlights_for_position(selection.head(), &buffer)
17959                        .filter(|highlight| {
17960                            highlight.start.excerpt_id == selection.head().excerpt_id
17961                                && highlight.end.excerpt_id == selection.head().excerpt_id
17962                        });
17963                    buffer_highlights
17964                        .next()
17965                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17966                })?
17967            };
17968            if let Some(rename_range) = rename_range {
17969                this.update_in(cx, |this, window, cx| {
17970                    let snapshot = cursor_buffer.read(cx).snapshot();
17971                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17972                    let cursor_offset_in_rename_range =
17973                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17974                    let cursor_offset_in_rename_range_end =
17975                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17976
17977                    this.take_rename(false, window, cx);
17978                    let buffer = this.buffer.read(cx).read(cx);
17979                    let cursor_offset = selection.head().to_offset(&buffer);
17980                    let rename_start =
17981                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17982                    let rename_end = rename_start + rename_buffer_range.len();
17983                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17984                    let mut old_highlight_id = None;
17985                    let old_name: Arc<str> = buffer
17986                        .chunks(rename_start..rename_end, true)
17987                        .map(|chunk| {
17988                            if old_highlight_id.is_none() {
17989                                old_highlight_id = chunk.syntax_highlight_id;
17990                            }
17991                            chunk.text
17992                        })
17993                        .collect::<String>()
17994                        .into();
17995
17996                    drop(buffer);
17997
17998                    // Position the selection in the rename editor so that it matches the current selection.
17999                    this.show_local_selections = false;
18000                    let rename_editor = cx.new(|cx| {
18001                        let mut editor = Editor::single_line(window, cx);
18002                        editor.buffer.update(cx, |buffer, cx| {
18003                            buffer.edit(
18004                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18005                                None,
18006                                cx,
18007                            )
18008                        });
18009                        let cursor_offset_in_rename_range =
18010                            MultiBufferOffset(cursor_offset_in_rename_range);
18011                        let cursor_offset_in_rename_range_end =
18012                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18013                        let rename_selection_range = match cursor_offset_in_rename_range
18014                            .cmp(&cursor_offset_in_rename_range_end)
18015                        {
18016                            Ordering::Equal => {
18017                                editor.select_all(&SelectAll, window, cx);
18018                                return editor;
18019                            }
18020                            Ordering::Less => {
18021                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18022                            }
18023                            Ordering::Greater => {
18024                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18025                            }
18026                        };
18027                        if rename_selection_range.end.0 > old_name.len() {
18028                            editor.select_all(&SelectAll, window, cx);
18029                        } else {
18030                            editor.change_selections(Default::default(), window, cx, |s| {
18031                                s.select_ranges([rename_selection_range]);
18032                            });
18033                        }
18034                        editor
18035                    });
18036                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18037                        if e == &EditorEvent::Focused {
18038                            cx.emit(EditorEvent::FocusedIn)
18039                        }
18040                    })
18041                    .detach();
18042
18043                    let write_highlights =
18044                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18045                    let read_highlights =
18046                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18047                    let ranges = write_highlights
18048                        .iter()
18049                        .flat_map(|(_, ranges)| ranges.iter())
18050                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18051                        .cloned()
18052                        .collect();
18053
18054                    this.highlight_text::<Rename>(
18055                        ranges,
18056                        HighlightStyle {
18057                            fade_out: Some(0.6),
18058                            ..Default::default()
18059                        },
18060                        cx,
18061                    );
18062                    let rename_focus_handle = rename_editor.focus_handle(cx);
18063                    window.focus(&rename_focus_handle, cx);
18064                    let block_id = this.insert_blocks(
18065                        [BlockProperties {
18066                            style: BlockStyle::Flex,
18067                            placement: BlockPlacement::Below(range.start),
18068                            height: Some(1),
18069                            render: Arc::new({
18070                                let rename_editor = rename_editor.clone();
18071                                move |cx: &mut BlockContext| {
18072                                    let mut text_style = cx.editor_style.text.clone();
18073                                    if let Some(highlight_style) = old_highlight_id
18074                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18075                                    {
18076                                        text_style = text_style.highlight(highlight_style);
18077                                    }
18078                                    div()
18079                                        .block_mouse_except_scroll()
18080                                        .pl(cx.anchor_x)
18081                                        .child(EditorElement::new(
18082                                            &rename_editor,
18083                                            EditorStyle {
18084                                                background: cx.theme().system().transparent,
18085                                                local_player: cx.editor_style.local_player,
18086                                                text: text_style,
18087                                                scrollbar_width: cx.editor_style.scrollbar_width,
18088                                                syntax: cx.editor_style.syntax.clone(),
18089                                                status: cx.editor_style.status.clone(),
18090                                                inlay_hints_style: HighlightStyle {
18091                                                    font_weight: Some(FontWeight::BOLD),
18092                                                    ..make_inlay_hints_style(cx.app)
18093                                                },
18094                                                edit_prediction_styles: make_suggestion_styles(
18095                                                    cx.app,
18096                                                ),
18097                                                ..EditorStyle::default()
18098                                            },
18099                                        ))
18100                                        .into_any_element()
18101                                }
18102                            }),
18103                            priority: 0,
18104                        }],
18105                        Some(Autoscroll::fit()),
18106                        cx,
18107                    )[0];
18108                    this.pending_rename = Some(RenameState {
18109                        range,
18110                        old_name,
18111                        editor: rename_editor,
18112                        block_id,
18113                    });
18114                })?;
18115            }
18116
18117            Ok(())
18118        }))
18119    }
18120
18121    pub fn confirm_rename(
18122        &mut self,
18123        _: &ConfirmRename,
18124        window: &mut Window,
18125        cx: &mut Context<Self>,
18126    ) -> Option<Task<Result<()>>> {
18127        let rename = self.take_rename(false, window, cx)?;
18128        let workspace = self.workspace()?.downgrade();
18129        let (buffer, start) = self
18130            .buffer
18131            .read(cx)
18132            .text_anchor_for_position(rename.range.start, cx)?;
18133        let (end_buffer, _) = self
18134            .buffer
18135            .read(cx)
18136            .text_anchor_for_position(rename.range.end, cx)?;
18137        if buffer != end_buffer {
18138            return None;
18139        }
18140
18141        let old_name = rename.old_name;
18142        let new_name = rename.editor.read(cx).text(cx);
18143
18144        let rename = self.semantics_provider.as_ref()?.perform_rename(
18145            &buffer,
18146            start,
18147            new_name.clone(),
18148            cx,
18149        )?;
18150
18151        Some(cx.spawn_in(window, async move |editor, cx| {
18152            let project_transaction = rename.await?;
18153            Self::open_project_transaction(
18154                &editor,
18155                workspace,
18156                project_transaction,
18157                format!("Rename: {}{}", old_name, new_name),
18158                cx,
18159            )
18160            .await?;
18161
18162            editor.update(cx, |editor, cx| {
18163                editor.refresh_document_highlights(cx);
18164            })?;
18165            Ok(())
18166        }))
18167    }
18168
18169    fn take_rename(
18170        &mut self,
18171        moving_cursor: bool,
18172        window: &mut Window,
18173        cx: &mut Context<Self>,
18174    ) -> Option<RenameState> {
18175        let rename = self.pending_rename.take()?;
18176        if rename.editor.focus_handle(cx).is_focused(window) {
18177            window.focus(&self.focus_handle, cx);
18178        }
18179
18180        self.remove_blocks(
18181            [rename.block_id].into_iter().collect(),
18182            Some(Autoscroll::fit()),
18183            cx,
18184        );
18185        self.clear_highlights::<Rename>(cx);
18186        self.show_local_selections = true;
18187
18188        if moving_cursor {
18189            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18190                editor
18191                    .selections
18192                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18193                    .head()
18194            });
18195
18196            // Update the selection to match the position of the selection inside
18197            // the rename editor.
18198            let snapshot = self.buffer.read(cx).read(cx);
18199            let rename_range = rename.range.to_offset(&snapshot);
18200            let cursor_in_editor = snapshot
18201                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18202                .min(rename_range.end);
18203            drop(snapshot);
18204
18205            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18206                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18207            });
18208        } else {
18209            self.refresh_document_highlights(cx);
18210        }
18211
18212        Some(rename)
18213    }
18214
18215    pub fn pending_rename(&self) -> Option<&RenameState> {
18216        self.pending_rename.as_ref()
18217    }
18218
18219    fn format(
18220        &mut self,
18221        _: &Format,
18222        window: &mut Window,
18223        cx: &mut Context<Self>,
18224    ) -> Option<Task<Result<()>>> {
18225        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18226
18227        let project = match &self.project {
18228            Some(project) => project.clone(),
18229            None => return None,
18230        };
18231
18232        Some(self.perform_format(
18233            project,
18234            FormatTrigger::Manual,
18235            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18236            window,
18237            cx,
18238        ))
18239    }
18240
18241    fn format_selections(
18242        &mut self,
18243        _: &FormatSelections,
18244        window: &mut Window,
18245        cx: &mut Context<Self>,
18246    ) -> Option<Task<Result<()>>> {
18247        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18248
18249        let project = match &self.project {
18250            Some(project) => project.clone(),
18251            None => return None,
18252        };
18253
18254        let ranges = self
18255            .selections
18256            .all_adjusted(&self.display_snapshot(cx))
18257            .into_iter()
18258            .map(|selection| selection.range())
18259            .collect_vec();
18260
18261        Some(self.perform_format(
18262            project,
18263            FormatTrigger::Manual,
18264            FormatTarget::Ranges(ranges),
18265            window,
18266            cx,
18267        ))
18268    }
18269
18270    fn perform_format(
18271        &mut self,
18272        project: Entity<Project>,
18273        trigger: FormatTrigger,
18274        target: FormatTarget,
18275        window: &mut Window,
18276        cx: &mut Context<Self>,
18277    ) -> Task<Result<()>> {
18278        let buffer = self.buffer.clone();
18279        let (buffers, target) = match target {
18280            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18281            FormatTarget::Ranges(selection_ranges) => {
18282                let multi_buffer = buffer.read(cx);
18283                let snapshot = multi_buffer.read(cx);
18284                let mut buffers = HashSet::default();
18285                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18286                    BTreeMap::new();
18287                for selection_range in selection_ranges {
18288                    for (buffer, buffer_range, _) in
18289                        snapshot.range_to_buffer_ranges(selection_range)
18290                    {
18291                        let buffer_id = buffer.remote_id();
18292                        let start = buffer.anchor_before(buffer_range.start);
18293                        let end = buffer.anchor_after(buffer_range.end);
18294                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18295                        buffer_id_to_ranges
18296                            .entry(buffer_id)
18297                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18298                            .or_insert_with(|| vec![start..end]);
18299                    }
18300                }
18301                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18302            }
18303        };
18304
18305        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18306        let selections_prev = transaction_id_prev
18307            .and_then(|transaction_id_prev| {
18308                // default to selections as they were after the last edit, if we have them,
18309                // instead of how they are now.
18310                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18311                // will take you back to where you made the last edit, instead of staying where you scrolled
18312                self.selection_history
18313                    .transaction(transaction_id_prev)
18314                    .map(|t| t.0.clone())
18315            })
18316            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18317
18318        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18319        let format = project.update(cx, |project, cx| {
18320            project.format(buffers, target, true, trigger, cx)
18321        });
18322
18323        cx.spawn_in(window, async move |editor, cx| {
18324            let transaction = futures::select_biased! {
18325                transaction = format.log_err().fuse() => transaction,
18326                () = timeout => {
18327                    log::warn!("timed out waiting for formatting");
18328                    None
18329                }
18330            };
18331
18332            buffer
18333                .update(cx, |buffer, cx| {
18334                    if let Some(transaction) = transaction
18335                        && !buffer.is_singleton()
18336                    {
18337                        buffer.push_transaction(&transaction.0, cx);
18338                    }
18339                    cx.notify();
18340                })
18341                .ok();
18342
18343            if let Some(transaction_id_now) =
18344                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
18345            {
18346                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18347                if has_new_transaction {
18348                    _ = editor.update(cx, |editor, _| {
18349                        editor
18350                            .selection_history
18351                            .insert_transaction(transaction_id_now, selections_prev);
18352                    });
18353                }
18354            }
18355
18356            Ok(())
18357        })
18358    }
18359
18360    fn organize_imports(
18361        &mut self,
18362        _: &OrganizeImports,
18363        window: &mut Window,
18364        cx: &mut Context<Self>,
18365    ) -> Option<Task<Result<()>>> {
18366        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18367        let project = match &self.project {
18368            Some(project) => project.clone(),
18369            None => return None,
18370        };
18371        Some(self.perform_code_action_kind(
18372            project,
18373            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18374            window,
18375            cx,
18376        ))
18377    }
18378
18379    fn perform_code_action_kind(
18380        &mut self,
18381        project: Entity<Project>,
18382        kind: CodeActionKind,
18383        window: &mut Window,
18384        cx: &mut Context<Self>,
18385    ) -> Task<Result<()>> {
18386        let buffer = self.buffer.clone();
18387        let buffers = buffer.read(cx).all_buffers();
18388        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18389        let apply_action = project.update(cx, |project, cx| {
18390            project.apply_code_action_kind(buffers, kind, true, cx)
18391        });
18392        cx.spawn_in(window, async move |_, cx| {
18393            let transaction = futures::select_biased! {
18394                () = timeout => {
18395                    log::warn!("timed out waiting for executing code action");
18396                    None
18397                }
18398                transaction = apply_action.log_err().fuse() => transaction,
18399            };
18400            buffer
18401                .update(cx, |buffer, cx| {
18402                    // check if we need this
18403                    if let Some(transaction) = transaction
18404                        && !buffer.is_singleton()
18405                    {
18406                        buffer.push_transaction(&transaction.0, cx);
18407                    }
18408                    cx.notify();
18409                })
18410                .ok();
18411            Ok(())
18412        })
18413    }
18414
18415    pub fn restart_language_server(
18416        &mut self,
18417        _: &RestartLanguageServer,
18418        _: &mut Window,
18419        cx: &mut Context<Self>,
18420    ) {
18421        if let Some(project) = self.project.clone() {
18422            self.buffer.update(cx, |multi_buffer, cx| {
18423                project.update(cx, |project, cx| {
18424                    project.restart_language_servers_for_buffers(
18425                        multi_buffer.all_buffers().into_iter().collect(),
18426                        HashSet::default(),
18427                        cx,
18428                    );
18429                });
18430            })
18431        }
18432    }
18433
18434    pub fn stop_language_server(
18435        &mut self,
18436        _: &StopLanguageServer,
18437        _: &mut Window,
18438        cx: &mut Context<Self>,
18439    ) {
18440        if let Some(project) = self.project.clone() {
18441            self.buffer.update(cx, |multi_buffer, cx| {
18442                project.update(cx, |project, cx| {
18443                    project.stop_language_servers_for_buffers(
18444                        multi_buffer.all_buffers().into_iter().collect(),
18445                        HashSet::default(),
18446                        cx,
18447                    );
18448                });
18449            });
18450            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18451        }
18452    }
18453
18454    fn cancel_language_server_work(
18455        workspace: &mut Workspace,
18456        _: &actions::CancelLanguageServerWork,
18457        _: &mut Window,
18458        cx: &mut Context<Workspace>,
18459    ) {
18460        let project = workspace.project();
18461        let buffers = workspace
18462            .active_item(cx)
18463            .and_then(|item| item.act_as::<Editor>(cx))
18464            .map_or(HashSet::default(), |editor| {
18465                editor.read(cx).buffer.read(cx).all_buffers()
18466            });
18467        project.update(cx, |project, cx| {
18468            project.cancel_language_server_work_for_buffers(buffers, cx);
18469        });
18470    }
18471
18472    fn show_character_palette(
18473        &mut self,
18474        _: &ShowCharacterPalette,
18475        window: &mut Window,
18476        _: &mut Context<Self>,
18477    ) {
18478        window.show_character_palette();
18479    }
18480
18481    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18482        if !self.diagnostics_enabled() {
18483            return;
18484        }
18485
18486        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18487            let buffer = self.buffer.read(cx).snapshot(cx);
18488            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18489            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18490            let is_valid = buffer
18491                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18492                .any(|entry| {
18493                    entry.diagnostic.is_primary
18494                        && !entry.range.is_empty()
18495                        && entry.range.start == primary_range_start
18496                        && entry.diagnostic.message == active_diagnostics.active_message
18497                });
18498
18499            if !is_valid {
18500                self.dismiss_diagnostics(cx);
18501            }
18502        }
18503    }
18504
18505    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18506        match &self.active_diagnostics {
18507            ActiveDiagnostic::Group(group) => Some(group),
18508            _ => None,
18509        }
18510    }
18511
18512    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18513        if !self.diagnostics_enabled() {
18514            return;
18515        }
18516        self.dismiss_diagnostics(cx);
18517        self.active_diagnostics = ActiveDiagnostic::All;
18518    }
18519
18520    fn activate_diagnostics(
18521        &mut self,
18522        buffer_id: BufferId,
18523        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18524        window: &mut Window,
18525        cx: &mut Context<Self>,
18526    ) {
18527        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18528            return;
18529        }
18530        self.dismiss_diagnostics(cx);
18531        let snapshot = self.snapshot(window, cx);
18532        let buffer = self.buffer.read(cx).snapshot(cx);
18533        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18534            return;
18535        };
18536
18537        let diagnostic_group = buffer
18538            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18539            .collect::<Vec<_>>();
18540
18541        let language_registry = self
18542            .project()
18543            .map(|project| project.read(cx).languages().clone());
18544
18545        let blocks = renderer.render_group(
18546            diagnostic_group,
18547            buffer_id,
18548            snapshot,
18549            cx.weak_entity(),
18550            language_registry,
18551            cx,
18552        );
18553
18554        let blocks = self.display_map.update(cx, |display_map, cx| {
18555            display_map.insert_blocks(blocks, cx).into_iter().collect()
18556        });
18557        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18558            active_range: buffer.anchor_before(diagnostic.range.start)
18559                ..buffer.anchor_after(diagnostic.range.end),
18560            active_message: diagnostic.diagnostic.message.clone(),
18561            group_id: diagnostic.diagnostic.group_id,
18562            blocks,
18563        });
18564        cx.notify();
18565    }
18566
18567    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18568        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18569            return;
18570        };
18571
18572        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18573        if let ActiveDiagnostic::Group(group) = prev {
18574            self.display_map.update(cx, |display_map, cx| {
18575                display_map.remove_blocks(group.blocks, cx);
18576            });
18577            cx.notify();
18578        }
18579    }
18580
18581    /// Disable inline diagnostics rendering for this editor.
18582    pub fn disable_inline_diagnostics(&mut self) {
18583        self.inline_diagnostics_enabled = false;
18584        self.inline_diagnostics_update = Task::ready(());
18585        self.inline_diagnostics.clear();
18586    }
18587
18588    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18589        self.diagnostics_enabled = false;
18590        self.dismiss_diagnostics(cx);
18591        self.inline_diagnostics_update = Task::ready(());
18592        self.inline_diagnostics.clear();
18593    }
18594
18595    pub fn disable_word_completions(&mut self) {
18596        self.word_completions_enabled = false;
18597    }
18598
18599    pub fn diagnostics_enabled(&self) -> bool {
18600        self.diagnostics_enabled && self.mode.is_full()
18601    }
18602
18603    pub fn inline_diagnostics_enabled(&self) -> bool {
18604        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18605    }
18606
18607    pub fn show_inline_diagnostics(&self) -> bool {
18608        self.show_inline_diagnostics
18609    }
18610
18611    pub fn toggle_inline_diagnostics(
18612        &mut self,
18613        _: &ToggleInlineDiagnostics,
18614        window: &mut Window,
18615        cx: &mut Context<Editor>,
18616    ) {
18617        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18618        self.refresh_inline_diagnostics(false, window, cx);
18619    }
18620
18621    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18622        self.diagnostics_max_severity = severity;
18623        self.display_map.update(cx, |display_map, _| {
18624            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18625        });
18626    }
18627
18628    pub fn toggle_diagnostics(
18629        &mut self,
18630        _: &ToggleDiagnostics,
18631        window: &mut Window,
18632        cx: &mut Context<Editor>,
18633    ) {
18634        if !self.diagnostics_enabled() {
18635            return;
18636        }
18637
18638        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18639            EditorSettings::get_global(cx)
18640                .diagnostics_max_severity
18641                .filter(|severity| severity != &DiagnosticSeverity::Off)
18642                .unwrap_or(DiagnosticSeverity::Hint)
18643        } else {
18644            DiagnosticSeverity::Off
18645        };
18646        self.set_max_diagnostics_severity(new_severity, cx);
18647        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18648            self.active_diagnostics = ActiveDiagnostic::None;
18649            self.inline_diagnostics_update = Task::ready(());
18650            self.inline_diagnostics.clear();
18651        } else {
18652            self.refresh_inline_diagnostics(false, window, cx);
18653        }
18654
18655        cx.notify();
18656    }
18657
18658    pub fn toggle_minimap(
18659        &mut self,
18660        _: &ToggleMinimap,
18661        window: &mut Window,
18662        cx: &mut Context<Editor>,
18663    ) {
18664        if self.supports_minimap(cx) {
18665            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18666        }
18667    }
18668
18669    fn refresh_inline_diagnostics(
18670        &mut self,
18671        debounce: bool,
18672        window: &mut Window,
18673        cx: &mut Context<Self>,
18674    ) {
18675        let max_severity = ProjectSettings::get_global(cx)
18676            .diagnostics
18677            .inline
18678            .max_severity
18679            .unwrap_or(self.diagnostics_max_severity);
18680
18681        if !self.inline_diagnostics_enabled()
18682            || !self.diagnostics_enabled()
18683            || !self.show_inline_diagnostics
18684            || max_severity == DiagnosticSeverity::Off
18685        {
18686            self.inline_diagnostics_update = Task::ready(());
18687            self.inline_diagnostics.clear();
18688            return;
18689        }
18690
18691        let debounce_ms = ProjectSettings::get_global(cx)
18692            .diagnostics
18693            .inline
18694            .update_debounce_ms;
18695        let debounce = if debounce && debounce_ms > 0 {
18696            Some(Duration::from_millis(debounce_ms))
18697        } else {
18698            None
18699        };
18700        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18701            if let Some(debounce) = debounce {
18702                cx.background_executor().timer(debounce).await;
18703            }
18704            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18705                editor
18706                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18707                    .ok()
18708            }) else {
18709                return;
18710            };
18711
18712            let new_inline_diagnostics = cx
18713                .background_spawn(async move {
18714                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18715                    for diagnostic_entry in
18716                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18717                    {
18718                        let message = diagnostic_entry
18719                            .diagnostic
18720                            .message
18721                            .split_once('\n')
18722                            .map(|(line, _)| line)
18723                            .map(SharedString::new)
18724                            .unwrap_or_else(|| {
18725                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18726                            });
18727                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18728                        let (Ok(i) | Err(i)) = inline_diagnostics
18729                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18730                        inline_diagnostics.insert(
18731                            i,
18732                            (
18733                                start_anchor,
18734                                InlineDiagnostic {
18735                                    message,
18736                                    group_id: diagnostic_entry.diagnostic.group_id,
18737                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18738                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18739                                    severity: diagnostic_entry.diagnostic.severity,
18740                                },
18741                            ),
18742                        );
18743                    }
18744                    inline_diagnostics
18745                })
18746                .await;
18747
18748            editor
18749                .update(cx, |editor, cx| {
18750                    editor.inline_diagnostics = new_inline_diagnostics;
18751                    cx.notify();
18752                })
18753                .ok();
18754        });
18755    }
18756
18757    fn pull_diagnostics(
18758        &mut self,
18759        buffer_id: Option<BufferId>,
18760        window: &Window,
18761        cx: &mut Context<Self>,
18762    ) -> Option<()> {
18763        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18764            return None;
18765        }
18766        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18767            .diagnostics
18768            .lsp_pull_diagnostics;
18769        if !pull_diagnostics_settings.enabled {
18770            return None;
18771        }
18772        let project = self.project()?.downgrade();
18773
18774        let mut edited_buffer_ids = HashSet::default();
18775        let mut edited_worktree_ids = HashSet::default();
18776        let edited_buffers = match buffer_id {
18777            Some(buffer_id) => {
18778                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
18779                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
18780                edited_buffer_ids.insert(buffer.read(cx).remote_id());
18781                edited_worktree_ids.insert(worktree_id);
18782                vec![buffer]
18783            }
18784            None => self
18785                .buffer()
18786                .read(cx)
18787                .all_buffers()
18788                .into_iter()
18789                .filter(|buffer| {
18790                    let buffer = buffer.read(cx);
18791                    match buffer.file().map(|f| f.worktree_id(cx)) {
18792                        Some(worktree_id) => {
18793                            edited_buffer_ids.insert(buffer.remote_id());
18794                            edited_worktree_ids.insert(worktree_id);
18795                            true
18796                        }
18797                        None => false,
18798                    }
18799                })
18800                .collect::<Vec<_>>(),
18801        };
18802
18803        if edited_buffers.is_empty() {
18804            self.pull_diagnostics_task = Task::ready(());
18805            self.pull_diagnostics_background_task = Task::ready(());
18806            return None;
18807        }
18808
18809        let mut already_used_buffers = HashSet::default();
18810        let related_open_buffers = self
18811            .workspace
18812            .as_ref()
18813            .and_then(|(workspace, _)| workspace.upgrade())
18814            .into_iter()
18815            .flat_map(|workspace| workspace.read(cx).panes())
18816            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
18817            .filter(|editor| editor != &cx.entity())
18818            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
18819            .filter(|buffer| {
18820                let buffer = buffer.read(cx);
18821                let buffer_id = buffer.remote_id();
18822                if already_used_buffers.insert(buffer_id) {
18823                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
18824                        return !edited_buffer_ids.contains(&buffer_id)
18825                            && !edited_worktree_ids.contains(&worktree_id);
18826                    }
18827                }
18828                false
18829            })
18830            .collect::<Vec<_>>();
18831
18832        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18833        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
18834            if buffers.is_empty() {
18835                return Task::ready(());
18836            }
18837            let project_weak = project.clone();
18838            cx.spawn_in(window, async move |_, cx| {
18839                cx.background_executor().timer(delay).await;
18840
18841                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18842                    buffers
18843                        .into_iter()
18844                        .filter_map(|buffer| {
18845                            project_weak
18846                                .update(cx, |project, cx| {
18847                                    project.lsp_store().update(cx, |lsp_store, cx| {
18848                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18849                                    })
18850                                })
18851                                .ok()
18852                        })
18853                        .collect::<FuturesUnordered<_>>()
18854                }) else {
18855                    return;
18856                };
18857
18858                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18859                    if let Err(e) = pull_task {
18860                        log::error!("Failed to update project diagnostics: {e:#}");
18861                    }
18862                }
18863            })
18864        };
18865
18866        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
18867        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
18868
18869        Some(())
18870    }
18871
18872    pub fn set_selections_from_remote(
18873        &mut self,
18874        selections: Vec<Selection<Anchor>>,
18875        pending_selection: Option<Selection<Anchor>>,
18876        window: &mut Window,
18877        cx: &mut Context<Self>,
18878    ) {
18879        let old_cursor_position = self.selections.newest_anchor().head();
18880        self.selections
18881            .change_with(&self.display_snapshot(cx), |s| {
18882                s.select_anchors(selections);
18883                if let Some(pending_selection) = pending_selection {
18884                    s.set_pending(pending_selection, SelectMode::Character);
18885                } else {
18886                    s.clear_pending();
18887                }
18888            });
18889        self.selections_did_change(
18890            false,
18891            &old_cursor_position,
18892            SelectionEffects::default(),
18893            window,
18894            cx,
18895        );
18896    }
18897
18898    pub fn transact(
18899        &mut self,
18900        window: &mut Window,
18901        cx: &mut Context<Self>,
18902        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18903    ) -> Option<TransactionId> {
18904        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18905            this.start_transaction_at(Instant::now(), window, cx);
18906            update(this, window, cx);
18907            this.end_transaction_at(Instant::now(), cx)
18908        })
18909    }
18910
18911    pub fn start_transaction_at(
18912        &mut self,
18913        now: Instant,
18914        window: &mut Window,
18915        cx: &mut Context<Self>,
18916    ) -> Option<TransactionId> {
18917        self.end_selection(window, cx);
18918        if let Some(tx_id) = self
18919            .buffer
18920            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18921        {
18922            self.selection_history
18923                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18924            cx.emit(EditorEvent::TransactionBegun {
18925                transaction_id: tx_id,
18926            });
18927            Some(tx_id)
18928        } else {
18929            None
18930        }
18931    }
18932
18933    pub fn end_transaction_at(
18934        &mut self,
18935        now: Instant,
18936        cx: &mut Context<Self>,
18937    ) -> Option<TransactionId> {
18938        if let Some(transaction_id) = self
18939            .buffer
18940            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18941        {
18942            if let Some((_, end_selections)) =
18943                self.selection_history.transaction_mut(transaction_id)
18944            {
18945                *end_selections = Some(self.selections.disjoint_anchors_arc());
18946            } else {
18947                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18948            }
18949
18950            cx.emit(EditorEvent::Edited { transaction_id });
18951            Some(transaction_id)
18952        } else {
18953            None
18954        }
18955    }
18956
18957    pub fn modify_transaction_selection_history(
18958        &mut self,
18959        transaction_id: TransactionId,
18960        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18961    ) -> bool {
18962        self.selection_history
18963            .transaction_mut(transaction_id)
18964            .map(modify)
18965            .is_some()
18966    }
18967
18968    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18969        if self.selection_mark_mode {
18970            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18971                s.move_with(|_, sel| {
18972                    sel.collapse_to(sel.head(), SelectionGoal::None);
18973                });
18974            })
18975        }
18976        self.selection_mark_mode = true;
18977        cx.notify();
18978    }
18979
18980    pub fn swap_selection_ends(
18981        &mut self,
18982        _: &actions::SwapSelectionEnds,
18983        window: &mut Window,
18984        cx: &mut Context<Self>,
18985    ) {
18986        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18987            s.move_with(|_, sel| {
18988                if sel.start != sel.end {
18989                    sel.reversed = !sel.reversed
18990                }
18991            });
18992        });
18993        self.request_autoscroll(Autoscroll::newest(), cx);
18994        cx.notify();
18995    }
18996
18997    pub fn toggle_focus(
18998        workspace: &mut Workspace,
18999        _: &actions::ToggleFocus,
19000        window: &mut Window,
19001        cx: &mut Context<Workspace>,
19002    ) {
19003        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19004            return;
19005        };
19006        workspace.activate_item(&item, true, true, window, cx);
19007    }
19008
19009    pub fn toggle_fold(
19010        &mut self,
19011        _: &actions::ToggleFold,
19012        window: &mut Window,
19013        cx: &mut Context<Self>,
19014    ) {
19015        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19016            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19017            let selection = self.selections.newest::<Point>(&display_map);
19018
19019            let range = if selection.is_empty() {
19020                let point = selection.head().to_display_point(&display_map);
19021                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19022                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19023                    .to_point(&display_map);
19024                start..end
19025            } else {
19026                selection.range()
19027            };
19028            if display_map.folds_in_range(range).next().is_some() {
19029                self.unfold_lines(&Default::default(), window, cx)
19030            } else {
19031                self.fold(&Default::default(), window, cx)
19032            }
19033        } else {
19034            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19035            let buffer_ids: HashSet<_> = self
19036                .selections
19037                .disjoint_anchor_ranges()
19038                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19039                .collect();
19040
19041            let should_unfold = buffer_ids
19042                .iter()
19043                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19044
19045            for buffer_id in buffer_ids {
19046                if should_unfold {
19047                    self.unfold_buffer(buffer_id, cx);
19048                } else {
19049                    self.fold_buffer(buffer_id, cx);
19050                }
19051            }
19052        }
19053    }
19054
19055    pub fn toggle_fold_recursive(
19056        &mut self,
19057        _: &actions::ToggleFoldRecursive,
19058        window: &mut Window,
19059        cx: &mut Context<Self>,
19060    ) {
19061        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19062
19063        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19064        let range = if selection.is_empty() {
19065            let point = selection.head().to_display_point(&display_map);
19066            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19067            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19068                .to_point(&display_map);
19069            start..end
19070        } else {
19071            selection.range()
19072        };
19073        if display_map.folds_in_range(range).next().is_some() {
19074            self.unfold_recursive(&Default::default(), window, cx)
19075        } else {
19076            self.fold_recursive(&Default::default(), window, cx)
19077        }
19078    }
19079
19080    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19081        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19082            let mut to_fold = Vec::new();
19083            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19084            let selections = self.selections.all_adjusted(&display_map);
19085
19086            for selection in selections {
19087                let range = selection.range().sorted();
19088                let buffer_start_row = range.start.row;
19089
19090                if range.start.row != range.end.row {
19091                    let mut found = false;
19092                    let mut row = range.start.row;
19093                    while row <= range.end.row {
19094                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19095                        {
19096                            found = true;
19097                            row = crease.range().end.row + 1;
19098                            to_fold.push(crease);
19099                        } else {
19100                            row += 1
19101                        }
19102                    }
19103                    if found {
19104                        continue;
19105                    }
19106                }
19107
19108                for row in (0..=range.start.row).rev() {
19109                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19110                        && crease.range().end.row >= buffer_start_row
19111                    {
19112                        to_fold.push(crease);
19113                        if row <= range.start.row {
19114                            break;
19115                        }
19116                    }
19117                }
19118            }
19119
19120            self.fold_creases(to_fold, true, window, cx);
19121        } else {
19122            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19123            let buffer_ids = self
19124                .selections
19125                .disjoint_anchor_ranges()
19126                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19127                .collect::<HashSet<_>>();
19128            for buffer_id in buffer_ids {
19129                self.fold_buffer(buffer_id, cx);
19130            }
19131        }
19132    }
19133
19134    pub fn toggle_fold_all(
19135        &mut self,
19136        _: &actions::ToggleFoldAll,
19137        window: &mut Window,
19138        cx: &mut Context<Self>,
19139    ) {
19140        if self.buffer.read(cx).is_singleton() {
19141            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19142            let has_folds = display_map
19143                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19144                .next()
19145                .is_some();
19146
19147            if has_folds {
19148                self.unfold_all(&actions::UnfoldAll, window, cx);
19149            } else {
19150                self.fold_all(&actions::FoldAll, window, cx);
19151            }
19152        } else {
19153            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19154            let should_unfold = buffer_ids
19155                .iter()
19156                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19157
19158            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19159                editor
19160                    .update_in(cx, |editor, _, cx| {
19161                        for buffer_id in buffer_ids {
19162                            if should_unfold {
19163                                editor.unfold_buffer(buffer_id, cx);
19164                            } else {
19165                                editor.fold_buffer(buffer_id, cx);
19166                            }
19167                        }
19168                    })
19169                    .ok();
19170            });
19171        }
19172    }
19173
19174    fn fold_at_level(
19175        &mut self,
19176        fold_at: &FoldAtLevel,
19177        window: &mut Window,
19178        cx: &mut Context<Self>,
19179    ) {
19180        if !self.buffer.read(cx).is_singleton() {
19181            return;
19182        }
19183
19184        let fold_at_level = fold_at.0;
19185        let snapshot = self.buffer.read(cx).snapshot(cx);
19186        let mut to_fold = Vec::new();
19187        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19188
19189        let row_ranges_to_keep: Vec<Range<u32>> = self
19190            .selections
19191            .all::<Point>(&self.display_snapshot(cx))
19192            .into_iter()
19193            .map(|sel| sel.start.row..sel.end.row)
19194            .collect();
19195
19196        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19197            while start_row < end_row {
19198                match self
19199                    .snapshot(window, cx)
19200                    .crease_for_buffer_row(MultiBufferRow(start_row))
19201                {
19202                    Some(crease) => {
19203                        let nested_start_row = crease.range().start.row + 1;
19204                        let nested_end_row = crease.range().end.row;
19205
19206                        if current_level < fold_at_level {
19207                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19208                        } else if current_level == fold_at_level {
19209                            // Fold iff there is no selection completely contained within the fold region
19210                            if !row_ranges_to_keep.iter().any(|selection| {
19211                                selection.end >= nested_start_row
19212                                    && selection.start <= nested_end_row
19213                            }) {
19214                                to_fold.push(crease);
19215                            }
19216                        }
19217
19218                        start_row = nested_end_row + 1;
19219                    }
19220                    None => start_row += 1,
19221                }
19222            }
19223        }
19224
19225        self.fold_creases(to_fold, true, window, cx);
19226    }
19227
19228    pub fn fold_at_level_1(
19229        &mut self,
19230        _: &actions::FoldAtLevel1,
19231        window: &mut Window,
19232        cx: &mut Context<Self>,
19233    ) {
19234        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19235    }
19236
19237    pub fn fold_at_level_2(
19238        &mut self,
19239        _: &actions::FoldAtLevel2,
19240        window: &mut Window,
19241        cx: &mut Context<Self>,
19242    ) {
19243        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19244    }
19245
19246    pub fn fold_at_level_3(
19247        &mut self,
19248        _: &actions::FoldAtLevel3,
19249        window: &mut Window,
19250        cx: &mut Context<Self>,
19251    ) {
19252        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19253    }
19254
19255    pub fn fold_at_level_4(
19256        &mut self,
19257        _: &actions::FoldAtLevel4,
19258        window: &mut Window,
19259        cx: &mut Context<Self>,
19260    ) {
19261        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19262    }
19263
19264    pub fn fold_at_level_5(
19265        &mut self,
19266        _: &actions::FoldAtLevel5,
19267        window: &mut Window,
19268        cx: &mut Context<Self>,
19269    ) {
19270        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19271    }
19272
19273    pub fn fold_at_level_6(
19274        &mut self,
19275        _: &actions::FoldAtLevel6,
19276        window: &mut Window,
19277        cx: &mut Context<Self>,
19278    ) {
19279        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19280    }
19281
19282    pub fn fold_at_level_7(
19283        &mut self,
19284        _: &actions::FoldAtLevel7,
19285        window: &mut Window,
19286        cx: &mut Context<Self>,
19287    ) {
19288        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19289    }
19290
19291    pub fn fold_at_level_8(
19292        &mut self,
19293        _: &actions::FoldAtLevel8,
19294        window: &mut Window,
19295        cx: &mut Context<Self>,
19296    ) {
19297        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19298    }
19299
19300    pub fn fold_at_level_9(
19301        &mut self,
19302        _: &actions::FoldAtLevel9,
19303        window: &mut Window,
19304        cx: &mut Context<Self>,
19305    ) {
19306        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19307    }
19308
19309    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19310        if self.buffer.read(cx).is_singleton() {
19311            let mut fold_ranges = Vec::new();
19312            let snapshot = self.buffer.read(cx).snapshot(cx);
19313
19314            for row in 0..snapshot.max_row().0 {
19315                if let Some(foldable_range) = self
19316                    .snapshot(window, cx)
19317                    .crease_for_buffer_row(MultiBufferRow(row))
19318                {
19319                    fold_ranges.push(foldable_range);
19320                }
19321            }
19322
19323            self.fold_creases(fold_ranges, true, window, cx);
19324        } else {
19325            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19326                editor
19327                    .update_in(cx, |editor, _, cx| {
19328                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19329                            editor.fold_buffer(buffer_id, cx);
19330                        }
19331                    })
19332                    .ok();
19333            });
19334        }
19335    }
19336
19337    pub fn fold_function_bodies(
19338        &mut self,
19339        _: &actions::FoldFunctionBodies,
19340        window: &mut Window,
19341        cx: &mut Context<Self>,
19342    ) {
19343        let snapshot = self.buffer.read(cx).snapshot(cx);
19344
19345        let ranges = snapshot
19346            .text_object_ranges(
19347                MultiBufferOffset(0)..snapshot.len(),
19348                TreeSitterOptions::default(),
19349            )
19350            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19351            .collect::<Vec<_>>();
19352
19353        let creases = ranges
19354            .into_iter()
19355            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19356            .collect();
19357
19358        self.fold_creases(creases, true, window, cx);
19359    }
19360
19361    pub fn fold_recursive(
19362        &mut self,
19363        _: &actions::FoldRecursive,
19364        window: &mut Window,
19365        cx: &mut Context<Self>,
19366    ) {
19367        let mut to_fold = Vec::new();
19368        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19369        let selections = self.selections.all_adjusted(&display_map);
19370
19371        for selection in selections {
19372            let range = selection.range().sorted();
19373            let buffer_start_row = range.start.row;
19374
19375            if range.start.row != range.end.row {
19376                let mut found = false;
19377                for row in range.start.row..=range.end.row {
19378                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19379                        found = true;
19380                        to_fold.push(crease);
19381                    }
19382                }
19383                if found {
19384                    continue;
19385                }
19386            }
19387
19388            for row in (0..=range.start.row).rev() {
19389                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19390                    if crease.range().end.row >= buffer_start_row {
19391                        to_fold.push(crease);
19392                    } else {
19393                        break;
19394                    }
19395                }
19396            }
19397        }
19398
19399        self.fold_creases(to_fold, true, window, cx);
19400    }
19401
19402    pub fn fold_at(
19403        &mut self,
19404        buffer_row: MultiBufferRow,
19405        window: &mut Window,
19406        cx: &mut Context<Self>,
19407    ) {
19408        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19409
19410        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19411            let autoscroll = self
19412                .selections
19413                .all::<Point>(&display_map)
19414                .iter()
19415                .any(|selection| crease.range().overlaps(&selection.range()));
19416
19417            self.fold_creases(vec![crease], autoscroll, window, cx);
19418        }
19419    }
19420
19421    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19422        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19423            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19424            let buffer = display_map.buffer_snapshot();
19425            let selections = self.selections.all::<Point>(&display_map);
19426            let ranges = selections
19427                .iter()
19428                .map(|s| {
19429                    let range = s.display_range(&display_map).sorted();
19430                    let mut start = range.start.to_point(&display_map);
19431                    let mut end = range.end.to_point(&display_map);
19432                    start.column = 0;
19433                    end.column = buffer.line_len(MultiBufferRow(end.row));
19434                    start..end
19435                })
19436                .collect::<Vec<_>>();
19437
19438            self.unfold_ranges(&ranges, true, true, cx);
19439        } else {
19440            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19441            let buffer_ids = self
19442                .selections
19443                .disjoint_anchor_ranges()
19444                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19445                .collect::<HashSet<_>>();
19446            for buffer_id in buffer_ids {
19447                self.unfold_buffer(buffer_id, cx);
19448            }
19449        }
19450    }
19451
19452    pub fn unfold_recursive(
19453        &mut self,
19454        _: &UnfoldRecursive,
19455        _window: &mut Window,
19456        cx: &mut Context<Self>,
19457    ) {
19458        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19459        let selections = self.selections.all::<Point>(&display_map);
19460        let ranges = selections
19461            .iter()
19462            .map(|s| {
19463                let mut range = s.display_range(&display_map).sorted();
19464                *range.start.column_mut() = 0;
19465                *range.end.column_mut() = display_map.line_len(range.end.row());
19466                let start = range.start.to_point(&display_map);
19467                let end = range.end.to_point(&display_map);
19468                start..end
19469            })
19470            .collect::<Vec<_>>();
19471
19472        self.unfold_ranges(&ranges, true, true, cx);
19473    }
19474
19475    pub fn unfold_at(
19476        &mut self,
19477        buffer_row: MultiBufferRow,
19478        _window: &mut Window,
19479        cx: &mut Context<Self>,
19480    ) {
19481        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19482
19483        let intersection_range = Point::new(buffer_row.0, 0)
19484            ..Point::new(
19485                buffer_row.0,
19486                display_map.buffer_snapshot().line_len(buffer_row),
19487            );
19488
19489        let autoscroll = self
19490            .selections
19491            .all::<Point>(&display_map)
19492            .iter()
19493            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19494
19495        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19496    }
19497
19498    pub fn unfold_all(
19499        &mut self,
19500        _: &actions::UnfoldAll,
19501        _window: &mut Window,
19502        cx: &mut Context<Self>,
19503    ) {
19504        if self.buffer.read(cx).is_singleton() {
19505            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19506            self.unfold_ranges(
19507                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19508                true,
19509                true,
19510                cx,
19511            );
19512        } else {
19513            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19514                editor
19515                    .update(cx, |editor, cx| {
19516                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19517                            editor.unfold_buffer(buffer_id, cx);
19518                        }
19519                    })
19520                    .ok();
19521            });
19522        }
19523    }
19524
19525    pub fn fold_selected_ranges(
19526        &mut self,
19527        _: &FoldSelectedRanges,
19528        window: &mut Window,
19529        cx: &mut Context<Self>,
19530    ) {
19531        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19532        let selections = self.selections.all_adjusted(&display_map);
19533        let ranges = selections
19534            .into_iter()
19535            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19536            .collect::<Vec<_>>();
19537        self.fold_creases(ranges, true, window, cx);
19538    }
19539
19540    pub fn fold_ranges<T: ToOffset + Clone>(
19541        &mut self,
19542        ranges: Vec<Range<T>>,
19543        auto_scroll: bool,
19544        window: &mut Window,
19545        cx: &mut Context<Self>,
19546    ) {
19547        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19548        let ranges = ranges
19549            .into_iter()
19550            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19551            .collect::<Vec<_>>();
19552        self.fold_creases(ranges, auto_scroll, window, cx);
19553    }
19554
19555    pub fn fold_creases<T: ToOffset + Clone>(
19556        &mut self,
19557        creases: Vec<Crease<T>>,
19558        auto_scroll: bool,
19559        _window: &mut Window,
19560        cx: &mut Context<Self>,
19561    ) {
19562        if creases.is_empty() {
19563            return;
19564        }
19565
19566        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19567
19568        if auto_scroll {
19569            self.request_autoscroll(Autoscroll::fit(), cx);
19570        }
19571
19572        cx.notify();
19573
19574        self.scrollbar_marker_state.dirty = true;
19575        self.folds_did_change(cx);
19576    }
19577
19578    /// Removes any folds whose ranges intersect any of the given ranges.
19579    pub fn unfold_ranges<T: ToOffset + Clone>(
19580        &mut self,
19581        ranges: &[Range<T>],
19582        inclusive: bool,
19583        auto_scroll: bool,
19584        cx: &mut Context<Self>,
19585    ) {
19586        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19587            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19588        });
19589        self.folds_did_change(cx);
19590    }
19591
19592    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19593        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19594            return;
19595        }
19596
19597        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19598        self.display_map.update(cx, |display_map, cx| {
19599            display_map.fold_buffers([buffer_id], cx)
19600        });
19601
19602        let snapshot = self.display_snapshot(cx);
19603        self.selections.change_with(&snapshot, |selections| {
19604            selections.remove_selections_from_buffer(buffer_id);
19605        });
19606
19607        cx.emit(EditorEvent::BufferFoldToggled {
19608            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19609            folded: true,
19610        });
19611        cx.notify();
19612    }
19613
19614    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19615        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19616            return;
19617        }
19618        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19619        self.display_map.update(cx, |display_map, cx| {
19620            display_map.unfold_buffers([buffer_id], cx);
19621        });
19622        cx.emit(EditorEvent::BufferFoldToggled {
19623            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19624            folded: false,
19625        });
19626        cx.notify();
19627    }
19628
19629    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19630        self.display_map.read(cx).is_buffer_folded(buffer)
19631    }
19632
19633    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19634        self.display_map.read(cx).folded_buffers()
19635    }
19636
19637    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19638        self.display_map.update(cx, |display_map, cx| {
19639            display_map.disable_header_for_buffer(buffer_id, cx);
19640        });
19641        cx.notify();
19642    }
19643
19644    /// Removes any folds with the given ranges.
19645    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19646        &mut self,
19647        ranges: &[Range<T>],
19648        type_id: TypeId,
19649        auto_scroll: bool,
19650        cx: &mut Context<Self>,
19651    ) {
19652        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19653            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19654        });
19655        self.folds_did_change(cx);
19656    }
19657
19658    fn remove_folds_with<T: ToOffset + Clone>(
19659        &mut self,
19660        ranges: &[Range<T>],
19661        auto_scroll: bool,
19662        cx: &mut Context<Self>,
19663        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19664    ) {
19665        if ranges.is_empty() {
19666            return;
19667        }
19668
19669        let mut buffers_affected = HashSet::default();
19670        let multi_buffer = self.buffer().read(cx);
19671        for range in ranges {
19672            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19673                buffers_affected.insert(buffer.read(cx).remote_id());
19674            };
19675        }
19676
19677        self.display_map.update(cx, update);
19678
19679        if auto_scroll {
19680            self.request_autoscroll(Autoscroll::fit(), cx);
19681        }
19682
19683        cx.notify();
19684        self.scrollbar_marker_state.dirty = true;
19685        self.active_indent_guides_state.dirty = true;
19686    }
19687
19688    pub fn update_renderer_widths(
19689        &mut self,
19690        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19691        cx: &mut Context<Self>,
19692    ) -> bool {
19693        self.display_map
19694            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19695    }
19696
19697    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19698        self.display_map.read(cx).fold_placeholder.clone()
19699    }
19700
19701    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19702        self.use_base_text_line_numbers = show;
19703    }
19704
19705    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19706        self.buffer.update(cx, |buffer, cx| {
19707            buffer.set_all_diff_hunks_expanded(cx);
19708        });
19709    }
19710
19711    pub fn expand_all_diff_hunks(
19712        &mut self,
19713        _: &ExpandAllDiffHunks,
19714        _window: &mut Window,
19715        cx: &mut Context<Self>,
19716    ) {
19717        self.buffer.update(cx, |buffer, cx| {
19718            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19719        });
19720    }
19721
19722    pub fn collapse_all_diff_hunks(
19723        &mut self,
19724        _: &CollapseAllDiffHunks,
19725        _window: &mut Window,
19726        cx: &mut Context<Self>,
19727    ) {
19728        self.buffer.update(cx, |buffer, cx| {
19729            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19730        });
19731    }
19732
19733    pub fn toggle_selected_diff_hunks(
19734        &mut self,
19735        _: &ToggleSelectedDiffHunks,
19736        _window: &mut Window,
19737        cx: &mut Context<Self>,
19738    ) {
19739        let ranges: Vec<_> = self
19740            .selections
19741            .disjoint_anchors()
19742            .iter()
19743            .map(|s| s.range())
19744            .collect();
19745        self.toggle_diff_hunks_in_ranges(ranges, cx);
19746    }
19747
19748    pub fn diff_hunks_in_ranges<'a>(
19749        &'a self,
19750        ranges: &'a [Range<Anchor>],
19751        buffer: &'a MultiBufferSnapshot,
19752    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19753        ranges.iter().flat_map(move |range| {
19754            let end_excerpt_id = range.end.excerpt_id;
19755            let range = range.to_point(buffer);
19756            let mut peek_end = range.end;
19757            if range.end.row < buffer.max_row().0 {
19758                peek_end = Point::new(range.end.row + 1, 0);
19759            }
19760            buffer
19761                .diff_hunks_in_range(range.start..peek_end)
19762                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19763        })
19764    }
19765
19766    pub fn has_stageable_diff_hunks_in_ranges(
19767        &self,
19768        ranges: &[Range<Anchor>],
19769        snapshot: &MultiBufferSnapshot,
19770    ) -> bool {
19771        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19772        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19773    }
19774
19775    pub fn toggle_staged_selected_diff_hunks(
19776        &mut self,
19777        _: &::git::ToggleStaged,
19778        _: &mut Window,
19779        cx: &mut Context<Self>,
19780    ) {
19781        let snapshot = self.buffer.read(cx).snapshot(cx);
19782        let ranges: Vec<_> = self
19783            .selections
19784            .disjoint_anchors()
19785            .iter()
19786            .map(|s| s.range())
19787            .collect();
19788        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19789        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19790    }
19791
19792    pub fn set_render_diff_hunk_controls(
19793        &mut self,
19794        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19795        cx: &mut Context<Self>,
19796    ) {
19797        self.render_diff_hunk_controls = render_diff_hunk_controls;
19798        cx.notify();
19799    }
19800
19801    pub fn stage_and_next(
19802        &mut self,
19803        _: &::git::StageAndNext,
19804        window: &mut Window,
19805        cx: &mut Context<Self>,
19806    ) {
19807        self.do_stage_or_unstage_and_next(true, window, cx);
19808    }
19809
19810    pub fn unstage_and_next(
19811        &mut self,
19812        _: &::git::UnstageAndNext,
19813        window: &mut Window,
19814        cx: &mut Context<Self>,
19815    ) {
19816        self.do_stage_or_unstage_and_next(false, window, cx);
19817    }
19818
19819    pub fn stage_or_unstage_diff_hunks(
19820        &mut self,
19821        stage: bool,
19822        ranges: Vec<Range<Anchor>>,
19823        cx: &mut Context<Self>,
19824    ) {
19825        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19826        cx.spawn(async move |this, cx| {
19827            task.await?;
19828            this.update(cx, |this, cx| {
19829                let snapshot = this.buffer.read(cx).snapshot(cx);
19830                let chunk_by = this
19831                    .diff_hunks_in_ranges(&ranges, &snapshot)
19832                    .chunk_by(|hunk| hunk.buffer_id);
19833                for (buffer_id, hunks) in &chunk_by {
19834                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19835                }
19836            })
19837        })
19838        .detach_and_log_err(cx);
19839    }
19840
19841    fn save_buffers_for_ranges_if_needed(
19842        &mut self,
19843        ranges: &[Range<Anchor>],
19844        cx: &mut Context<Editor>,
19845    ) -> Task<Result<()>> {
19846        let multibuffer = self.buffer.read(cx);
19847        let snapshot = multibuffer.read(cx);
19848        let buffer_ids: HashSet<_> = ranges
19849            .iter()
19850            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19851            .collect();
19852        drop(snapshot);
19853
19854        let mut buffers = HashSet::default();
19855        for buffer_id in buffer_ids {
19856            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19857                let buffer = buffer_entity.read(cx);
19858                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19859                {
19860                    buffers.insert(buffer_entity);
19861                }
19862            }
19863        }
19864
19865        if let Some(project) = &self.project {
19866            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19867        } else {
19868            Task::ready(Ok(()))
19869        }
19870    }
19871
19872    fn do_stage_or_unstage_and_next(
19873        &mut self,
19874        stage: bool,
19875        window: &mut Window,
19876        cx: &mut Context<Self>,
19877    ) {
19878        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19879
19880        if ranges.iter().any(|range| range.start != range.end) {
19881            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19882            return;
19883        }
19884
19885        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19886        let snapshot = self.snapshot(window, cx);
19887        let position = self
19888            .selections
19889            .newest::<Point>(&snapshot.display_snapshot)
19890            .head();
19891        let mut row = snapshot
19892            .buffer_snapshot()
19893            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19894            .find(|hunk| hunk.row_range.start.0 > position.row)
19895            .map(|hunk| hunk.row_range.start);
19896
19897        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19898        // Outside of the project diff editor, wrap around to the beginning.
19899        if !all_diff_hunks_expanded {
19900            row = row.or_else(|| {
19901                snapshot
19902                    .buffer_snapshot()
19903                    .diff_hunks_in_range(Point::zero()..position)
19904                    .find(|hunk| hunk.row_range.end.0 < position.row)
19905                    .map(|hunk| hunk.row_range.start)
19906            });
19907        }
19908
19909        if let Some(row) = row {
19910            let destination = Point::new(row.0, 0);
19911            let autoscroll = Autoscroll::center();
19912
19913            self.unfold_ranges(&[destination..destination], false, false, cx);
19914            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19915                s.select_ranges([destination..destination]);
19916            });
19917        }
19918    }
19919
19920    fn do_stage_or_unstage(
19921        &self,
19922        stage: bool,
19923        buffer_id: BufferId,
19924        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19925        cx: &mut App,
19926    ) -> Option<()> {
19927        let project = self.project()?;
19928        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19929        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19930        let buffer_snapshot = buffer.read(cx).snapshot();
19931        let file_exists = buffer_snapshot
19932            .file()
19933            .is_some_and(|file| file.disk_state().exists());
19934        diff.update(cx, |diff, cx| {
19935            diff.stage_or_unstage_hunks(
19936                stage,
19937                &hunks
19938                    .map(|hunk| buffer_diff::DiffHunk {
19939                        buffer_range: hunk.buffer_range,
19940                        // We don't need to pass in word diffs here because they're only used for rendering and
19941                        // this function changes internal state
19942                        base_word_diffs: Vec::default(),
19943                        buffer_word_diffs: Vec::default(),
19944                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19945                            ..hunk.diff_base_byte_range.end.0,
19946                        secondary_status: hunk.secondary_status,
19947                        range: Point::zero()..Point::zero(), // unused
19948                    })
19949                    .collect::<Vec<_>>(),
19950                &buffer_snapshot,
19951                file_exists,
19952                cx,
19953            )
19954        });
19955        None
19956    }
19957
19958    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19959        let ranges: Vec<_> = self
19960            .selections
19961            .disjoint_anchors()
19962            .iter()
19963            .map(|s| s.range())
19964            .collect();
19965        self.buffer
19966            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19967    }
19968
19969    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19970        self.buffer.update(cx, |buffer, cx| {
19971            let ranges = vec![Anchor::min()..Anchor::max()];
19972            if !buffer.all_diff_hunks_expanded()
19973                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19974            {
19975                buffer.collapse_diff_hunks(ranges, cx);
19976                true
19977            } else {
19978                false
19979            }
19980        })
19981    }
19982
19983    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19984        if self.buffer.read(cx).all_diff_hunks_expanded() {
19985            return true;
19986        }
19987        let ranges = vec![Anchor::min()..Anchor::max()];
19988        self.buffer
19989            .read(cx)
19990            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19991    }
19992
19993    fn toggle_diff_hunks_in_ranges(
19994        &mut self,
19995        ranges: Vec<Range<Anchor>>,
19996        cx: &mut Context<Editor>,
19997    ) {
19998        self.buffer.update(cx, |buffer, cx| {
19999            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
20000            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
20001        })
20002    }
20003
20004    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20005        self.buffer.update(cx, |buffer, cx| {
20006            let snapshot = buffer.snapshot(cx);
20007            let excerpt_id = range.end.excerpt_id;
20008            let point_range = range.to_point(&snapshot);
20009            let expand = !buffer.single_hunk_is_expanded(range, cx);
20010            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
20011        })
20012    }
20013
20014    pub(crate) fn apply_all_diff_hunks(
20015        &mut self,
20016        _: &ApplyAllDiffHunks,
20017        window: &mut Window,
20018        cx: &mut Context<Self>,
20019    ) {
20020        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20021
20022        let buffers = self.buffer.read(cx).all_buffers();
20023        for branch_buffer in buffers {
20024            branch_buffer.update(cx, |branch_buffer, cx| {
20025                branch_buffer.merge_into_base(Vec::new(), cx);
20026            });
20027        }
20028
20029        if let Some(project) = self.project.clone() {
20030            self.save(
20031                SaveOptions {
20032                    format: true,
20033                    autosave: false,
20034                },
20035                project,
20036                window,
20037                cx,
20038            )
20039            .detach_and_log_err(cx);
20040        }
20041    }
20042
20043    pub(crate) fn apply_selected_diff_hunks(
20044        &mut self,
20045        _: &ApplyDiffHunk,
20046        window: &mut Window,
20047        cx: &mut Context<Self>,
20048    ) {
20049        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20050        let snapshot = self.snapshot(window, cx);
20051        let hunks = snapshot.hunks_for_ranges(
20052            self.selections
20053                .all(&snapshot.display_snapshot)
20054                .into_iter()
20055                .map(|selection| selection.range()),
20056        );
20057        let mut ranges_by_buffer = HashMap::default();
20058        self.transact(window, cx, |editor, _window, cx| {
20059            for hunk in hunks {
20060                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20061                    ranges_by_buffer
20062                        .entry(buffer.clone())
20063                        .or_insert_with(Vec::new)
20064                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20065                }
20066            }
20067
20068            for (buffer, ranges) in ranges_by_buffer {
20069                buffer.update(cx, |buffer, cx| {
20070                    buffer.merge_into_base(ranges, cx);
20071                });
20072            }
20073        });
20074
20075        if let Some(project) = self.project.clone() {
20076            self.save(
20077                SaveOptions {
20078                    format: true,
20079                    autosave: false,
20080                },
20081                project,
20082                window,
20083                cx,
20084            )
20085            .detach_and_log_err(cx);
20086        }
20087    }
20088
20089    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20090        if hovered != self.gutter_hovered {
20091            self.gutter_hovered = hovered;
20092            cx.notify();
20093        }
20094    }
20095
20096    pub fn insert_blocks(
20097        &mut self,
20098        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20099        autoscroll: Option<Autoscroll>,
20100        cx: &mut Context<Self>,
20101    ) -> Vec<CustomBlockId> {
20102        let blocks = self
20103            .display_map
20104            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20105        if let Some(autoscroll) = autoscroll {
20106            self.request_autoscroll(autoscroll, cx);
20107        }
20108        cx.notify();
20109        blocks
20110    }
20111
20112    pub fn resize_blocks(
20113        &mut self,
20114        heights: HashMap<CustomBlockId, u32>,
20115        autoscroll: Option<Autoscroll>,
20116        cx: &mut Context<Self>,
20117    ) {
20118        self.display_map
20119            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20120        if let Some(autoscroll) = autoscroll {
20121            self.request_autoscroll(autoscroll, cx);
20122        }
20123        cx.notify();
20124    }
20125
20126    pub fn replace_blocks(
20127        &mut self,
20128        renderers: HashMap<CustomBlockId, RenderBlock>,
20129        autoscroll: Option<Autoscroll>,
20130        cx: &mut Context<Self>,
20131    ) {
20132        self.display_map
20133            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20134        if let Some(autoscroll) = autoscroll {
20135            self.request_autoscroll(autoscroll, cx);
20136        }
20137        cx.notify();
20138    }
20139
20140    pub fn remove_blocks(
20141        &mut self,
20142        block_ids: HashSet<CustomBlockId>,
20143        autoscroll: Option<Autoscroll>,
20144        cx: &mut Context<Self>,
20145    ) {
20146        self.display_map.update(cx, |display_map, cx| {
20147            display_map.remove_blocks(block_ids, cx)
20148        });
20149        if let Some(autoscroll) = autoscroll {
20150            self.request_autoscroll(autoscroll, cx);
20151        }
20152        cx.notify();
20153    }
20154
20155    pub fn row_for_block(
20156        &self,
20157        block_id: CustomBlockId,
20158        cx: &mut Context<Self>,
20159    ) -> Option<DisplayRow> {
20160        self.display_map
20161            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20162    }
20163
20164    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20165        self.focused_block = Some(focused_block);
20166    }
20167
20168    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20169        self.focused_block.take()
20170    }
20171
20172    pub fn insert_creases(
20173        &mut self,
20174        creases: impl IntoIterator<Item = Crease<Anchor>>,
20175        cx: &mut Context<Self>,
20176    ) -> Vec<CreaseId> {
20177        self.display_map
20178            .update(cx, |map, cx| map.insert_creases(creases, cx))
20179    }
20180
20181    pub fn remove_creases(
20182        &mut self,
20183        ids: impl IntoIterator<Item = CreaseId>,
20184        cx: &mut Context<Self>,
20185    ) -> Vec<(CreaseId, Range<Anchor>)> {
20186        self.display_map
20187            .update(cx, |map, cx| map.remove_creases(ids, cx))
20188    }
20189
20190    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20191        self.display_map
20192            .update(cx, |map, cx| map.snapshot(cx))
20193            .longest_row()
20194    }
20195
20196    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20197        self.display_map
20198            .update(cx, |map, cx| map.snapshot(cx))
20199            .max_point()
20200    }
20201
20202    pub fn text(&self, cx: &App) -> String {
20203        self.buffer.read(cx).read(cx).text()
20204    }
20205
20206    pub fn is_empty(&self, cx: &App) -> bool {
20207        self.buffer.read(cx).read(cx).is_empty()
20208    }
20209
20210    pub fn text_option(&self, cx: &App) -> Option<String> {
20211        let text = self.text(cx);
20212        let text = text.trim();
20213
20214        if text.is_empty() {
20215            return None;
20216        }
20217
20218        Some(text.to_string())
20219    }
20220
20221    pub fn set_text(
20222        &mut self,
20223        text: impl Into<Arc<str>>,
20224        window: &mut Window,
20225        cx: &mut Context<Self>,
20226    ) {
20227        self.transact(window, cx, |this, _, cx| {
20228            this.buffer
20229                .read(cx)
20230                .as_singleton()
20231                .expect("you can only call set_text on editors for singleton buffers")
20232                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20233        });
20234    }
20235
20236    pub fn display_text(&self, cx: &mut App) -> String {
20237        self.display_map
20238            .update(cx, |map, cx| map.snapshot(cx))
20239            .text()
20240    }
20241
20242    fn create_minimap(
20243        &self,
20244        minimap_settings: MinimapSettings,
20245        window: &mut Window,
20246        cx: &mut Context<Self>,
20247    ) -> Option<Entity<Self>> {
20248        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20249            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20250    }
20251
20252    fn initialize_new_minimap(
20253        &self,
20254        minimap_settings: MinimapSettings,
20255        window: &mut Window,
20256        cx: &mut Context<Self>,
20257    ) -> Entity<Self> {
20258        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20259
20260        let mut minimap = Editor::new_internal(
20261            EditorMode::Minimap {
20262                parent: cx.weak_entity(),
20263            },
20264            self.buffer.clone(),
20265            None,
20266            Some(self.display_map.clone()),
20267            window,
20268            cx,
20269        );
20270        minimap.scroll_manager.clone_state(&self.scroll_manager);
20271        minimap.set_text_style_refinement(TextStyleRefinement {
20272            font_size: Some(MINIMAP_FONT_SIZE),
20273            font_weight: Some(MINIMAP_FONT_WEIGHT),
20274            ..Default::default()
20275        });
20276        minimap.update_minimap_configuration(minimap_settings, cx);
20277        cx.new(|_| minimap)
20278    }
20279
20280    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20281        let current_line_highlight = minimap_settings
20282            .current_line_highlight
20283            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20284        self.set_current_line_highlight(Some(current_line_highlight));
20285    }
20286
20287    pub fn minimap(&self) -> Option<&Entity<Self>> {
20288        self.minimap
20289            .as_ref()
20290            .filter(|_| self.minimap_visibility.visible())
20291    }
20292
20293    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20294        let mut wrap_guides = smallvec![];
20295
20296        if self.show_wrap_guides == Some(false) {
20297            return wrap_guides;
20298        }
20299
20300        let settings = self.buffer.read(cx).language_settings(cx);
20301        if settings.show_wrap_guides {
20302            match self.soft_wrap_mode(cx) {
20303                SoftWrap::Column(soft_wrap) => {
20304                    wrap_guides.push((soft_wrap as usize, true));
20305                }
20306                SoftWrap::Bounded(soft_wrap) => {
20307                    wrap_guides.push((soft_wrap as usize, true));
20308                }
20309                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20310            }
20311            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20312        }
20313
20314        wrap_guides
20315    }
20316
20317    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20318        let settings = self.buffer.read(cx).language_settings(cx);
20319        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20320        match mode {
20321            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20322                SoftWrap::None
20323            }
20324            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20325            language_settings::SoftWrap::PreferredLineLength => {
20326                SoftWrap::Column(settings.preferred_line_length)
20327            }
20328            language_settings::SoftWrap::Bounded => {
20329                SoftWrap::Bounded(settings.preferred_line_length)
20330            }
20331        }
20332    }
20333
20334    pub fn set_soft_wrap_mode(
20335        &mut self,
20336        mode: language_settings::SoftWrap,
20337
20338        cx: &mut Context<Self>,
20339    ) {
20340        self.soft_wrap_mode_override = Some(mode);
20341        cx.notify();
20342    }
20343
20344    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20345        self.hard_wrap = hard_wrap;
20346        cx.notify();
20347    }
20348
20349    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20350        self.text_style_refinement = Some(style);
20351    }
20352
20353    /// called by the Element so we know what style we were most recently rendered with.
20354    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20355        // We intentionally do not inform the display map about the minimap style
20356        // so that wrapping is not recalculated and stays consistent for the editor
20357        // and its linked minimap.
20358        if !self.mode.is_minimap() {
20359            let font = style.text.font();
20360            let font_size = style.text.font_size.to_pixels(window.rem_size());
20361            let display_map = self
20362                .placeholder_display_map
20363                .as_ref()
20364                .filter(|_| self.is_empty(cx))
20365                .unwrap_or(&self.display_map);
20366
20367            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20368        }
20369        self.style = Some(style);
20370    }
20371
20372    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20373        if self.style.is_none() {
20374            self.style = Some(self.create_style(cx));
20375        }
20376        self.style.as_ref().unwrap()
20377    }
20378
20379    // Called by the element. This method is not designed to be called outside of the editor
20380    // element's layout code because it does not notify when rewrapping is computed synchronously.
20381    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20382        if self.is_empty(cx) {
20383            self.placeholder_display_map
20384                .as_ref()
20385                .map_or(false, |display_map| {
20386                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20387                })
20388        } else {
20389            self.display_map
20390                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20391        }
20392    }
20393
20394    pub fn set_soft_wrap(&mut self) {
20395        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20396    }
20397
20398    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20399        if self.soft_wrap_mode_override.is_some() {
20400            self.soft_wrap_mode_override.take();
20401        } else {
20402            let soft_wrap = match self.soft_wrap_mode(cx) {
20403                SoftWrap::GitDiff => return,
20404                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20405                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20406                    language_settings::SoftWrap::None
20407                }
20408            };
20409            self.soft_wrap_mode_override = Some(soft_wrap);
20410        }
20411        cx.notify();
20412    }
20413
20414    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20415        let Some(workspace) = self.workspace() else {
20416            return;
20417        };
20418        let fs = workspace.read(cx).app_state().fs.clone();
20419        let current_show = TabBarSettings::get_global(cx).show;
20420        update_settings_file(fs, cx, move |setting, _| {
20421            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20422        });
20423    }
20424
20425    pub fn toggle_indent_guides(
20426        &mut self,
20427        _: &ToggleIndentGuides,
20428        _: &mut Window,
20429        cx: &mut Context<Self>,
20430    ) {
20431        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20432            self.buffer
20433                .read(cx)
20434                .language_settings(cx)
20435                .indent_guides
20436                .enabled
20437        });
20438        self.show_indent_guides = Some(!currently_enabled);
20439        cx.notify();
20440    }
20441
20442    fn should_show_indent_guides(&self) -> Option<bool> {
20443        self.show_indent_guides
20444    }
20445
20446    pub fn disable_indent_guides_for_buffer(
20447        &mut self,
20448        buffer_id: BufferId,
20449        cx: &mut Context<Self>,
20450    ) {
20451        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20452        cx.notify();
20453    }
20454
20455    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20456        self.buffers_with_disabled_indent_guides
20457            .contains(&buffer_id)
20458    }
20459
20460    pub fn toggle_line_numbers(
20461        &mut self,
20462        _: &ToggleLineNumbers,
20463        _: &mut Window,
20464        cx: &mut Context<Self>,
20465    ) {
20466        let mut editor_settings = EditorSettings::get_global(cx).clone();
20467        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20468        EditorSettings::override_global(editor_settings, cx);
20469    }
20470
20471    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20472        if let Some(show_line_numbers) = self.show_line_numbers {
20473            return show_line_numbers;
20474        }
20475        EditorSettings::get_global(cx).gutter.line_numbers
20476    }
20477
20478    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
20479        match (
20480            self.use_relative_line_numbers,
20481            EditorSettings::get_global(cx).relative_line_numbers,
20482        ) {
20483            (None, setting) => setting,
20484            (Some(false), _) => RelativeLineNumbers::Disabled,
20485            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20486            (Some(true), _) => RelativeLineNumbers::Enabled,
20487        }
20488    }
20489
20490    pub fn toggle_relative_line_numbers(
20491        &mut self,
20492        _: &ToggleRelativeLineNumbers,
20493        _: &mut Window,
20494        cx: &mut Context<Self>,
20495    ) {
20496        let is_relative = self.relative_line_numbers(cx);
20497        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20498    }
20499
20500    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20501        self.use_relative_line_numbers = is_relative;
20502        cx.notify();
20503    }
20504
20505    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20506        self.show_gutter = show_gutter;
20507        cx.notify();
20508    }
20509
20510    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20511        self.show_scrollbars = ScrollbarAxes {
20512            horizontal: show,
20513            vertical: show,
20514        };
20515        cx.notify();
20516    }
20517
20518    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20519        self.show_scrollbars.vertical = show;
20520        cx.notify();
20521    }
20522
20523    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20524        self.show_scrollbars.horizontal = show;
20525        cx.notify();
20526    }
20527
20528    pub fn set_minimap_visibility(
20529        &mut self,
20530        minimap_visibility: MinimapVisibility,
20531        window: &mut Window,
20532        cx: &mut Context<Self>,
20533    ) {
20534        if self.minimap_visibility != minimap_visibility {
20535            if minimap_visibility.visible() && self.minimap.is_none() {
20536                let minimap_settings = EditorSettings::get_global(cx).minimap;
20537                self.minimap =
20538                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20539            }
20540            self.minimap_visibility = minimap_visibility;
20541            cx.notify();
20542        }
20543    }
20544
20545    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20546        self.set_show_scrollbars(false, cx);
20547        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20548    }
20549
20550    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20551        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20552    }
20553
20554    /// Normally the text in full mode and auto height editors is padded on the
20555    /// left side by roughly half a character width for improved hit testing.
20556    ///
20557    /// Use this method to disable this for cases where this is not wanted (e.g.
20558    /// if you want to align the editor text with some other text above or below)
20559    /// or if you want to add this padding to single-line editors.
20560    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20561        self.offset_content = offset_content;
20562        cx.notify();
20563    }
20564
20565    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20566        self.show_line_numbers = Some(show_line_numbers);
20567        cx.notify();
20568    }
20569
20570    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20571        self.disable_expand_excerpt_buttons = true;
20572        cx.notify();
20573    }
20574
20575    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20576        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20577        cx.notify();
20578    }
20579
20580    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20581        self.show_code_actions = Some(show_code_actions);
20582        cx.notify();
20583    }
20584
20585    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20586        self.show_runnables = Some(show_runnables);
20587        cx.notify();
20588    }
20589
20590    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20591        self.show_breakpoints = Some(show_breakpoints);
20592        cx.notify();
20593    }
20594
20595    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20596        if self.display_map.read(cx).masked != masked {
20597            self.display_map.update(cx, |map, _| map.masked = masked);
20598        }
20599        cx.notify()
20600    }
20601
20602    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20603        self.show_wrap_guides = Some(show_wrap_guides);
20604        cx.notify();
20605    }
20606
20607    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20608        self.show_indent_guides = Some(show_indent_guides);
20609        cx.notify();
20610    }
20611
20612    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20613        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20614            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20615                && let Some(dir) = file.abs_path(cx).parent()
20616            {
20617                return Some(dir.to_owned());
20618            }
20619        }
20620
20621        None
20622    }
20623
20624    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20625        self.active_excerpt(cx)?
20626            .1
20627            .read(cx)
20628            .file()
20629            .and_then(|f| f.as_local())
20630    }
20631
20632    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20633        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20634            let buffer = buffer.read(cx);
20635            if let Some(project_path) = buffer.project_path(cx) {
20636                let project = self.project()?.read(cx);
20637                project.absolute_path(&project_path, cx)
20638            } else {
20639                buffer
20640                    .file()
20641                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20642            }
20643        })
20644    }
20645
20646    pub fn reveal_in_finder(
20647        &mut self,
20648        _: &RevealInFileManager,
20649        _window: &mut Window,
20650        cx: &mut Context<Self>,
20651    ) {
20652        if let Some(target) = self.target_file(cx) {
20653            cx.reveal_path(&target.abs_path(cx));
20654        }
20655    }
20656
20657    pub fn copy_path(
20658        &mut self,
20659        _: &zed_actions::workspace::CopyPath,
20660        _window: &mut Window,
20661        cx: &mut Context<Self>,
20662    ) {
20663        if let Some(path) = self.target_file_abs_path(cx)
20664            && let Some(path) = path.to_str()
20665        {
20666            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20667        } else {
20668            cx.propagate();
20669        }
20670    }
20671
20672    pub fn copy_relative_path(
20673        &mut self,
20674        _: &zed_actions::workspace::CopyRelativePath,
20675        _window: &mut Window,
20676        cx: &mut Context<Self>,
20677    ) {
20678        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20679            let project = self.project()?.read(cx);
20680            let path = buffer.read(cx).file()?.path();
20681            let path = path.display(project.path_style(cx));
20682            Some(path)
20683        }) {
20684            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20685        } else {
20686            cx.propagate();
20687        }
20688    }
20689
20690    /// Returns the project path for the editor's buffer, if any buffer is
20691    /// opened in the editor.
20692    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20693        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20694            buffer.read(cx).project_path(cx)
20695        } else {
20696            None
20697        }
20698    }
20699
20700    // Returns true if the editor handled a go-to-line request
20701    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20702        maybe!({
20703            let breakpoint_store = self.breakpoint_store.as_ref()?;
20704
20705            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20706            else {
20707                self.clear_row_highlights::<ActiveDebugLine>();
20708                return None;
20709            };
20710
20711            let position = active_stack_frame.position;
20712            let buffer_id = position.buffer_id?;
20713            let snapshot = self
20714                .project
20715                .as_ref()?
20716                .read(cx)
20717                .buffer_for_id(buffer_id, cx)?
20718                .read(cx)
20719                .snapshot();
20720
20721            let mut handled = false;
20722            for (id, ExcerptRange { context, .. }) in
20723                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20724            {
20725                if context.start.cmp(&position, &snapshot).is_ge()
20726                    || context.end.cmp(&position, &snapshot).is_lt()
20727                {
20728                    continue;
20729                }
20730                let snapshot = self.buffer.read(cx).snapshot(cx);
20731                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20732
20733                handled = true;
20734                self.clear_row_highlights::<ActiveDebugLine>();
20735
20736                self.go_to_line::<ActiveDebugLine>(
20737                    multibuffer_anchor,
20738                    Some(cx.theme().colors().editor_debugger_active_line_background),
20739                    window,
20740                    cx,
20741                );
20742
20743                cx.notify();
20744            }
20745
20746            handled.then_some(())
20747        })
20748        .is_some()
20749    }
20750
20751    pub fn copy_file_name_without_extension(
20752        &mut self,
20753        _: &CopyFileNameWithoutExtension,
20754        _: &mut Window,
20755        cx: &mut Context<Self>,
20756    ) {
20757        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20758            let file = buffer.read(cx).file()?;
20759            file.path().file_stem()
20760        }) {
20761            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20762        }
20763    }
20764
20765    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20766        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20767            let file = buffer.read(cx).file()?;
20768            Some(file.file_name(cx))
20769        }) {
20770            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20771        }
20772    }
20773
20774    pub fn toggle_git_blame(
20775        &mut self,
20776        _: &::git::Blame,
20777        window: &mut Window,
20778        cx: &mut Context<Self>,
20779    ) {
20780        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20781
20782        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20783            self.start_git_blame(true, window, cx);
20784        }
20785
20786        cx.notify();
20787    }
20788
20789    pub fn toggle_git_blame_inline(
20790        &mut self,
20791        _: &ToggleGitBlameInline,
20792        window: &mut Window,
20793        cx: &mut Context<Self>,
20794    ) {
20795        self.toggle_git_blame_inline_internal(true, window, cx);
20796        cx.notify();
20797    }
20798
20799    pub fn open_git_blame_commit(
20800        &mut self,
20801        _: &OpenGitBlameCommit,
20802        window: &mut Window,
20803        cx: &mut Context<Self>,
20804    ) {
20805        self.open_git_blame_commit_internal(window, cx);
20806    }
20807
20808    fn open_git_blame_commit_internal(
20809        &mut self,
20810        window: &mut Window,
20811        cx: &mut Context<Self>,
20812    ) -> Option<()> {
20813        let blame = self.blame.as_ref()?;
20814        let snapshot = self.snapshot(window, cx);
20815        let cursor = self
20816            .selections
20817            .newest::<Point>(&snapshot.display_snapshot)
20818            .head();
20819        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20820        let (_, blame_entry) = blame
20821            .update(cx, |blame, cx| {
20822                blame
20823                    .blame_for_rows(
20824                        &[RowInfo {
20825                            buffer_id: Some(buffer.remote_id()),
20826                            buffer_row: Some(point.row),
20827                            ..Default::default()
20828                        }],
20829                        cx,
20830                    )
20831                    .next()
20832            })
20833            .flatten()?;
20834        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20835        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20836        let workspace = self.workspace()?.downgrade();
20837        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20838        None
20839    }
20840
20841    pub fn git_blame_inline_enabled(&self) -> bool {
20842        self.git_blame_inline_enabled
20843    }
20844
20845    pub fn toggle_selection_menu(
20846        &mut self,
20847        _: &ToggleSelectionMenu,
20848        _: &mut Window,
20849        cx: &mut Context<Self>,
20850    ) {
20851        self.show_selection_menu = self
20852            .show_selection_menu
20853            .map(|show_selections_menu| !show_selections_menu)
20854            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20855
20856        cx.notify();
20857    }
20858
20859    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20860        self.show_selection_menu
20861            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20862    }
20863
20864    fn start_git_blame(
20865        &mut self,
20866        user_triggered: bool,
20867        window: &mut Window,
20868        cx: &mut Context<Self>,
20869    ) {
20870        if let Some(project) = self.project() {
20871            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20872                && buffer.read(cx).file().is_none()
20873            {
20874                return;
20875            }
20876
20877            let focused = self.focus_handle(cx).contains_focused(window, cx);
20878
20879            let project = project.clone();
20880            let blame = cx
20881                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20882            self.blame_subscription =
20883                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20884            self.blame = Some(blame);
20885        }
20886    }
20887
20888    fn toggle_git_blame_inline_internal(
20889        &mut self,
20890        user_triggered: bool,
20891        window: &mut Window,
20892        cx: &mut Context<Self>,
20893    ) {
20894        if self.git_blame_inline_enabled {
20895            self.git_blame_inline_enabled = false;
20896            self.show_git_blame_inline = false;
20897            self.show_git_blame_inline_delay_task.take();
20898        } else {
20899            self.git_blame_inline_enabled = true;
20900            self.start_git_blame_inline(user_triggered, window, cx);
20901        }
20902
20903        cx.notify();
20904    }
20905
20906    fn start_git_blame_inline(
20907        &mut self,
20908        user_triggered: bool,
20909        window: &mut Window,
20910        cx: &mut Context<Self>,
20911    ) {
20912        self.start_git_blame(user_triggered, window, cx);
20913
20914        if ProjectSettings::get_global(cx)
20915            .git
20916            .inline_blame_delay()
20917            .is_some()
20918        {
20919            self.start_inline_blame_timer(window, cx);
20920        } else {
20921            self.show_git_blame_inline = true
20922        }
20923    }
20924
20925    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20926        self.blame.as_ref()
20927    }
20928
20929    pub fn show_git_blame_gutter(&self) -> bool {
20930        self.show_git_blame_gutter
20931    }
20932
20933    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20934        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20935    }
20936
20937    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20938        self.show_git_blame_inline
20939            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20940            && !self.newest_selection_head_on_empty_line(cx)
20941            && self.has_blame_entries(cx)
20942    }
20943
20944    fn has_blame_entries(&self, cx: &App) -> bool {
20945        self.blame()
20946            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20947    }
20948
20949    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20950        let cursor_anchor = self.selections.newest_anchor().head();
20951
20952        let snapshot = self.buffer.read(cx).snapshot(cx);
20953        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20954
20955        snapshot.line_len(buffer_row) == 0
20956    }
20957
20958    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20959        let buffer_and_selection = maybe!({
20960            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20961            let selection_range = selection.range();
20962
20963            let multi_buffer = self.buffer().read(cx);
20964            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20965            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20966
20967            let (buffer, range, _) = if selection.reversed {
20968                buffer_ranges.first()
20969            } else {
20970                buffer_ranges.last()
20971            }?;
20972
20973            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
20974            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
20975
20976            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
20977                let selection = start_row_in_buffer..end_row_in_buffer;
20978
20979                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
20980            };
20981
20982            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
20983
20984            Some((
20985                multi_buffer.buffer(buffer.remote_id()).unwrap(),
20986                buffer_diff_snapshot.row_to_base_text_row(start_row_in_buffer, buffer)
20987                    ..buffer_diff_snapshot.row_to_base_text_row(end_row_in_buffer, buffer),
20988            ))
20989        });
20990
20991        let Some((buffer, selection)) = buffer_and_selection else {
20992            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20993        };
20994
20995        let Some(project) = self.project() else {
20996            return Task::ready(Err(anyhow!("editor does not have project")));
20997        };
20998
20999        project.update(cx, |project, cx| {
21000            project.get_permalink_to_line(&buffer, selection, cx)
21001        })
21002    }
21003
21004    pub fn copy_permalink_to_line(
21005        &mut self,
21006        _: &CopyPermalinkToLine,
21007        window: &mut Window,
21008        cx: &mut Context<Self>,
21009    ) {
21010        let permalink_task = self.get_permalink_to_line(cx);
21011        let workspace = self.workspace();
21012
21013        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21014            Ok(permalink) => {
21015                cx.update(|_, cx| {
21016                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
21017                })
21018                .ok();
21019            }
21020            Err(err) => {
21021                let message = format!("Failed to copy permalink: {err}");
21022
21023                anyhow::Result::<()>::Err(err).log_err();
21024
21025                if let Some(workspace) = workspace {
21026                    workspace
21027                        .update_in(cx, |workspace, _, cx| {
21028                            struct CopyPermalinkToLine;
21029
21030                            workspace.show_toast(
21031                                Toast::new(
21032                                    NotificationId::unique::<CopyPermalinkToLine>(),
21033                                    message,
21034                                ),
21035                                cx,
21036                            )
21037                        })
21038                        .ok();
21039                }
21040            }
21041        })
21042        .detach();
21043    }
21044
21045    pub fn copy_file_location(
21046        &mut self,
21047        _: &CopyFileLocation,
21048        _: &mut Window,
21049        cx: &mut Context<Self>,
21050    ) {
21051        let selection = self
21052            .selections
21053            .newest::<Point>(&self.display_snapshot(cx))
21054            .start
21055            .row
21056            + 1;
21057        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21058            let project = self.project()?.read(cx);
21059            let file = buffer.read(cx).file()?;
21060            let path = file.path().display(project.path_style(cx));
21061
21062            Some(format!("{path}:{selection}"))
21063        }) {
21064            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
21065        }
21066    }
21067
21068    pub fn open_permalink_to_line(
21069        &mut self,
21070        _: &OpenPermalinkToLine,
21071        window: &mut Window,
21072        cx: &mut Context<Self>,
21073    ) {
21074        let permalink_task = self.get_permalink_to_line(cx);
21075        let workspace = self.workspace();
21076
21077        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21078            Ok(permalink) => {
21079                cx.update(|_, cx| {
21080                    cx.open_url(permalink.as_ref());
21081                })
21082                .ok();
21083            }
21084            Err(err) => {
21085                let message = format!("Failed to open permalink: {err}");
21086
21087                anyhow::Result::<()>::Err(err).log_err();
21088
21089                if let Some(workspace) = workspace {
21090                    workspace
21091                        .update(cx, |workspace, cx| {
21092                            struct OpenPermalinkToLine;
21093
21094                            workspace.show_toast(
21095                                Toast::new(
21096                                    NotificationId::unique::<OpenPermalinkToLine>(),
21097                                    message,
21098                                ),
21099                                cx,
21100                            )
21101                        })
21102                        .ok();
21103                }
21104            }
21105        })
21106        .detach();
21107    }
21108
21109    pub fn insert_uuid_v4(
21110        &mut self,
21111        _: &InsertUuidV4,
21112        window: &mut Window,
21113        cx: &mut Context<Self>,
21114    ) {
21115        self.insert_uuid(UuidVersion::V4, window, cx);
21116    }
21117
21118    pub fn insert_uuid_v7(
21119        &mut self,
21120        _: &InsertUuidV7,
21121        window: &mut Window,
21122        cx: &mut Context<Self>,
21123    ) {
21124        self.insert_uuid(UuidVersion::V7, window, cx);
21125    }
21126
21127    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
21128        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21129        self.transact(window, cx, |this, window, cx| {
21130            let edits = this
21131                .selections
21132                .all::<Point>(&this.display_snapshot(cx))
21133                .into_iter()
21134                .map(|selection| {
21135                    let uuid = match version {
21136                        UuidVersion::V4 => uuid::Uuid::new_v4(),
21137                        UuidVersion::V7 => uuid::Uuid::now_v7(),
21138                    };
21139
21140                    (selection.range(), uuid.to_string())
21141                });
21142            this.edit(edits, cx);
21143            this.refresh_edit_prediction(true, false, window, cx);
21144        });
21145    }
21146
21147    pub fn open_selections_in_multibuffer(
21148        &mut self,
21149        _: &OpenSelectionsInMultibuffer,
21150        window: &mut Window,
21151        cx: &mut Context<Self>,
21152    ) {
21153        let multibuffer = self.buffer.read(cx);
21154
21155        let Some(buffer) = multibuffer.as_singleton() else {
21156            return;
21157        };
21158
21159        let Some(workspace) = self.workspace() else {
21160            return;
21161        };
21162
21163        let title = multibuffer.title(cx).to_string();
21164
21165        let locations = self
21166            .selections
21167            .all_anchors(&self.display_snapshot(cx))
21168            .iter()
21169            .map(|selection| {
21170                (
21171                    buffer.clone(),
21172                    (selection.start.text_anchor..selection.end.text_anchor)
21173                        .to_point(buffer.read(cx)),
21174                )
21175            })
21176            .into_group_map();
21177
21178        cx.spawn_in(window, async move |_, cx| {
21179            workspace.update_in(cx, |workspace, window, cx| {
21180                Self::open_locations_in_multibuffer(
21181                    workspace,
21182                    locations,
21183                    format!("Selections for '{title}'"),
21184                    false,
21185                    false,
21186                    MultibufferSelectionMode::All,
21187                    window,
21188                    cx,
21189                );
21190            })
21191        })
21192        .detach();
21193    }
21194
21195    /// Adds a row highlight for the given range. If a row has multiple highlights, the
21196    /// last highlight added will be used.
21197    ///
21198    /// If the range ends at the beginning of a line, then that line will not be highlighted.
21199    pub fn highlight_rows<T: 'static>(
21200        &mut self,
21201        range: Range<Anchor>,
21202        color: Hsla,
21203        options: RowHighlightOptions,
21204        cx: &mut Context<Self>,
21205    ) {
21206        let snapshot = self.buffer().read(cx).snapshot(cx);
21207        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21208        let ix = row_highlights.binary_search_by(|highlight| {
21209            Ordering::Equal
21210                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
21211                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
21212        });
21213
21214        if let Err(mut ix) = ix {
21215            let index = post_inc(&mut self.highlight_order);
21216
21217            // If this range intersects with the preceding highlight, then merge it with
21218            // the preceding highlight. Otherwise insert a new highlight.
21219            let mut merged = false;
21220            if ix > 0 {
21221                let prev_highlight = &mut row_highlights[ix - 1];
21222                if prev_highlight
21223                    .range
21224                    .end
21225                    .cmp(&range.start, &snapshot)
21226                    .is_ge()
21227                {
21228                    ix -= 1;
21229                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
21230                        prev_highlight.range.end = range.end;
21231                    }
21232                    merged = true;
21233                    prev_highlight.index = index;
21234                    prev_highlight.color = color;
21235                    prev_highlight.options = options;
21236                }
21237            }
21238
21239            if !merged {
21240                row_highlights.insert(
21241                    ix,
21242                    RowHighlight {
21243                        range,
21244                        index,
21245                        color,
21246                        options,
21247                        type_id: TypeId::of::<T>(),
21248                    },
21249                );
21250            }
21251
21252            // If any of the following highlights intersect with this one, merge them.
21253            while let Some(next_highlight) = row_highlights.get(ix + 1) {
21254                let highlight = &row_highlights[ix];
21255                if next_highlight
21256                    .range
21257                    .start
21258                    .cmp(&highlight.range.end, &snapshot)
21259                    .is_le()
21260                {
21261                    if next_highlight
21262                        .range
21263                        .end
21264                        .cmp(&highlight.range.end, &snapshot)
21265                        .is_gt()
21266                    {
21267                        row_highlights[ix].range.end = next_highlight.range.end;
21268                    }
21269                    row_highlights.remove(ix + 1);
21270                } else {
21271                    break;
21272                }
21273            }
21274        }
21275    }
21276
21277    /// Remove any highlighted row ranges of the given type that intersect the
21278    /// given ranges.
21279    pub fn remove_highlighted_rows<T: 'static>(
21280        &mut self,
21281        ranges_to_remove: Vec<Range<Anchor>>,
21282        cx: &mut Context<Self>,
21283    ) {
21284        let snapshot = self.buffer().read(cx).snapshot(cx);
21285        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21286        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21287        row_highlights.retain(|highlight| {
21288            while let Some(range_to_remove) = ranges_to_remove.peek() {
21289                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
21290                    Ordering::Less | Ordering::Equal => {
21291                        ranges_to_remove.next();
21292                    }
21293                    Ordering::Greater => {
21294                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
21295                            Ordering::Less | Ordering::Equal => {
21296                                return false;
21297                            }
21298                            Ordering::Greater => break,
21299                        }
21300                    }
21301                }
21302            }
21303
21304            true
21305        })
21306    }
21307
21308    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
21309    pub fn clear_row_highlights<T: 'static>(&mut self) {
21310        self.highlighted_rows.remove(&TypeId::of::<T>());
21311    }
21312
21313    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
21314    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
21315        self.highlighted_rows
21316            .get(&TypeId::of::<T>())
21317            .map_or(&[] as &[_], |vec| vec.as_slice())
21318            .iter()
21319            .map(|highlight| (highlight.range.clone(), highlight.color))
21320    }
21321
21322    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
21323    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
21324    /// Allows to ignore certain kinds of highlights.
21325    pub fn highlighted_display_rows(
21326        &self,
21327        window: &mut Window,
21328        cx: &mut App,
21329    ) -> BTreeMap<DisplayRow, LineHighlight> {
21330        let snapshot = self.snapshot(window, cx);
21331        let mut used_highlight_orders = HashMap::default();
21332        self.highlighted_rows
21333            .iter()
21334            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
21335            .fold(
21336                BTreeMap::<DisplayRow, LineHighlight>::new(),
21337                |mut unique_rows, highlight| {
21338                    let start = highlight.range.start.to_display_point(&snapshot);
21339                    let end = highlight.range.end.to_display_point(&snapshot);
21340                    let start_row = start.row().0;
21341                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
21342                    {
21343                        end.row().0.saturating_sub(1)
21344                    } else {
21345                        end.row().0
21346                    };
21347                    for row in start_row..=end_row {
21348                        let used_index =
21349                            used_highlight_orders.entry(row).or_insert(highlight.index);
21350                        if highlight.index >= *used_index {
21351                            *used_index = highlight.index;
21352                            unique_rows.insert(
21353                                DisplayRow(row),
21354                                LineHighlight {
21355                                    include_gutter: highlight.options.include_gutter,
21356                                    border: None,
21357                                    background: highlight.color.into(),
21358                                    type_id: Some(highlight.type_id),
21359                                },
21360                            );
21361                        }
21362                    }
21363                    unique_rows
21364                },
21365            )
21366    }
21367
21368    pub fn highlighted_display_row_for_autoscroll(
21369        &self,
21370        snapshot: &DisplaySnapshot,
21371    ) -> Option<DisplayRow> {
21372        self.highlighted_rows
21373            .values()
21374            .flat_map(|highlighted_rows| highlighted_rows.iter())
21375            .filter_map(|highlight| {
21376                if highlight.options.autoscroll {
21377                    Some(highlight.range.start.to_display_point(snapshot).row())
21378                } else {
21379                    None
21380                }
21381            })
21382            .min()
21383    }
21384
21385    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21386        self.highlight_background::<SearchWithinRange>(
21387            ranges,
21388            |_, colors| colors.colors().editor_document_highlight_read_background,
21389            cx,
21390        )
21391    }
21392
21393    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21394        self.breadcrumb_header = Some(new_header);
21395    }
21396
21397    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21398        self.clear_background_highlights::<SearchWithinRange>(cx);
21399    }
21400
21401    pub fn highlight_background<T: 'static>(
21402        &mut self,
21403        ranges: &[Range<Anchor>],
21404        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21405        cx: &mut Context<Self>,
21406    ) {
21407        self.background_highlights.insert(
21408            HighlightKey::Type(TypeId::of::<T>()),
21409            (Arc::new(color_fetcher), Arc::from(ranges)),
21410        );
21411        self.scrollbar_marker_state.dirty = true;
21412        cx.notify();
21413    }
21414
21415    pub fn highlight_background_key<T: 'static>(
21416        &mut self,
21417        key: usize,
21418        ranges: &[Range<Anchor>],
21419        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21420        cx: &mut Context<Self>,
21421    ) {
21422        self.background_highlights.insert(
21423            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21424            (Arc::new(color_fetcher), Arc::from(ranges)),
21425        );
21426        self.scrollbar_marker_state.dirty = true;
21427        cx.notify();
21428    }
21429
21430    pub fn clear_background_highlights<T: 'static>(
21431        &mut self,
21432        cx: &mut Context<Self>,
21433    ) -> Option<BackgroundHighlight> {
21434        let text_highlights = self
21435            .background_highlights
21436            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21437        if !text_highlights.1.is_empty() {
21438            self.scrollbar_marker_state.dirty = true;
21439            cx.notify();
21440        }
21441        Some(text_highlights)
21442    }
21443
21444    pub fn highlight_gutter<T: 'static>(
21445        &mut self,
21446        ranges: impl Into<Vec<Range<Anchor>>>,
21447        color_fetcher: fn(&App) -> Hsla,
21448        cx: &mut Context<Self>,
21449    ) {
21450        self.gutter_highlights
21451            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21452        cx.notify();
21453    }
21454
21455    pub fn clear_gutter_highlights<T: 'static>(
21456        &mut self,
21457        cx: &mut Context<Self>,
21458    ) -> Option<GutterHighlight> {
21459        cx.notify();
21460        self.gutter_highlights.remove(&TypeId::of::<T>())
21461    }
21462
21463    pub fn insert_gutter_highlight<T: 'static>(
21464        &mut self,
21465        range: Range<Anchor>,
21466        color_fetcher: fn(&App) -> Hsla,
21467        cx: &mut Context<Self>,
21468    ) {
21469        let snapshot = self.buffer().read(cx).snapshot(cx);
21470        let mut highlights = self
21471            .gutter_highlights
21472            .remove(&TypeId::of::<T>())
21473            .map(|(_, highlights)| highlights)
21474            .unwrap_or_default();
21475        let ix = highlights.binary_search_by(|highlight| {
21476            Ordering::Equal
21477                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21478                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21479        });
21480        if let Err(ix) = ix {
21481            highlights.insert(ix, range);
21482        }
21483        self.gutter_highlights
21484            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21485    }
21486
21487    pub fn remove_gutter_highlights<T: 'static>(
21488        &mut self,
21489        ranges_to_remove: Vec<Range<Anchor>>,
21490        cx: &mut Context<Self>,
21491    ) {
21492        let snapshot = self.buffer().read(cx).snapshot(cx);
21493        let Some((color_fetcher, mut gutter_highlights)) =
21494            self.gutter_highlights.remove(&TypeId::of::<T>())
21495        else {
21496            return;
21497        };
21498        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21499        gutter_highlights.retain(|highlight| {
21500            while let Some(range_to_remove) = ranges_to_remove.peek() {
21501                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21502                    Ordering::Less | Ordering::Equal => {
21503                        ranges_to_remove.next();
21504                    }
21505                    Ordering::Greater => {
21506                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21507                            Ordering::Less | Ordering::Equal => {
21508                                return false;
21509                            }
21510                            Ordering::Greater => break,
21511                        }
21512                    }
21513                }
21514            }
21515
21516            true
21517        });
21518        self.gutter_highlights
21519            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21520    }
21521
21522    #[cfg(feature = "test-support")]
21523    pub fn all_text_highlights(
21524        &self,
21525        window: &mut Window,
21526        cx: &mut Context<Self>,
21527    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21528        let snapshot = self.snapshot(window, cx);
21529        self.display_map.update(cx, |display_map, _| {
21530            display_map
21531                .all_text_highlights()
21532                .map(|highlight| {
21533                    let (style, ranges) = highlight.as_ref();
21534                    (
21535                        *style,
21536                        ranges
21537                            .iter()
21538                            .map(|range| range.clone().to_display_points(&snapshot))
21539                            .collect(),
21540                    )
21541                })
21542                .collect()
21543        })
21544    }
21545
21546    #[cfg(feature = "test-support")]
21547    pub fn all_text_background_highlights(
21548        &self,
21549        window: &mut Window,
21550        cx: &mut Context<Self>,
21551    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21552        let snapshot = self.snapshot(window, cx);
21553        let buffer = &snapshot.buffer_snapshot();
21554        let start = buffer.anchor_before(MultiBufferOffset(0));
21555        let end = buffer.anchor_after(buffer.len());
21556        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21557    }
21558
21559    #[cfg(any(test, feature = "test-support"))]
21560    pub fn sorted_background_highlights_in_range(
21561        &self,
21562        search_range: Range<Anchor>,
21563        display_snapshot: &DisplaySnapshot,
21564        theme: &Theme,
21565    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21566        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21567        res.sort_by(|a, b| {
21568            a.0.start
21569                .cmp(&b.0.start)
21570                .then_with(|| a.0.end.cmp(&b.0.end))
21571                .then_with(|| a.1.cmp(&b.1))
21572        });
21573        res
21574    }
21575
21576    #[cfg(feature = "test-support")]
21577    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21578        let snapshot = self.buffer().read(cx).snapshot(cx);
21579
21580        let highlights = self
21581            .background_highlights
21582            .get(&HighlightKey::Type(TypeId::of::<
21583                items::BufferSearchHighlights,
21584            >()));
21585
21586        if let Some((_color, ranges)) = highlights {
21587            ranges
21588                .iter()
21589                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21590                .collect_vec()
21591        } else {
21592            vec![]
21593        }
21594    }
21595
21596    fn document_highlights_for_position<'a>(
21597        &'a self,
21598        position: Anchor,
21599        buffer: &'a MultiBufferSnapshot,
21600    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21601        let read_highlights = self
21602            .background_highlights
21603            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21604            .map(|h| &h.1);
21605        let write_highlights = self
21606            .background_highlights
21607            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21608            .map(|h| &h.1);
21609        let left_position = position.bias_left(buffer);
21610        let right_position = position.bias_right(buffer);
21611        read_highlights
21612            .into_iter()
21613            .chain(write_highlights)
21614            .flat_map(move |ranges| {
21615                let start_ix = match ranges.binary_search_by(|probe| {
21616                    let cmp = probe.end.cmp(&left_position, buffer);
21617                    if cmp.is_ge() {
21618                        Ordering::Greater
21619                    } else {
21620                        Ordering::Less
21621                    }
21622                }) {
21623                    Ok(i) | Err(i) => i,
21624                };
21625
21626                ranges[start_ix..]
21627                    .iter()
21628                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21629            })
21630    }
21631
21632    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21633        self.background_highlights
21634            .get(&HighlightKey::Type(TypeId::of::<T>()))
21635            .is_some_and(|(_, highlights)| !highlights.is_empty())
21636    }
21637
21638    /// Returns all background highlights for a given range.
21639    ///
21640    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21641    pub fn background_highlights_in_range(
21642        &self,
21643        search_range: Range<Anchor>,
21644        display_snapshot: &DisplaySnapshot,
21645        theme: &Theme,
21646    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21647        let mut results = Vec::new();
21648        for (color_fetcher, ranges) in self.background_highlights.values() {
21649            let start_ix = match ranges.binary_search_by(|probe| {
21650                let cmp = probe
21651                    .end
21652                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21653                if cmp.is_gt() {
21654                    Ordering::Greater
21655                } else {
21656                    Ordering::Less
21657                }
21658            }) {
21659                Ok(i) | Err(i) => i,
21660            };
21661            for (index, range) in ranges[start_ix..].iter().enumerate() {
21662                if range
21663                    .start
21664                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21665                    .is_ge()
21666                {
21667                    break;
21668                }
21669
21670                let color = color_fetcher(&(start_ix + index), theme);
21671                let start = range.start.to_display_point(display_snapshot);
21672                let end = range.end.to_display_point(display_snapshot);
21673                results.push((start..end, color))
21674            }
21675        }
21676        results
21677    }
21678
21679    pub fn gutter_highlights_in_range(
21680        &self,
21681        search_range: Range<Anchor>,
21682        display_snapshot: &DisplaySnapshot,
21683        cx: &App,
21684    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21685        let mut results = Vec::new();
21686        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21687            let color = color_fetcher(cx);
21688            let start_ix = match ranges.binary_search_by(|probe| {
21689                let cmp = probe
21690                    .end
21691                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21692                if cmp.is_gt() {
21693                    Ordering::Greater
21694                } else {
21695                    Ordering::Less
21696                }
21697            }) {
21698                Ok(i) | Err(i) => i,
21699            };
21700            for range in &ranges[start_ix..] {
21701                if range
21702                    .start
21703                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21704                    .is_ge()
21705                {
21706                    break;
21707                }
21708
21709                let start = range.start.to_display_point(display_snapshot);
21710                let end = range.end.to_display_point(display_snapshot);
21711                results.push((start..end, color))
21712            }
21713        }
21714        results
21715    }
21716
21717    /// Get the text ranges corresponding to the redaction query
21718    pub fn redacted_ranges(
21719        &self,
21720        search_range: Range<Anchor>,
21721        display_snapshot: &DisplaySnapshot,
21722        cx: &App,
21723    ) -> Vec<Range<DisplayPoint>> {
21724        display_snapshot
21725            .buffer_snapshot()
21726            .redacted_ranges(search_range, |file| {
21727                if let Some(file) = file {
21728                    file.is_private()
21729                        && EditorSettings::get(
21730                            Some(SettingsLocation {
21731                                worktree_id: file.worktree_id(cx),
21732                                path: file.path().as_ref(),
21733                            }),
21734                            cx,
21735                        )
21736                        .redact_private_values
21737                } else {
21738                    false
21739                }
21740            })
21741            .map(|range| {
21742                range.start.to_display_point(display_snapshot)
21743                    ..range.end.to_display_point(display_snapshot)
21744            })
21745            .collect()
21746    }
21747
21748    pub fn highlight_text_key<T: 'static>(
21749        &mut self,
21750        key: usize,
21751        ranges: Vec<Range<Anchor>>,
21752        style: HighlightStyle,
21753        merge: bool,
21754        cx: &mut Context<Self>,
21755    ) {
21756        self.display_map.update(cx, |map, cx| {
21757            map.highlight_text(
21758                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21759                ranges,
21760                style,
21761                merge,
21762                cx,
21763            );
21764        });
21765        cx.notify();
21766    }
21767
21768    pub fn highlight_text<T: 'static>(
21769        &mut self,
21770        ranges: Vec<Range<Anchor>>,
21771        style: HighlightStyle,
21772        cx: &mut Context<Self>,
21773    ) {
21774        self.display_map.update(cx, |map, cx| {
21775            map.highlight_text(
21776                HighlightKey::Type(TypeId::of::<T>()),
21777                ranges,
21778                style,
21779                false,
21780                cx,
21781            )
21782        });
21783        cx.notify();
21784    }
21785
21786    pub fn text_highlights<'a, T: 'static>(
21787        &'a self,
21788        cx: &'a App,
21789    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21790        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21791    }
21792
21793    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21794        let cleared = self
21795            .display_map
21796            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21797        if cleared {
21798            cx.notify();
21799        }
21800    }
21801
21802    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21803        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21804            && self.focus_handle.is_focused(window)
21805    }
21806
21807    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21808        self.show_cursor_when_unfocused = is_enabled;
21809        cx.notify();
21810    }
21811
21812    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21813        cx.notify();
21814    }
21815
21816    fn on_debug_session_event(
21817        &mut self,
21818        _session: Entity<Session>,
21819        event: &SessionEvent,
21820        cx: &mut Context<Self>,
21821    ) {
21822        if let SessionEvent::InvalidateInlineValue = event {
21823            self.refresh_inline_values(cx);
21824        }
21825    }
21826
21827    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21828        let Some(project) = self.project.clone() else {
21829            return;
21830        };
21831
21832        if !self.inline_value_cache.enabled {
21833            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21834            self.splice_inlays(&inlays, Vec::new(), cx);
21835            return;
21836        }
21837
21838        let current_execution_position = self
21839            .highlighted_rows
21840            .get(&TypeId::of::<ActiveDebugLine>())
21841            .and_then(|lines| lines.last().map(|line| line.range.end));
21842
21843        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21844            let inline_values = editor
21845                .update(cx, |editor, cx| {
21846                    let Some(current_execution_position) = current_execution_position else {
21847                        return Some(Task::ready(Ok(Vec::new())));
21848                    };
21849
21850                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21851                        let snapshot = buffer.snapshot(cx);
21852
21853                        let excerpt = snapshot.excerpt_containing(
21854                            current_execution_position..current_execution_position,
21855                        )?;
21856
21857                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21858                    })?;
21859
21860                    let range =
21861                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21862
21863                    project.inline_values(buffer, range, cx)
21864                })
21865                .ok()
21866                .flatten()?
21867                .await
21868                .context("refreshing debugger inlays")
21869                .log_err()?;
21870
21871            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21872
21873            for (buffer_id, inline_value) in inline_values
21874                .into_iter()
21875                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21876            {
21877                buffer_inline_values
21878                    .entry(buffer_id)
21879                    .or_default()
21880                    .push(inline_value);
21881            }
21882
21883            editor
21884                .update(cx, |editor, cx| {
21885                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21886                    let mut new_inlays = Vec::default();
21887
21888                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21889                        let buffer_id = buffer_snapshot.remote_id();
21890                        buffer_inline_values
21891                            .get(&buffer_id)
21892                            .into_iter()
21893                            .flatten()
21894                            .for_each(|hint| {
21895                                let inlay = Inlay::debugger(
21896                                    post_inc(&mut editor.next_inlay_id),
21897                                    Anchor::in_buffer(excerpt_id, hint.position),
21898                                    hint.text(),
21899                                );
21900                                if !inlay.text().chars().contains(&'\n') {
21901                                    new_inlays.push(inlay);
21902                                }
21903                            });
21904                    }
21905
21906                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21907                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21908
21909                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21910                })
21911                .ok()?;
21912            Some(())
21913        });
21914    }
21915
21916    fn on_buffer_event(
21917        &mut self,
21918        multibuffer: &Entity<MultiBuffer>,
21919        event: &multi_buffer::Event,
21920        window: &mut Window,
21921        cx: &mut Context<Self>,
21922    ) {
21923        match event {
21924            multi_buffer::Event::Edited { edited_buffer } => {
21925                self.scrollbar_marker_state.dirty = true;
21926                self.active_indent_guides_state.dirty = true;
21927                self.refresh_active_diagnostics(cx);
21928                self.refresh_code_actions(window, cx);
21929                self.refresh_single_line_folds(window, cx);
21930                self.refresh_matching_bracket_highlights(window, cx);
21931                if self.has_active_edit_prediction() {
21932                    self.update_visible_edit_prediction(window, cx);
21933                }
21934
21935                if let Some(buffer) = edited_buffer {
21936                    if buffer.read(cx).file().is_none() {
21937                        cx.emit(EditorEvent::TitleChanged);
21938                    }
21939
21940                    if self.project.is_some() {
21941                        let buffer_id = buffer.read(cx).remote_id();
21942                        self.register_buffer(buffer_id, cx);
21943                        self.update_lsp_data(Some(buffer_id), window, cx);
21944                        self.refresh_inlay_hints(
21945                            InlayHintRefreshReason::BufferEdited(buffer_id),
21946                            cx,
21947                        );
21948                    }
21949                }
21950
21951                cx.emit(EditorEvent::BufferEdited);
21952                cx.emit(SearchEvent::MatchesInvalidated);
21953
21954                let Some(project) = &self.project else { return };
21955                let (telemetry, is_via_ssh) = {
21956                    let project = project.read(cx);
21957                    let telemetry = project.client().telemetry().clone();
21958                    let is_via_ssh = project.is_via_remote_server();
21959                    (telemetry, is_via_ssh)
21960                };
21961                telemetry.log_edit_event("editor", is_via_ssh);
21962            }
21963            multi_buffer::Event::ExcerptsAdded {
21964                buffer,
21965                predecessor,
21966                excerpts,
21967            } => {
21968                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21969                let buffer_id = buffer.read(cx).remote_id();
21970                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21971                    && let Some(project) = &self.project
21972                {
21973                    update_uncommitted_diff_for_buffer(
21974                        cx.entity(),
21975                        project,
21976                        [buffer.clone()],
21977                        self.buffer.clone(),
21978                        cx,
21979                    )
21980                    .detach();
21981                }
21982                self.update_lsp_data(Some(buffer_id), window, cx);
21983                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21984                self.colorize_brackets(false, cx);
21985                cx.emit(EditorEvent::ExcerptsAdded {
21986                    buffer: buffer.clone(),
21987                    predecessor: *predecessor,
21988                    excerpts: excerpts.clone(),
21989                });
21990            }
21991            multi_buffer::Event::ExcerptsRemoved {
21992                ids,
21993                removed_buffer_ids,
21994            } => {
21995                if let Some(inlay_hints) = &mut self.inlay_hints {
21996                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21997                }
21998                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21999                for buffer_id in removed_buffer_ids {
22000                    self.registered_buffers.remove(buffer_id);
22001                }
22002                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22003                cx.emit(EditorEvent::ExcerptsRemoved {
22004                    ids: ids.clone(),
22005                    removed_buffer_ids: removed_buffer_ids.clone(),
22006                });
22007            }
22008            multi_buffer::Event::ExcerptsEdited {
22009                excerpt_ids,
22010                buffer_ids,
22011            } => {
22012                self.display_map.update(cx, |map, cx| {
22013                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
22014                });
22015                cx.emit(EditorEvent::ExcerptsEdited {
22016                    ids: excerpt_ids.clone(),
22017                });
22018            }
22019            multi_buffer::Event::ExcerptsExpanded { ids } => {
22020                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22021                self.refresh_document_highlights(cx);
22022                for id in ids {
22023                    self.fetched_tree_sitter_chunks.remove(id);
22024                }
22025                self.colorize_brackets(false, cx);
22026                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
22027            }
22028            multi_buffer::Event::Reparsed(buffer_id) => {
22029                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22030                self.refresh_selected_text_highlights(true, window, cx);
22031                self.colorize_brackets(true, cx);
22032                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22033
22034                cx.emit(EditorEvent::Reparsed(*buffer_id));
22035            }
22036            multi_buffer::Event::DiffHunksToggled => {
22037                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22038            }
22039            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
22040                if !is_fresh_language {
22041                    self.registered_buffers.remove(&buffer_id);
22042                }
22043                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22044                cx.emit(EditorEvent::Reparsed(*buffer_id));
22045                cx.notify();
22046            }
22047            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
22048            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
22049            multi_buffer::Event::FileHandleChanged
22050            | multi_buffer::Event::Reloaded
22051            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
22052            multi_buffer::Event::DiagnosticsUpdated => {
22053                self.update_diagnostics_state(window, cx);
22054            }
22055            _ => {}
22056        };
22057    }
22058
22059    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
22060        if !self.diagnostics_enabled() {
22061            return;
22062        }
22063        self.refresh_active_diagnostics(cx);
22064        self.refresh_inline_diagnostics(true, window, cx);
22065        self.scrollbar_marker_state.dirty = true;
22066        cx.notify();
22067    }
22068
22069    pub fn start_temporary_diff_override(&mut self) {
22070        self.load_diff_task.take();
22071        self.temporary_diff_override = true;
22072    }
22073
22074    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
22075        self.temporary_diff_override = false;
22076        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
22077        self.buffer.update(cx, |buffer, cx| {
22078            buffer.set_all_diff_hunks_collapsed(cx);
22079        });
22080
22081        if let Some(project) = self.project.clone() {
22082            self.load_diff_task = Some(
22083                update_uncommitted_diff_for_buffer(
22084                    cx.entity(),
22085                    &project,
22086                    self.buffer.read(cx).all_buffers(),
22087                    self.buffer.clone(),
22088                    cx,
22089                )
22090                .shared(),
22091            );
22092        }
22093    }
22094
22095    fn on_display_map_changed(
22096        &mut self,
22097        _: Entity<DisplayMap>,
22098        _: &mut Window,
22099        cx: &mut Context<Self>,
22100    ) {
22101        cx.notify();
22102    }
22103
22104    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
22105        if !self.mode.is_full() {
22106            return None;
22107        }
22108
22109        let theme_settings = theme::ThemeSettings::get_global(cx);
22110        let theme = cx.theme();
22111        let accent_colors = theme.accents().clone();
22112
22113        let accent_overrides = theme_settings
22114            .theme_overrides
22115            .get(theme.name.as_ref())
22116            .map(|theme_style| &theme_style.accents)
22117            .into_iter()
22118            .flatten()
22119            .chain(
22120                theme_settings
22121                    .experimental_theme_overrides
22122                    .as_ref()
22123                    .map(|overrides| &overrides.accents)
22124                    .into_iter()
22125                    .flatten(),
22126            )
22127            .flat_map(|accent| accent.0.clone())
22128            .collect();
22129
22130        Some(AccentData {
22131            colors: accent_colors,
22132            overrides: accent_overrides,
22133        })
22134    }
22135
22136    fn fetch_applicable_language_settings(
22137        &self,
22138        cx: &App,
22139    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
22140        if !self.mode.is_full() {
22141            return HashMap::default();
22142        }
22143
22144        self.buffer().read(cx).all_buffers().into_iter().fold(
22145            HashMap::default(),
22146            |mut acc, buffer| {
22147                let buffer = buffer.read(cx);
22148                let language = buffer.language().map(|language| language.name());
22149                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
22150                    let file = buffer.file();
22151                    v.insert(language_settings(language, file, cx).into_owned());
22152                }
22153                acc
22154            },
22155        )
22156    }
22157
22158    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22159        let new_language_settings = self.fetch_applicable_language_settings(cx);
22160        let language_settings_changed = new_language_settings != self.applicable_language_settings;
22161        self.applicable_language_settings = new_language_settings;
22162
22163        let new_accents = self.fetch_accent_data(cx);
22164        let accents_changed = new_accents != self.accent_data;
22165        self.accent_data = new_accents;
22166
22167        if self.diagnostics_enabled() {
22168            let new_severity = EditorSettings::get_global(cx)
22169                .diagnostics_max_severity
22170                .unwrap_or(DiagnosticSeverity::Hint);
22171            self.set_max_diagnostics_severity(new_severity, cx);
22172        }
22173        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22174        self.update_edit_prediction_settings(cx);
22175        self.refresh_edit_prediction(true, false, window, cx);
22176        self.refresh_inline_values(cx);
22177        self.refresh_inlay_hints(
22178            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
22179                self.selections.newest_anchor().head(),
22180                &self.buffer.read(cx).snapshot(cx),
22181                cx,
22182            )),
22183            cx,
22184        );
22185
22186        let old_cursor_shape = self.cursor_shape;
22187        let old_show_breadcrumbs = self.show_breadcrumbs;
22188
22189        {
22190            let editor_settings = EditorSettings::get_global(cx);
22191            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
22192            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
22193            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
22194            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
22195        }
22196
22197        if old_cursor_shape != self.cursor_shape {
22198            cx.emit(EditorEvent::CursorShapeChanged);
22199        }
22200
22201        if old_show_breadcrumbs != self.show_breadcrumbs {
22202            cx.emit(EditorEvent::BreadcrumbsChanged);
22203        }
22204
22205        let project_settings = ProjectSettings::get_global(cx);
22206        self.buffer_serialization = self
22207            .should_serialize_buffer()
22208            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
22209
22210        if self.mode.is_full() {
22211            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
22212            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
22213            if self.show_inline_diagnostics != show_inline_diagnostics {
22214                self.show_inline_diagnostics = show_inline_diagnostics;
22215                self.refresh_inline_diagnostics(false, window, cx);
22216            }
22217
22218            if self.git_blame_inline_enabled != inline_blame_enabled {
22219                self.toggle_git_blame_inline_internal(false, window, cx);
22220            }
22221
22222            let minimap_settings = EditorSettings::get_global(cx).minimap;
22223            if self.minimap_visibility != MinimapVisibility::Disabled {
22224                if self.minimap_visibility.settings_visibility()
22225                    != minimap_settings.minimap_enabled()
22226                {
22227                    self.set_minimap_visibility(
22228                        MinimapVisibility::for_mode(self.mode(), cx),
22229                        window,
22230                        cx,
22231                    );
22232                } else if let Some(minimap_entity) = self.minimap.as_ref() {
22233                    minimap_entity.update(cx, |minimap_editor, cx| {
22234                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
22235                    })
22236                }
22237            }
22238
22239            if language_settings_changed || accents_changed {
22240                self.colorize_brackets(true, cx);
22241            }
22242
22243            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
22244                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
22245            }) {
22246                if !inlay_splice.is_empty() {
22247                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
22248                }
22249                self.refresh_colors_for_visible_range(None, window, cx);
22250            }
22251        }
22252
22253        cx.notify();
22254    }
22255
22256    pub fn set_searchable(&mut self, searchable: bool) {
22257        self.searchable = searchable;
22258    }
22259
22260    pub fn searchable(&self) -> bool {
22261        self.searchable
22262    }
22263
22264    pub fn open_excerpts_in_split(
22265        &mut self,
22266        _: &OpenExcerptsSplit,
22267        window: &mut Window,
22268        cx: &mut Context<Self>,
22269    ) {
22270        self.open_excerpts_common(None, true, window, cx)
22271    }
22272
22273    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
22274        self.open_excerpts_common(None, false, window, cx)
22275    }
22276
22277    fn open_excerpts_common(
22278        &mut self,
22279        jump_data: Option<JumpData>,
22280        split: bool,
22281        window: &mut Window,
22282        cx: &mut Context<Self>,
22283    ) {
22284        let Some(workspace) = self.workspace() else {
22285            cx.propagate();
22286            return;
22287        };
22288
22289        if self.buffer.read(cx).is_singleton() {
22290            cx.propagate();
22291            return;
22292        }
22293
22294        let mut new_selections_by_buffer = HashMap::default();
22295        match &jump_data {
22296            Some(JumpData::MultiBufferPoint {
22297                excerpt_id,
22298                position,
22299                anchor,
22300                line_offset_from_top,
22301            }) => {
22302                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22303                if let Some(buffer) = multi_buffer_snapshot
22304                    .buffer_id_for_excerpt(*excerpt_id)
22305                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
22306                {
22307                    let buffer_snapshot = buffer.read(cx).snapshot();
22308                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
22309                        language::ToPoint::to_point(anchor, &buffer_snapshot)
22310                    } else {
22311                        buffer_snapshot.clip_point(*position, Bias::Left)
22312                    };
22313                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
22314                    new_selections_by_buffer.insert(
22315                        buffer,
22316                        (
22317                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
22318                            Some(*line_offset_from_top),
22319                        ),
22320                    );
22321                }
22322            }
22323            Some(JumpData::MultiBufferRow {
22324                row,
22325                line_offset_from_top,
22326            }) => {
22327                let point = MultiBufferPoint::new(row.0, 0);
22328                if let Some((buffer, buffer_point, _)) =
22329                    self.buffer.read(cx).point_to_buffer_point(point, cx)
22330                {
22331                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
22332                    new_selections_by_buffer
22333                        .entry(buffer)
22334                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
22335                        .0
22336                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
22337                }
22338            }
22339            None => {
22340                let selections = self
22341                    .selections
22342                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
22343                let multi_buffer = self.buffer.read(cx);
22344                for selection in selections {
22345                    for (snapshot, range, _, anchor) in multi_buffer
22346                        .snapshot(cx)
22347                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
22348                    {
22349                        if let Some(anchor) = anchor {
22350                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
22351                            else {
22352                                continue;
22353                            };
22354                            let offset = text::ToOffset::to_offset(
22355                                &anchor.text_anchor,
22356                                &buffer_handle.read(cx).snapshot(),
22357                            );
22358                            let range = BufferOffset(offset)..BufferOffset(offset);
22359                            new_selections_by_buffer
22360                                .entry(buffer_handle)
22361                                .or_insert((Vec::new(), None))
22362                                .0
22363                                .push(range)
22364                        } else {
22365                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22366                            else {
22367                                continue;
22368                            };
22369                            new_selections_by_buffer
22370                                .entry(buffer_handle)
22371                                .or_insert((Vec::new(), None))
22372                                .0
22373                                .push(range)
22374                        }
22375                    }
22376                }
22377            }
22378        }
22379
22380        new_selections_by_buffer
22381            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
22382
22383        if new_selections_by_buffer.is_empty() {
22384            return;
22385        }
22386
22387        // We defer the pane interaction because we ourselves are a workspace item
22388        // and activating a new item causes the pane to call a method on us reentrantly,
22389        // which panics if we're on the stack.
22390        window.defer(cx, move |window, cx| {
22391            workspace.update(cx, |workspace, cx| {
22392                let pane = if split {
22393                    workspace.adjacent_pane(window, cx)
22394                } else {
22395                    workspace.active_pane().clone()
22396                };
22397
22398                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22399                    let buffer_read = buffer.read(cx);
22400                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22401                        (true, project::File::from_dyn(Some(file)).is_some())
22402                    } else {
22403                        (false, false)
22404                    };
22405
22406                    // If project file is none workspace.open_project_item will fail to open the excerpt
22407                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22408                    // so we check if there's a tab match in that case first
22409                    let editor = (!has_file || !is_project_file)
22410                        .then(|| {
22411                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22412                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22413                            // Instead, we try to activate the existing editor in the pane first.
22414                            let (editor, pane_item_index, pane_item_id) =
22415                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22416                                    let editor = item.downcast::<Editor>()?;
22417                                    let singleton_buffer =
22418                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22419                                    if singleton_buffer == buffer {
22420                                        Some((editor, i, item.item_id()))
22421                                    } else {
22422                                        None
22423                                    }
22424                                })?;
22425                            pane.update(cx, |pane, cx| {
22426                                pane.activate_item(pane_item_index, true, true, window, cx);
22427                                if !PreviewTabsSettings::get_global(cx)
22428                                    .enable_preview_from_multibuffer
22429                                {
22430                                    pane.unpreview_item_if_preview(pane_item_id);
22431                                }
22432                            });
22433                            Some(editor)
22434                        })
22435                        .flatten()
22436                        .unwrap_or_else(|| {
22437                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22438                                .enable_keep_preview_on_code_navigation;
22439                            let allow_new_preview =
22440                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22441                            workspace.open_project_item::<Self>(
22442                                pane.clone(),
22443                                buffer,
22444                                true,
22445                                true,
22446                                keep_old_preview,
22447                                allow_new_preview,
22448                                window,
22449                                cx,
22450                            )
22451                        });
22452
22453                    editor.update(cx, |editor, cx| {
22454                        if has_file && !is_project_file {
22455                            editor.set_read_only(true);
22456                        }
22457                        let autoscroll = match scroll_offset {
22458                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22459                            None => Autoscroll::newest(),
22460                        };
22461                        let nav_history = editor.nav_history.take();
22462                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
22463                        let Some((&excerpt_id, _, buffer_snapshot)) =
22464                            multibuffer_snapshot.as_singleton()
22465                        else {
22466                            return;
22467                        };
22468                        editor.change_selections(
22469                            SelectionEffects::scroll(autoscroll),
22470                            window,
22471                            cx,
22472                            |s| {
22473                                s.select_ranges(ranges.into_iter().map(|range| {
22474                                    let range = buffer_snapshot.anchor_before(range.start)
22475                                        ..buffer_snapshot.anchor_after(range.end);
22476                                    multibuffer_snapshot
22477                                        .anchor_range_in_excerpt(excerpt_id, range)
22478                                        .unwrap()
22479                                }));
22480                            },
22481                        );
22482                        editor.nav_history = nav_history;
22483                    });
22484                }
22485            })
22486        });
22487    }
22488
22489    // Allow opening excerpts for buffers that either belong to the current project
22490    // or represent synthetic/non-local files (e.g., git blobs). File-less buffers
22491    // are also supported so tests and other in-memory views keep working.
22492    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
22493        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some() || !file.is_local())
22494    }
22495
22496    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22497        let snapshot = self.buffer.read(cx).read(cx);
22498        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22499        Some(
22500            ranges
22501                .iter()
22502                .map(move |range| {
22503                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22504                })
22505                .collect(),
22506        )
22507    }
22508
22509    fn selection_replacement_ranges(
22510        &self,
22511        range: Range<MultiBufferOffsetUtf16>,
22512        cx: &mut App,
22513    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22514        let selections = self
22515            .selections
22516            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22517        let newest_selection = selections
22518            .iter()
22519            .max_by_key(|selection| selection.id)
22520            .unwrap();
22521        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22522        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22523        let snapshot = self.buffer.read(cx).read(cx);
22524        selections
22525            .into_iter()
22526            .map(|mut selection| {
22527                selection.start.0.0 =
22528                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22529                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22530                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22531                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22532            })
22533            .collect()
22534    }
22535
22536    fn report_editor_event(
22537        &self,
22538        reported_event: ReportEditorEvent,
22539        file_extension: Option<String>,
22540        cx: &App,
22541    ) {
22542        if cfg!(any(test, feature = "test-support")) {
22543            return;
22544        }
22545
22546        let Some(project) = &self.project else { return };
22547
22548        // If None, we are in a file without an extension
22549        let file = self
22550            .buffer
22551            .read(cx)
22552            .as_singleton()
22553            .and_then(|b| b.read(cx).file());
22554        let file_extension = file_extension.or(file
22555            .as_ref()
22556            .and_then(|file| Path::new(file.file_name(cx)).extension())
22557            .and_then(|e| e.to_str())
22558            .map(|a| a.to_string()));
22559
22560        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22561            .map(|vim_mode| vim_mode.0)
22562            .unwrap_or(false);
22563
22564        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22565        let copilot_enabled = edit_predictions_provider
22566            == language::language_settings::EditPredictionProvider::Copilot;
22567        let copilot_enabled_for_language = self
22568            .buffer
22569            .read(cx)
22570            .language_settings(cx)
22571            .show_edit_predictions;
22572
22573        let project = project.read(cx);
22574        let event_type = reported_event.event_type();
22575
22576        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22577            telemetry::event!(
22578                event_type,
22579                type = if auto_saved {"autosave"} else {"manual"},
22580                file_extension,
22581                vim_mode,
22582                copilot_enabled,
22583                copilot_enabled_for_language,
22584                edit_predictions_provider,
22585                is_via_ssh = project.is_via_remote_server(),
22586            );
22587        } else {
22588            telemetry::event!(
22589                event_type,
22590                file_extension,
22591                vim_mode,
22592                copilot_enabled,
22593                copilot_enabled_for_language,
22594                edit_predictions_provider,
22595                is_via_ssh = project.is_via_remote_server(),
22596            );
22597        };
22598    }
22599
22600    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22601    /// with each line being an array of {text, highlight} objects.
22602    fn copy_highlight_json(
22603        &mut self,
22604        _: &CopyHighlightJson,
22605        window: &mut Window,
22606        cx: &mut Context<Self>,
22607    ) {
22608        #[derive(Serialize)]
22609        struct Chunk<'a> {
22610            text: String,
22611            highlight: Option<&'a str>,
22612        }
22613
22614        let snapshot = self.buffer.read(cx).snapshot(cx);
22615        let range = self
22616            .selected_text_range(false, window, cx)
22617            .and_then(|selection| {
22618                if selection.range.is_empty() {
22619                    None
22620                } else {
22621                    Some(
22622                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22623                            selection.range.start,
22624                        )))
22625                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22626                                selection.range.end,
22627                            ))),
22628                    )
22629                }
22630            })
22631            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22632
22633        let chunks = snapshot.chunks(range, true);
22634        let mut lines = Vec::new();
22635        let mut line: VecDeque<Chunk> = VecDeque::new();
22636
22637        let Some(style) = self.style.as_ref() else {
22638            return;
22639        };
22640
22641        for chunk in chunks {
22642            let highlight = chunk
22643                .syntax_highlight_id
22644                .and_then(|id| id.name(&style.syntax));
22645            let mut chunk_lines = chunk.text.split('\n').peekable();
22646            while let Some(text) = chunk_lines.next() {
22647                let mut merged_with_last_token = false;
22648                if let Some(last_token) = line.back_mut()
22649                    && last_token.highlight == highlight
22650                {
22651                    last_token.text.push_str(text);
22652                    merged_with_last_token = true;
22653                }
22654
22655                if !merged_with_last_token {
22656                    line.push_back(Chunk {
22657                        text: text.into(),
22658                        highlight,
22659                    });
22660                }
22661
22662                if chunk_lines.peek().is_some() {
22663                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22664                        line.pop_front();
22665                    }
22666                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22667                        line.pop_back();
22668                    }
22669
22670                    lines.push(mem::take(&mut line));
22671                }
22672            }
22673        }
22674
22675        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22676            return;
22677        };
22678        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22679    }
22680
22681    pub fn open_context_menu(
22682        &mut self,
22683        _: &OpenContextMenu,
22684        window: &mut Window,
22685        cx: &mut Context<Self>,
22686    ) {
22687        self.request_autoscroll(Autoscroll::newest(), cx);
22688        let position = self
22689            .selections
22690            .newest_display(&self.display_snapshot(cx))
22691            .start;
22692        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22693    }
22694
22695    pub fn replay_insert_event(
22696        &mut self,
22697        text: &str,
22698        relative_utf16_range: Option<Range<isize>>,
22699        window: &mut Window,
22700        cx: &mut Context<Self>,
22701    ) {
22702        if !self.input_enabled {
22703            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22704            return;
22705        }
22706        if let Some(relative_utf16_range) = relative_utf16_range {
22707            let selections = self
22708                .selections
22709                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22710            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22711                let new_ranges = selections.into_iter().map(|range| {
22712                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22713                        range
22714                            .head()
22715                            .0
22716                            .0
22717                            .saturating_add_signed(relative_utf16_range.start),
22718                    ));
22719                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22720                        range
22721                            .head()
22722                            .0
22723                            .0
22724                            .saturating_add_signed(relative_utf16_range.end),
22725                    ));
22726                    start..end
22727                });
22728                s.select_ranges(new_ranges);
22729            });
22730        }
22731
22732        self.handle_input(text, window, cx);
22733    }
22734
22735    pub fn is_focused(&self, window: &Window) -> bool {
22736        self.focus_handle.is_focused(window)
22737    }
22738
22739    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22740        cx.emit(EditorEvent::Focused);
22741
22742        if let Some(descendant) = self
22743            .last_focused_descendant
22744            .take()
22745            .and_then(|descendant| descendant.upgrade())
22746        {
22747            window.focus(&descendant, cx);
22748        } else {
22749            if let Some(blame) = self.blame.as_ref() {
22750                blame.update(cx, GitBlame::focus)
22751            }
22752
22753            self.blink_manager.update(cx, BlinkManager::enable);
22754            self.show_cursor_names(window, cx);
22755            self.buffer.update(cx, |buffer, cx| {
22756                buffer.finalize_last_transaction(cx);
22757                if self.leader_id.is_none() {
22758                    buffer.set_active_selections(
22759                        &self.selections.disjoint_anchors_arc(),
22760                        self.selections.line_mode(),
22761                        self.cursor_shape,
22762                        cx,
22763                    );
22764                }
22765            });
22766
22767            if let Some(position_map) = self.last_position_map.clone() {
22768                EditorElement::mouse_moved(
22769                    self,
22770                    &MouseMoveEvent {
22771                        position: window.mouse_position(),
22772                        pressed_button: None,
22773                        modifiers: window.modifiers(),
22774                    },
22775                    &position_map,
22776                    window,
22777                    cx,
22778                );
22779            }
22780        }
22781    }
22782
22783    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22784        cx.emit(EditorEvent::FocusedIn)
22785    }
22786
22787    fn handle_focus_out(
22788        &mut self,
22789        event: FocusOutEvent,
22790        _window: &mut Window,
22791        cx: &mut Context<Self>,
22792    ) {
22793        if event.blurred != self.focus_handle {
22794            self.last_focused_descendant = Some(event.blurred);
22795        }
22796        self.selection_drag_state = SelectionDragState::None;
22797        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22798    }
22799
22800    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22801        self.blink_manager.update(cx, BlinkManager::disable);
22802        self.buffer
22803            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22804
22805        if let Some(blame) = self.blame.as_ref() {
22806            blame.update(cx, GitBlame::blur)
22807        }
22808        if !self.hover_state.focused(window, cx) {
22809            hide_hover(self, cx);
22810        }
22811        if !self
22812            .context_menu
22813            .borrow()
22814            .as_ref()
22815            .is_some_and(|context_menu| context_menu.focused(window, cx))
22816        {
22817            self.hide_context_menu(window, cx);
22818        }
22819        self.take_active_edit_prediction(cx);
22820        cx.emit(EditorEvent::Blurred);
22821        cx.notify();
22822    }
22823
22824    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22825        let mut pending: String = window
22826            .pending_input_keystrokes()
22827            .into_iter()
22828            .flatten()
22829            .filter_map(|keystroke| keystroke.key_char.clone())
22830            .collect();
22831
22832        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22833            pending = "".to_string();
22834        }
22835
22836        let existing_pending = self
22837            .text_highlights::<PendingInput>(cx)
22838            .map(|(_, ranges)| ranges.to_vec());
22839        if existing_pending.is_none() && pending.is_empty() {
22840            return;
22841        }
22842        let transaction =
22843            self.transact(window, cx, |this, window, cx| {
22844                let selections = this
22845                    .selections
22846                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22847                let edits = selections
22848                    .iter()
22849                    .map(|selection| (selection.end..selection.end, pending.clone()));
22850                this.edit(edits, cx);
22851                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22852                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22853                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22854                    }));
22855                });
22856                if let Some(existing_ranges) = existing_pending {
22857                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22858                    this.edit(edits, cx);
22859                }
22860            });
22861
22862        let snapshot = self.snapshot(window, cx);
22863        let ranges = self
22864            .selections
22865            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22866            .into_iter()
22867            .map(|selection| {
22868                snapshot.buffer_snapshot().anchor_after(selection.end)
22869                    ..snapshot
22870                        .buffer_snapshot()
22871                        .anchor_before(selection.end + pending.len())
22872            })
22873            .collect();
22874
22875        if pending.is_empty() {
22876            self.clear_highlights::<PendingInput>(cx);
22877        } else {
22878            self.highlight_text::<PendingInput>(
22879                ranges,
22880                HighlightStyle {
22881                    underline: Some(UnderlineStyle {
22882                        thickness: px(1.),
22883                        color: None,
22884                        wavy: false,
22885                    }),
22886                    ..Default::default()
22887                },
22888                cx,
22889            );
22890        }
22891
22892        self.ime_transaction = self.ime_transaction.or(transaction);
22893        if let Some(transaction) = self.ime_transaction {
22894            self.buffer.update(cx, |buffer, cx| {
22895                buffer.group_until_transaction(transaction, cx);
22896            });
22897        }
22898
22899        if self.text_highlights::<PendingInput>(cx).is_none() {
22900            self.ime_transaction.take();
22901        }
22902    }
22903
22904    pub fn register_action_renderer(
22905        &mut self,
22906        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22907    ) -> Subscription {
22908        let id = self.next_editor_action_id.post_inc();
22909        self.editor_actions
22910            .borrow_mut()
22911            .insert(id, Box::new(listener));
22912
22913        let editor_actions = self.editor_actions.clone();
22914        Subscription::new(move || {
22915            editor_actions.borrow_mut().remove(&id);
22916        })
22917    }
22918
22919    pub fn register_action<A: Action>(
22920        &mut self,
22921        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22922    ) -> Subscription {
22923        let id = self.next_editor_action_id.post_inc();
22924        let listener = Arc::new(listener);
22925        self.editor_actions.borrow_mut().insert(
22926            id,
22927            Box::new(move |_, window, _| {
22928                let listener = listener.clone();
22929                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22930                    let action = action.downcast_ref().unwrap();
22931                    if phase == DispatchPhase::Bubble {
22932                        listener(action, window, cx)
22933                    }
22934                })
22935            }),
22936        );
22937
22938        let editor_actions = self.editor_actions.clone();
22939        Subscription::new(move || {
22940            editor_actions.borrow_mut().remove(&id);
22941        })
22942    }
22943
22944    pub fn file_header_size(&self) -> u32 {
22945        FILE_HEADER_HEIGHT
22946    }
22947
22948    pub fn restore(
22949        &mut self,
22950        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22951        window: &mut Window,
22952        cx: &mut Context<Self>,
22953    ) {
22954        self.buffer().update(cx, |multi_buffer, cx| {
22955            for (buffer_id, changes) in revert_changes {
22956                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22957                    buffer.update(cx, |buffer, cx| {
22958                        buffer.edit(
22959                            changes
22960                                .into_iter()
22961                                .map(|(range, text)| (range, text.to_string())),
22962                            None,
22963                            cx,
22964                        );
22965                    });
22966                }
22967            }
22968        });
22969        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22970            selections.refresh()
22971        });
22972    }
22973
22974    pub fn to_pixel_point(
22975        &mut self,
22976        source: multi_buffer::Anchor,
22977        editor_snapshot: &EditorSnapshot,
22978        window: &mut Window,
22979        cx: &App,
22980    ) -> Option<gpui::Point<Pixels>> {
22981        let source_point = source.to_display_point(editor_snapshot);
22982        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
22983    }
22984
22985    pub fn display_to_pixel_point(
22986        &mut self,
22987        source: DisplayPoint,
22988        editor_snapshot: &EditorSnapshot,
22989        window: &mut Window,
22990        cx: &App,
22991    ) -> Option<gpui::Point<Pixels>> {
22992        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
22993        let text_layout_details = self.text_layout_details(window);
22994        let scroll_top = text_layout_details
22995            .scroll_anchor
22996            .scroll_position(editor_snapshot)
22997            .y;
22998
22999        if source.row().as_f64() < scroll_top.floor() {
23000            return None;
23001        }
23002        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
23003        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
23004        Some(gpui::Point::new(source_x, source_y))
23005    }
23006
23007    pub fn has_visible_completions_menu(&self) -> bool {
23008        !self.edit_prediction_preview_is_active()
23009            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
23010                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
23011            })
23012    }
23013
23014    pub fn register_addon<T: Addon>(&mut self, instance: T) {
23015        if self.mode.is_minimap() {
23016            return;
23017        }
23018        self.addons
23019            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
23020    }
23021
23022    pub fn unregister_addon<T: Addon>(&mut self) {
23023        self.addons.remove(&std::any::TypeId::of::<T>());
23024    }
23025
23026    pub fn addon<T: Addon>(&self) -> Option<&T> {
23027        let type_id = std::any::TypeId::of::<T>();
23028        self.addons
23029            .get(&type_id)
23030            .and_then(|item| item.to_any().downcast_ref::<T>())
23031    }
23032
23033    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
23034        let type_id = std::any::TypeId::of::<T>();
23035        self.addons
23036            .get_mut(&type_id)
23037            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
23038    }
23039
23040    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
23041        let text_layout_details = self.text_layout_details(window);
23042        let style = &text_layout_details.editor_style;
23043        let font_id = window.text_system().resolve_font(&style.text.font());
23044        let font_size = style.text.font_size.to_pixels(window.rem_size());
23045        let line_height = style.text.line_height_in_pixels(window.rem_size());
23046        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
23047        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
23048
23049        CharacterDimensions {
23050            em_width,
23051            em_advance,
23052            line_height,
23053        }
23054    }
23055
23056    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
23057        self.load_diff_task.clone()
23058    }
23059
23060    fn read_metadata_from_db(
23061        &mut self,
23062        item_id: u64,
23063        workspace_id: WorkspaceId,
23064        window: &mut Window,
23065        cx: &mut Context<Editor>,
23066    ) {
23067        if self.buffer_kind(cx) == ItemBufferKind::Singleton
23068            && !self.mode.is_minimap()
23069            && WorkspaceSettings::get(None, cx).restore_on_startup
23070                != RestoreOnStartupBehavior::EmptyTab
23071        {
23072            let buffer_snapshot = OnceCell::new();
23073
23074            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
23075                && !folds.is_empty()
23076            {
23077                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23078                self.fold_ranges(
23079                    folds
23080                        .into_iter()
23081                        .map(|(start, end)| {
23082                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23083                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23084                        })
23085                        .collect(),
23086                    false,
23087                    window,
23088                    cx,
23089                );
23090            }
23091
23092            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
23093                && !selections.is_empty()
23094            {
23095                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23096                // skip adding the initial selection to selection history
23097                self.selection_history.mode = SelectionHistoryMode::Skipping;
23098                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23099                    s.select_ranges(selections.into_iter().map(|(start, end)| {
23100                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23101                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23102                    }));
23103                });
23104                self.selection_history.mode = SelectionHistoryMode::Normal;
23105            };
23106        }
23107
23108        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
23109    }
23110
23111    fn update_lsp_data(
23112        &mut self,
23113        for_buffer: Option<BufferId>,
23114        window: &mut Window,
23115        cx: &mut Context<'_, Self>,
23116    ) {
23117        self.pull_diagnostics(for_buffer, window, cx);
23118        self.refresh_colors_for_visible_range(for_buffer, window, cx);
23119    }
23120
23121    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
23122        if self.ignore_lsp_data() {
23123            return;
23124        }
23125        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
23126            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
23127        }
23128    }
23129
23130    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
23131        if self.ignore_lsp_data() {
23132            return;
23133        }
23134
23135        if !self.registered_buffers.contains_key(&buffer_id)
23136            && let Some(project) = self.project.as_ref()
23137        {
23138            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
23139                project.update(cx, |project, cx| {
23140                    self.registered_buffers.insert(
23141                        buffer_id,
23142                        project.register_buffer_with_language_servers(&buffer, cx),
23143                    );
23144                });
23145            } else {
23146                self.registered_buffers.remove(&buffer_id);
23147            }
23148        }
23149    }
23150
23151    fn ignore_lsp_data(&self) -> bool {
23152        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
23153        // skip any LSP updates for it.
23154        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
23155    }
23156
23157    fn create_style(&self, cx: &App) -> EditorStyle {
23158        let settings = ThemeSettings::get_global(cx);
23159
23160        let mut text_style = match self.mode {
23161            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23162                color: cx.theme().colors().editor_foreground,
23163                font_family: settings.ui_font.family.clone(),
23164                font_features: settings.ui_font.features.clone(),
23165                font_fallbacks: settings.ui_font.fallbacks.clone(),
23166                font_size: rems(0.875).into(),
23167                font_weight: settings.ui_font.weight,
23168                line_height: relative(settings.buffer_line_height.value()),
23169                ..Default::default()
23170            },
23171            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23172                color: cx.theme().colors().editor_foreground,
23173                font_family: settings.buffer_font.family.clone(),
23174                font_features: settings.buffer_font.features.clone(),
23175                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23176                font_size: settings.buffer_font_size(cx).into(),
23177                font_weight: settings.buffer_font.weight,
23178                line_height: relative(settings.buffer_line_height.value()),
23179                ..Default::default()
23180            },
23181        };
23182        if let Some(text_style_refinement) = &self.text_style_refinement {
23183            text_style.refine(text_style_refinement)
23184        }
23185
23186        let background = match self.mode {
23187            EditorMode::SingleLine => cx.theme().system().transparent,
23188            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23189            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23190            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23191        };
23192
23193        EditorStyle {
23194            background,
23195            border: cx.theme().colors().border,
23196            local_player: cx.theme().players().local(),
23197            text: text_style,
23198            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23199            syntax: cx.theme().syntax().clone(),
23200            status: cx.theme().status().clone(),
23201            inlay_hints_style: make_inlay_hints_style(cx),
23202            edit_prediction_styles: make_suggestion_styles(cx),
23203            unnecessary_code_fade: settings.unnecessary_code_fade,
23204            show_underlines: self.diagnostics_enabled(),
23205        }
23206    }
23207}
23208
23209fn edit_for_markdown_paste<'a>(
23210    buffer: &MultiBufferSnapshot,
23211    range: Range<MultiBufferOffset>,
23212    to_insert: &'a str,
23213    url: Option<url::Url>,
23214) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
23215    if url.is_none() {
23216        return (range, Cow::Borrowed(to_insert));
23217    };
23218
23219    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
23220
23221    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
23222        Cow::Borrowed(to_insert)
23223    } else {
23224        Cow::Owned(format!("[{old_text}]({to_insert})"))
23225    };
23226    (range, new_text)
23227}
23228
23229fn process_completion_for_edit(
23230    completion: &Completion,
23231    intent: CompletionIntent,
23232    buffer: &Entity<Buffer>,
23233    cursor_position: &text::Anchor,
23234    cx: &mut Context<Editor>,
23235) -> CompletionEdit {
23236    let buffer = buffer.read(cx);
23237    let buffer_snapshot = buffer.snapshot();
23238    let (snippet, new_text) = if completion.is_snippet() {
23239        let mut snippet_source = completion.new_text.clone();
23240        // Workaround for typescript language server issues so that methods don't expand within
23241        // strings and functions with type expressions. The previous point is used because the query
23242        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
23243        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
23244        let previous_point = if previous_point.column > 0 {
23245            cursor_position.to_previous_offset(&buffer_snapshot)
23246        } else {
23247            cursor_position.to_offset(&buffer_snapshot)
23248        };
23249        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
23250            && scope.prefers_label_for_snippet_in_completion()
23251            && let Some(label) = completion.label()
23252            && matches!(
23253                completion.kind(),
23254                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
23255            )
23256        {
23257            snippet_source = label;
23258        }
23259        match Snippet::parse(&snippet_source).log_err() {
23260            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
23261            None => (None, completion.new_text.clone()),
23262        }
23263    } else {
23264        (None, completion.new_text.clone())
23265    };
23266
23267    let mut range_to_replace = {
23268        let replace_range = &completion.replace_range;
23269        if let CompletionSource::Lsp {
23270            insert_range: Some(insert_range),
23271            ..
23272        } = &completion.source
23273        {
23274            debug_assert_eq!(
23275                insert_range.start, replace_range.start,
23276                "insert_range and replace_range should start at the same position"
23277            );
23278            debug_assert!(
23279                insert_range
23280                    .start
23281                    .cmp(cursor_position, &buffer_snapshot)
23282                    .is_le(),
23283                "insert_range should start before or at cursor position"
23284            );
23285            debug_assert!(
23286                replace_range
23287                    .start
23288                    .cmp(cursor_position, &buffer_snapshot)
23289                    .is_le(),
23290                "replace_range should start before or at cursor position"
23291            );
23292
23293            let should_replace = match intent {
23294                CompletionIntent::CompleteWithInsert => false,
23295                CompletionIntent::CompleteWithReplace => true,
23296                CompletionIntent::Complete | CompletionIntent::Compose => {
23297                    let insert_mode =
23298                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
23299                            .completions
23300                            .lsp_insert_mode;
23301                    match insert_mode {
23302                        LspInsertMode::Insert => false,
23303                        LspInsertMode::Replace => true,
23304                        LspInsertMode::ReplaceSubsequence => {
23305                            let mut text_to_replace = buffer.chars_for_range(
23306                                buffer.anchor_before(replace_range.start)
23307                                    ..buffer.anchor_after(replace_range.end),
23308                            );
23309                            let mut current_needle = text_to_replace.next();
23310                            for haystack_ch in completion.label.text.chars() {
23311                                if let Some(needle_ch) = current_needle
23312                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
23313                                {
23314                                    current_needle = text_to_replace.next();
23315                                }
23316                            }
23317                            current_needle.is_none()
23318                        }
23319                        LspInsertMode::ReplaceSuffix => {
23320                            if replace_range
23321                                .end
23322                                .cmp(cursor_position, &buffer_snapshot)
23323                                .is_gt()
23324                            {
23325                                let range_after_cursor = *cursor_position..replace_range.end;
23326                                let text_after_cursor = buffer
23327                                    .text_for_range(
23328                                        buffer.anchor_before(range_after_cursor.start)
23329                                            ..buffer.anchor_after(range_after_cursor.end),
23330                                    )
23331                                    .collect::<String>()
23332                                    .to_ascii_lowercase();
23333                                completion
23334                                    .label
23335                                    .text
23336                                    .to_ascii_lowercase()
23337                                    .ends_with(&text_after_cursor)
23338                            } else {
23339                                true
23340                            }
23341                        }
23342                    }
23343                }
23344            };
23345
23346            if should_replace {
23347                replace_range.clone()
23348            } else {
23349                insert_range.clone()
23350            }
23351        } else {
23352            replace_range.clone()
23353        }
23354    };
23355
23356    if range_to_replace
23357        .end
23358        .cmp(cursor_position, &buffer_snapshot)
23359        .is_lt()
23360    {
23361        range_to_replace.end = *cursor_position;
23362    }
23363
23364    let replace_range = range_to_replace.to_offset(buffer);
23365    CompletionEdit {
23366        new_text,
23367        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
23368        snippet,
23369    }
23370}
23371
23372struct CompletionEdit {
23373    new_text: String,
23374    replace_range: Range<BufferOffset>,
23375    snippet: Option<Snippet>,
23376}
23377
23378fn comment_delimiter_for_newline(
23379    start_point: &Point,
23380    buffer: &MultiBufferSnapshot,
23381    language: &LanguageScope,
23382) -> Option<Arc<str>> {
23383    let delimiters = language.line_comment_prefixes();
23384    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
23385    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23386
23387    let num_of_whitespaces = snapshot
23388        .chars_for_range(range.clone())
23389        .take_while(|c| c.is_whitespace())
23390        .count();
23391    let comment_candidate = snapshot
23392        .chars_for_range(range.clone())
23393        .skip(num_of_whitespaces)
23394        .take(max_len_of_delimiter)
23395        .collect::<String>();
23396    let (delimiter, trimmed_len) = delimiters
23397        .iter()
23398        .filter_map(|delimiter| {
23399            let prefix = delimiter.trim_end();
23400            if comment_candidate.starts_with(prefix) {
23401                Some((delimiter, prefix.len()))
23402            } else {
23403                None
23404            }
23405        })
23406        .max_by_key(|(_, len)| *len)?;
23407
23408    if let Some(BlockCommentConfig {
23409        start: block_start, ..
23410    }) = language.block_comment()
23411    {
23412        let block_start_trimmed = block_start.trim_end();
23413        if block_start_trimmed.starts_with(delimiter.trim_end()) {
23414            let line_content = snapshot
23415                .chars_for_range(range)
23416                .skip(num_of_whitespaces)
23417                .take(block_start_trimmed.len())
23418                .collect::<String>();
23419
23420            if line_content.starts_with(block_start_trimmed) {
23421                return None;
23422            }
23423        }
23424    }
23425
23426    let cursor_is_placed_after_comment_marker =
23427        num_of_whitespaces + trimmed_len <= start_point.column as usize;
23428    if cursor_is_placed_after_comment_marker {
23429        Some(delimiter.clone())
23430    } else {
23431        None
23432    }
23433}
23434
23435fn documentation_delimiter_for_newline(
23436    start_point: &Point,
23437    buffer: &MultiBufferSnapshot,
23438    language: &LanguageScope,
23439    newline_config: &mut NewlineConfig,
23440) -> Option<Arc<str>> {
23441    let BlockCommentConfig {
23442        start: start_tag,
23443        end: end_tag,
23444        prefix: delimiter,
23445        tab_size: len,
23446    } = language.documentation_comment()?;
23447    let is_within_block_comment = buffer
23448        .language_scope_at(*start_point)
23449        .is_some_and(|scope| scope.override_name() == Some("comment"));
23450    if !is_within_block_comment {
23451        return None;
23452    }
23453
23454    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23455
23456    let num_of_whitespaces = snapshot
23457        .chars_for_range(range.clone())
23458        .take_while(|c| c.is_whitespace())
23459        .count();
23460
23461    // 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.
23462    let column = start_point.column;
23463    let cursor_is_after_start_tag = {
23464        let start_tag_len = start_tag.len();
23465        let start_tag_line = snapshot
23466            .chars_for_range(range.clone())
23467            .skip(num_of_whitespaces)
23468            .take(start_tag_len)
23469            .collect::<String>();
23470        if start_tag_line.starts_with(start_tag.as_ref()) {
23471            num_of_whitespaces + start_tag_len <= column as usize
23472        } else {
23473            false
23474        }
23475    };
23476
23477    let cursor_is_after_delimiter = {
23478        let delimiter_trim = delimiter.trim_end();
23479        let delimiter_line = snapshot
23480            .chars_for_range(range.clone())
23481            .skip(num_of_whitespaces)
23482            .take(delimiter_trim.len())
23483            .collect::<String>();
23484        if delimiter_line.starts_with(delimiter_trim) {
23485            num_of_whitespaces + delimiter_trim.len() <= column as usize
23486        } else {
23487            false
23488        }
23489    };
23490
23491    let mut needs_extra_line = false;
23492    let mut extra_line_additional_indent = IndentSize::spaces(0);
23493
23494    let cursor_is_before_end_tag_if_exists = {
23495        let mut char_position = 0u32;
23496        let mut end_tag_offset = None;
23497
23498        'outer: for chunk in snapshot.text_for_range(range) {
23499            if let Some(byte_pos) = chunk.find(&**end_tag) {
23500                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
23501                end_tag_offset = Some(char_position + chars_before_match);
23502                break 'outer;
23503            }
23504            char_position += chunk.chars().count() as u32;
23505        }
23506
23507        if let Some(end_tag_offset) = end_tag_offset {
23508            let cursor_is_before_end_tag = column <= end_tag_offset;
23509            if cursor_is_after_start_tag {
23510                if cursor_is_before_end_tag {
23511                    needs_extra_line = true;
23512                }
23513                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
23514                if cursor_is_at_start_of_end_tag {
23515                    extra_line_additional_indent.len = *len;
23516                }
23517            }
23518            cursor_is_before_end_tag
23519        } else {
23520            true
23521        }
23522    };
23523
23524    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
23525        && cursor_is_before_end_tag_if_exists
23526    {
23527        let additional_indent = if cursor_is_after_start_tag {
23528            IndentSize::spaces(*len)
23529        } else {
23530            IndentSize::spaces(0)
23531        };
23532
23533        *newline_config = NewlineConfig::Newline {
23534            additional_indent,
23535            extra_line_additional_indent: if needs_extra_line {
23536                Some(extra_line_additional_indent)
23537            } else {
23538                None
23539            },
23540            prevent_auto_indent: true,
23541        };
23542        Some(delimiter.clone())
23543    } else {
23544        None
23545    }
23546}
23547
23548const ORDERED_LIST_MAX_MARKER_LEN: usize = 16;
23549
23550fn list_delimiter_for_newline(
23551    start_point: &Point,
23552    buffer: &MultiBufferSnapshot,
23553    language: &LanguageScope,
23554    newline_config: &mut NewlineConfig,
23555) -> Option<Arc<str>> {
23556    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23557
23558    let num_of_whitespaces = snapshot
23559        .chars_for_range(range.clone())
23560        .take_while(|c| c.is_whitespace())
23561        .count();
23562
23563    let task_list_entries: Vec<_> = language
23564        .task_list()
23565        .into_iter()
23566        .flat_map(|config| {
23567            config
23568                .prefixes
23569                .iter()
23570                .map(|prefix| (prefix.as_ref(), config.continuation.as_ref()))
23571        })
23572        .collect();
23573    let unordered_list_entries: Vec<_> = language
23574        .unordered_list()
23575        .iter()
23576        .map(|marker| (marker.as_ref(), marker.as_ref()))
23577        .collect();
23578
23579    let all_entries: Vec<_> = task_list_entries
23580        .into_iter()
23581        .chain(unordered_list_entries)
23582        .collect();
23583
23584    if let Some(max_prefix_len) = all_entries.iter().map(|(p, _)| p.len()).max() {
23585        let candidate: String = snapshot
23586            .chars_for_range(range.clone())
23587            .skip(num_of_whitespaces)
23588            .take(max_prefix_len)
23589            .collect();
23590
23591        if let Some((prefix, continuation)) = all_entries
23592            .iter()
23593            .filter(|(prefix, _)| candidate.starts_with(*prefix))
23594            .max_by_key(|(prefix, _)| prefix.len())
23595        {
23596            let end_of_prefix = num_of_whitespaces + prefix.len();
23597            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
23598            let has_content_after_marker = snapshot
23599                .chars_for_range(range)
23600                .skip(end_of_prefix)
23601                .any(|c| !c.is_whitespace());
23602
23603            if has_content_after_marker && cursor_is_after_prefix {
23604                return Some((*continuation).into());
23605            }
23606
23607            if start_point.column as usize == end_of_prefix {
23608                if num_of_whitespaces == 0 {
23609                    *newline_config = NewlineConfig::ClearCurrentLine;
23610                } else {
23611                    *newline_config = NewlineConfig::UnindentCurrentLine {
23612                        continuation: (*continuation).into(),
23613                    };
23614                }
23615            }
23616
23617            return None;
23618        }
23619    }
23620
23621    let candidate: String = snapshot
23622        .chars_for_range(range.clone())
23623        .skip(num_of_whitespaces)
23624        .take(ORDERED_LIST_MAX_MARKER_LEN)
23625        .collect();
23626
23627    for ordered_config in language.ordered_list() {
23628        let regex = match Regex::new(&ordered_config.pattern) {
23629            Ok(r) => r,
23630            Err(_) => continue,
23631        };
23632
23633        if let Some(captures) = regex.captures(&candidate) {
23634            let full_match = captures.get(0)?;
23635            let marker_len = full_match.len();
23636            let end_of_prefix = num_of_whitespaces + marker_len;
23637            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
23638
23639            let has_content_after_marker = snapshot
23640                .chars_for_range(range)
23641                .skip(end_of_prefix)
23642                .any(|c| !c.is_whitespace());
23643
23644            if has_content_after_marker && cursor_is_after_prefix {
23645                let number: u32 = captures.get(1)?.as_str().parse().ok()?;
23646                let continuation = ordered_config
23647                    .format
23648                    .replace("{1}", &(number + 1).to_string());
23649                return Some(continuation.into());
23650            }
23651
23652            if start_point.column as usize == end_of_prefix {
23653                let continuation = ordered_config.format.replace("{1}", "1");
23654                if num_of_whitespaces == 0 {
23655                    *newline_config = NewlineConfig::ClearCurrentLine;
23656                } else {
23657                    *newline_config = NewlineConfig::UnindentCurrentLine {
23658                        continuation: continuation.into(),
23659                    };
23660                }
23661            }
23662
23663            return None;
23664        }
23665    }
23666
23667    None
23668}
23669
23670fn is_list_prefix_row(
23671    row: MultiBufferRow,
23672    buffer: &MultiBufferSnapshot,
23673    language: &LanguageScope,
23674) -> bool {
23675    let Some((snapshot, range)) = buffer.buffer_line_for_row(row) else {
23676        return false;
23677    };
23678
23679    let num_of_whitespaces = snapshot
23680        .chars_for_range(range.clone())
23681        .take_while(|c| c.is_whitespace())
23682        .count();
23683
23684    let task_list_prefixes: Vec<_> = language
23685        .task_list()
23686        .into_iter()
23687        .flat_map(|config| {
23688            config
23689                .prefixes
23690                .iter()
23691                .map(|p| p.as_ref())
23692                .collect::<Vec<_>>()
23693        })
23694        .collect();
23695    let unordered_list_markers: Vec<_> = language
23696        .unordered_list()
23697        .iter()
23698        .map(|marker| marker.as_ref())
23699        .collect();
23700    let all_prefixes: Vec<_> = task_list_prefixes
23701        .into_iter()
23702        .chain(unordered_list_markers)
23703        .collect();
23704    if let Some(max_prefix_len) = all_prefixes.iter().map(|p| p.len()).max() {
23705        let candidate: String = snapshot
23706            .chars_for_range(range.clone())
23707            .skip(num_of_whitespaces)
23708            .take(max_prefix_len)
23709            .collect();
23710        if all_prefixes
23711            .iter()
23712            .any(|prefix| candidate.starts_with(*prefix))
23713        {
23714            return true;
23715        }
23716    }
23717
23718    let ordered_list_candidate: String = snapshot
23719        .chars_for_range(range)
23720        .skip(num_of_whitespaces)
23721        .take(ORDERED_LIST_MAX_MARKER_LEN)
23722        .collect();
23723    for ordered_config in language.ordered_list() {
23724        let regex = match Regex::new(&ordered_config.pattern) {
23725            Ok(r) => r,
23726            Err(_) => continue,
23727        };
23728        if let Some(captures) = regex.captures(&ordered_list_candidate) {
23729            return captures.get(0).is_some();
23730        }
23731    }
23732
23733    false
23734}
23735
23736#[derive(Debug)]
23737enum NewlineConfig {
23738    /// Insert newline with optional additional indent and optional extra blank line
23739    Newline {
23740        additional_indent: IndentSize,
23741        extra_line_additional_indent: Option<IndentSize>,
23742        prevent_auto_indent: bool,
23743    },
23744    /// Clear the current line
23745    ClearCurrentLine,
23746    /// Unindent the current line and add continuation
23747    UnindentCurrentLine { continuation: Arc<str> },
23748}
23749
23750impl NewlineConfig {
23751    fn has_extra_line(&self) -> bool {
23752        matches!(
23753            self,
23754            Self::Newline {
23755                extra_line_additional_indent: Some(_),
23756                ..
23757            }
23758        )
23759    }
23760
23761    fn insert_extra_newline_brackets(
23762        buffer: &MultiBufferSnapshot,
23763        range: Range<MultiBufferOffset>,
23764        language: &language::LanguageScope,
23765    ) -> bool {
23766        let leading_whitespace_len = buffer
23767            .reversed_chars_at(range.start)
23768            .take_while(|c| c.is_whitespace() && *c != '\n')
23769            .map(|c| c.len_utf8())
23770            .sum::<usize>();
23771        let trailing_whitespace_len = buffer
23772            .chars_at(range.end)
23773            .take_while(|c| c.is_whitespace() && *c != '\n')
23774            .map(|c| c.len_utf8())
23775            .sum::<usize>();
23776        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
23777
23778        language.brackets().any(|(pair, enabled)| {
23779            let pair_start = pair.start.trim_end();
23780            let pair_end = pair.end.trim_start();
23781
23782            enabled
23783                && pair.newline
23784                && buffer.contains_str_at(range.end, pair_end)
23785                && buffer.contains_str_at(
23786                    range.start.saturating_sub_usize(pair_start.len()),
23787                    pair_start,
23788                )
23789        })
23790    }
23791
23792    fn insert_extra_newline_tree_sitter(
23793        buffer: &MultiBufferSnapshot,
23794        range: Range<MultiBufferOffset>,
23795    ) -> bool {
23796        let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
23797            [(buffer, range, _)] => (*buffer, range.clone()),
23798            _ => return false,
23799        };
23800        let pair = {
23801            let mut result: Option<BracketMatch<usize>> = None;
23802
23803            for pair in buffer
23804                .all_bracket_ranges(range.start.0..range.end.0)
23805                .filter(move |pair| {
23806                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
23807                })
23808            {
23809                let len = pair.close_range.end - pair.open_range.start;
23810
23811                if let Some(existing) = &result {
23812                    let existing_len = existing.close_range.end - existing.open_range.start;
23813                    if len > existing_len {
23814                        continue;
23815                    }
23816                }
23817
23818                result = Some(pair);
23819            }
23820
23821            result
23822        };
23823        let Some(pair) = pair else {
23824            return false;
23825        };
23826        pair.newline_only
23827            && buffer
23828                .chars_for_range(pair.open_range.end..range.start.0)
23829                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
23830                .all(|c| c.is_whitespace() && c != '\n')
23831    }
23832}
23833
23834fn update_uncommitted_diff_for_buffer(
23835    editor: Entity<Editor>,
23836    project: &Entity<Project>,
23837    buffers: impl IntoIterator<Item = Entity<Buffer>>,
23838    buffer: Entity<MultiBuffer>,
23839    cx: &mut App,
23840) -> Task<()> {
23841    let mut tasks = Vec::new();
23842    project.update(cx, |project, cx| {
23843        for buffer in buffers {
23844            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
23845                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
23846            }
23847        }
23848    });
23849    cx.spawn(async move |cx| {
23850        let diffs = future::join_all(tasks).await;
23851        if editor
23852            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
23853            .unwrap_or(false)
23854        {
23855            return;
23856        }
23857
23858        buffer
23859            .update(cx, |buffer, cx| {
23860                for diff in diffs.into_iter().flatten() {
23861                    buffer.add_diff(diff, cx);
23862                }
23863            })
23864            .ok();
23865    })
23866}
23867
23868fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
23869    let tab_size = tab_size.get() as usize;
23870    let mut width = offset;
23871
23872    for ch in text.chars() {
23873        width += if ch == '\t' {
23874            tab_size - (width % tab_size)
23875        } else {
23876            1
23877        };
23878    }
23879
23880    width - offset
23881}
23882
23883#[cfg(test)]
23884mod tests {
23885    use super::*;
23886
23887    #[test]
23888    fn test_string_size_with_expanded_tabs() {
23889        let nz = |val| NonZeroU32::new(val).unwrap();
23890        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
23891        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
23892        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
23893        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
23894        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
23895        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
23896        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
23897        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
23898    }
23899}
23900
23901/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
23902struct WordBreakingTokenizer<'a> {
23903    input: &'a str,
23904}
23905
23906impl<'a> WordBreakingTokenizer<'a> {
23907    fn new(input: &'a str) -> Self {
23908        Self { input }
23909    }
23910}
23911
23912fn is_char_ideographic(ch: char) -> bool {
23913    use unicode_script::Script::*;
23914    use unicode_script::UnicodeScript;
23915    matches!(ch.script(), Han | Tangut | Yi)
23916}
23917
23918fn is_grapheme_ideographic(text: &str) -> bool {
23919    text.chars().any(is_char_ideographic)
23920}
23921
23922fn is_grapheme_whitespace(text: &str) -> bool {
23923    text.chars().any(|x| x.is_whitespace())
23924}
23925
23926fn should_stay_with_preceding_ideograph(text: &str) -> bool {
23927    text.chars()
23928        .next()
23929        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
23930}
23931
23932#[derive(PartialEq, Eq, Debug, Clone, Copy)]
23933enum WordBreakToken<'a> {
23934    Word { token: &'a str, grapheme_len: usize },
23935    InlineWhitespace { token: &'a str, grapheme_len: usize },
23936    Newline,
23937}
23938
23939impl<'a> Iterator for WordBreakingTokenizer<'a> {
23940    /// Yields a span, the count of graphemes in the token, and whether it was
23941    /// whitespace. Note that it also breaks at word boundaries.
23942    type Item = WordBreakToken<'a>;
23943
23944    fn next(&mut self) -> Option<Self::Item> {
23945        use unicode_segmentation::UnicodeSegmentation;
23946        if self.input.is_empty() {
23947            return None;
23948        }
23949
23950        let mut iter = self.input.graphemes(true).peekable();
23951        let mut offset = 0;
23952        let mut grapheme_len = 0;
23953        if let Some(first_grapheme) = iter.next() {
23954            let is_newline = first_grapheme == "\n";
23955            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23956            offset += first_grapheme.len();
23957            grapheme_len += 1;
23958            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
23959                if let Some(grapheme) = iter.peek().copied()
23960                    && should_stay_with_preceding_ideograph(grapheme)
23961                {
23962                    offset += grapheme.len();
23963                    grapheme_len += 1;
23964                }
23965            } else {
23966                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23967                let mut next_word_bound = words.peek().copied();
23968                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23969                    next_word_bound = words.next();
23970                }
23971                while let Some(grapheme) = iter.peek().copied() {
23972                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23973                        break;
23974                    };
23975                    if is_grapheme_whitespace(grapheme) != is_whitespace
23976                        || (grapheme == "\n") != is_newline
23977                    {
23978                        break;
23979                    };
23980                    offset += grapheme.len();
23981                    grapheme_len += 1;
23982                    iter.next();
23983                }
23984            }
23985            let token = &self.input[..offset];
23986            self.input = &self.input[offset..];
23987            if token == "\n" {
23988                Some(WordBreakToken::Newline)
23989            } else if is_whitespace {
23990                Some(WordBreakToken::InlineWhitespace {
23991                    token,
23992                    grapheme_len,
23993                })
23994            } else {
23995                Some(WordBreakToken::Word {
23996                    token,
23997                    grapheme_len,
23998                })
23999            }
24000        } else {
24001            None
24002        }
24003    }
24004}
24005
24006#[test]
24007fn test_word_breaking_tokenizer() {
24008    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
24009        ("", &[]),
24010        ("  ", &[whitespace("  ", 2)]),
24011        ("Ʒ", &[word("Ʒ", 1)]),
24012        ("Ǽ", &[word("Ǽ", 1)]),
24013        ("", &[word("", 1)]),
24014        ("⋑⋑", &[word("⋑⋑", 2)]),
24015        (
24016            "原理,进而",
24017            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
24018        ),
24019        (
24020            "hello world",
24021            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
24022        ),
24023        (
24024            "hello, world",
24025            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
24026        ),
24027        (
24028            "  hello world",
24029            &[
24030                whitespace("  ", 2),
24031                word("hello", 5),
24032                whitespace(" ", 1),
24033                word("world", 5),
24034            ],
24035        ),
24036        (
24037            "这是什么 \n 钢笔",
24038            &[
24039                word("", 1),
24040                word("", 1),
24041                word("", 1),
24042                word("", 1),
24043                whitespace(" ", 1),
24044                newline(),
24045                whitespace(" ", 1),
24046                word("", 1),
24047                word("", 1),
24048            ],
24049        ),
24050        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
24051    ];
24052
24053    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
24054        WordBreakToken::Word {
24055            token,
24056            grapheme_len,
24057        }
24058    }
24059
24060    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
24061        WordBreakToken::InlineWhitespace {
24062            token,
24063            grapheme_len,
24064        }
24065    }
24066
24067    fn newline() -> WordBreakToken<'static> {
24068        WordBreakToken::Newline
24069    }
24070
24071    for (input, result) in tests {
24072        assert_eq!(
24073            WordBreakingTokenizer::new(input)
24074                .collect::<Vec<_>>()
24075                .as_slice(),
24076            *result,
24077        );
24078    }
24079}
24080
24081fn wrap_with_prefix(
24082    first_line_prefix: String,
24083    subsequent_lines_prefix: String,
24084    unwrapped_text: String,
24085    wrap_column: usize,
24086    tab_size: NonZeroU32,
24087    preserve_existing_whitespace: bool,
24088) -> String {
24089    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
24090    let subsequent_lines_prefix_len =
24091        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
24092    let mut wrapped_text = String::new();
24093    let mut current_line = first_line_prefix;
24094    let mut is_first_line = true;
24095
24096    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
24097    let mut current_line_len = first_line_prefix_len;
24098    let mut in_whitespace = false;
24099    for token in tokenizer {
24100        let have_preceding_whitespace = in_whitespace;
24101        match token {
24102            WordBreakToken::Word {
24103                token,
24104                grapheme_len,
24105            } => {
24106                in_whitespace = false;
24107                let current_prefix_len = if is_first_line {
24108                    first_line_prefix_len
24109                } else {
24110                    subsequent_lines_prefix_len
24111                };
24112                if current_line_len + grapheme_len > wrap_column
24113                    && current_line_len != current_prefix_len
24114                {
24115                    wrapped_text.push_str(current_line.trim_end());
24116                    wrapped_text.push('\n');
24117                    is_first_line = false;
24118                    current_line = subsequent_lines_prefix.clone();
24119                    current_line_len = subsequent_lines_prefix_len;
24120                }
24121                current_line.push_str(token);
24122                current_line_len += grapheme_len;
24123            }
24124            WordBreakToken::InlineWhitespace {
24125                mut token,
24126                mut grapheme_len,
24127            } => {
24128                in_whitespace = true;
24129                if have_preceding_whitespace && !preserve_existing_whitespace {
24130                    continue;
24131                }
24132                if !preserve_existing_whitespace {
24133                    // Keep a single whitespace grapheme as-is
24134                    if let Some(first) =
24135                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
24136                    {
24137                        token = first;
24138                    } else {
24139                        token = " ";
24140                    }
24141                    grapheme_len = 1;
24142                }
24143                let current_prefix_len = if is_first_line {
24144                    first_line_prefix_len
24145                } else {
24146                    subsequent_lines_prefix_len
24147                };
24148                if current_line_len + grapheme_len > wrap_column {
24149                    wrapped_text.push_str(current_line.trim_end());
24150                    wrapped_text.push('\n');
24151                    is_first_line = false;
24152                    current_line = subsequent_lines_prefix.clone();
24153                    current_line_len = subsequent_lines_prefix_len;
24154                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
24155                    current_line.push_str(token);
24156                    current_line_len += grapheme_len;
24157                }
24158            }
24159            WordBreakToken::Newline => {
24160                in_whitespace = true;
24161                let current_prefix_len = if is_first_line {
24162                    first_line_prefix_len
24163                } else {
24164                    subsequent_lines_prefix_len
24165                };
24166                if preserve_existing_whitespace {
24167                    wrapped_text.push_str(current_line.trim_end());
24168                    wrapped_text.push('\n');
24169                    is_first_line = false;
24170                    current_line = subsequent_lines_prefix.clone();
24171                    current_line_len = subsequent_lines_prefix_len;
24172                } else if have_preceding_whitespace {
24173                    continue;
24174                } else if current_line_len + 1 > wrap_column
24175                    && current_line_len != current_prefix_len
24176                {
24177                    wrapped_text.push_str(current_line.trim_end());
24178                    wrapped_text.push('\n');
24179                    is_first_line = false;
24180                    current_line = subsequent_lines_prefix.clone();
24181                    current_line_len = subsequent_lines_prefix_len;
24182                } else if current_line_len != current_prefix_len {
24183                    current_line.push(' ');
24184                    current_line_len += 1;
24185                }
24186            }
24187        }
24188    }
24189
24190    if !current_line.is_empty() {
24191        wrapped_text.push_str(&current_line);
24192    }
24193    wrapped_text
24194}
24195
24196#[test]
24197fn test_wrap_with_prefix() {
24198    assert_eq!(
24199        wrap_with_prefix(
24200            "# ".to_string(),
24201            "# ".to_string(),
24202            "abcdefg".to_string(),
24203            4,
24204            NonZeroU32::new(4).unwrap(),
24205            false,
24206        ),
24207        "# abcdefg"
24208    );
24209    assert_eq!(
24210        wrap_with_prefix(
24211            "".to_string(),
24212            "".to_string(),
24213            "\thello world".to_string(),
24214            8,
24215            NonZeroU32::new(4).unwrap(),
24216            false,
24217        ),
24218        "hello\nworld"
24219    );
24220    assert_eq!(
24221        wrap_with_prefix(
24222            "// ".to_string(),
24223            "// ".to_string(),
24224            "xx \nyy zz aa bb cc".to_string(),
24225            12,
24226            NonZeroU32::new(4).unwrap(),
24227            false,
24228        ),
24229        "// xx yy zz\n// aa bb cc"
24230    );
24231    assert_eq!(
24232        wrap_with_prefix(
24233            String::new(),
24234            String::new(),
24235            "这是什么 \n 钢笔".to_string(),
24236            3,
24237            NonZeroU32::new(4).unwrap(),
24238            false,
24239        ),
24240        "这是什\n么 钢\n"
24241    );
24242    assert_eq!(
24243        wrap_with_prefix(
24244            String::new(),
24245            String::new(),
24246            format!("foo{}bar", '\u{2009}'), // thin space
24247            80,
24248            NonZeroU32::new(4).unwrap(),
24249            false,
24250        ),
24251        format!("foo{}bar", '\u{2009}')
24252    );
24253}
24254
24255pub trait CollaborationHub {
24256    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
24257    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
24258    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
24259}
24260
24261impl CollaborationHub for Entity<Project> {
24262    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
24263        self.read(cx).collaborators()
24264    }
24265
24266    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
24267        self.read(cx).user_store().read(cx).participant_indices()
24268    }
24269
24270    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
24271        let this = self.read(cx);
24272        let user_ids = this.collaborators().values().map(|c| c.user_id);
24273        this.user_store().read(cx).participant_names(user_ids, cx)
24274    }
24275}
24276
24277pub trait SemanticsProvider {
24278    fn hover(
24279        &self,
24280        buffer: &Entity<Buffer>,
24281        position: text::Anchor,
24282        cx: &mut App,
24283    ) -> Option<Task<Option<Vec<project::Hover>>>>;
24284
24285    fn inline_values(
24286        &self,
24287        buffer_handle: Entity<Buffer>,
24288        range: Range<text::Anchor>,
24289        cx: &mut App,
24290    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
24291
24292    fn applicable_inlay_chunks(
24293        &self,
24294        buffer: &Entity<Buffer>,
24295        ranges: &[Range<text::Anchor>],
24296        cx: &mut App,
24297    ) -> Vec<Range<BufferRow>>;
24298
24299    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
24300
24301    fn inlay_hints(
24302        &self,
24303        invalidate: InvalidationStrategy,
24304        buffer: Entity<Buffer>,
24305        ranges: Vec<Range<text::Anchor>>,
24306        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24307        cx: &mut App,
24308    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
24309
24310    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
24311
24312    fn document_highlights(
24313        &self,
24314        buffer: &Entity<Buffer>,
24315        position: text::Anchor,
24316        cx: &mut App,
24317    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
24318
24319    fn definitions(
24320        &self,
24321        buffer: &Entity<Buffer>,
24322        position: text::Anchor,
24323        kind: GotoDefinitionKind,
24324        cx: &mut App,
24325    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
24326
24327    fn range_for_rename(
24328        &self,
24329        buffer: &Entity<Buffer>,
24330        position: text::Anchor,
24331        cx: &mut App,
24332    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
24333
24334    fn perform_rename(
24335        &self,
24336        buffer: &Entity<Buffer>,
24337        position: text::Anchor,
24338        new_name: String,
24339        cx: &mut App,
24340    ) -> Option<Task<Result<ProjectTransaction>>>;
24341}
24342
24343pub trait CompletionProvider {
24344    fn completions(
24345        &self,
24346        excerpt_id: ExcerptId,
24347        buffer: &Entity<Buffer>,
24348        buffer_position: text::Anchor,
24349        trigger: CompletionContext,
24350        window: &mut Window,
24351        cx: &mut Context<Editor>,
24352    ) -> Task<Result<Vec<CompletionResponse>>>;
24353
24354    fn resolve_completions(
24355        &self,
24356        _buffer: Entity<Buffer>,
24357        _completion_indices: Vec<usize>,
24358        _completions: Rc<RefCell<Box<[Completion]>>>,
24359        _cx: &mut Context<Editor>,
24360    ) -> Task<Result<bool>> {
24361        Task::ready(Ok(false))
24362    }
24363
24364    fn apply_additional_edits_for_completion(
24365        &self,
24366        _buffer: Entity<Buffer>,
24367        _completions: Rc<RefCell<Box<[Completion]>>>,
24368        _completion_index: usize,
24369        _push_to_history: bool,
24370        _cx: &mut Context<Editor>,
24371    ) -> Task<Result<Option<language::Transaction>>> {
24372        Task::ready(Ok(None))
24373    }
24374
24375    fn is_completion_trigger(
24376        &self,
24377        buffer: &Entity<Buffer>,
24378        position: language::Anchor,
24379        text: &str,
24380        trigger_in_words: bool,
24381        cx: &mut Context<Editor>,
24382    ) -> bool;
24383
24384    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
24385
24386    fn sort_completions(&self) -> bool {
24387        true
24388    }
24389
24390    fn filter_completions(&self) -> bool {
24391        true
24392    }
24393
24394    fn show_snippets(&self) -> bool {
24395        false
24396    }
24397}
24398
24399pub trait CodeActionProvider {
24400    fn id(&self) -> Arc<str>;
24401
24402    fn code_actions(
24403        &self,
24404        buffer: &Entity<Buffer>,
24405        range: Range<text::Anchor>,
24406        window: &mut Window,
24407        cx: &mut App,
24408    ) -> Task<Result<Vec<CodeAction>>>;
24409
24410    fn apply_code_action(
24411        &self,
24412        buffer_handle: Entity<Buffer>,
24413        action: CodeAction,
24414        excerpt_id: ExcerptId,
24415        push_to_history: bool,
24416        window: &mut Window,
24417        cx: &mut App,
24418    ) -> Task<Result<ProjectTransaction>>;
24419}
24420
24421impl CodeActionProvider for Entity<Project> {
24422    fn id(&self) -> Arc<str> {
24423        "project".into()
24424    }
24425
24426    fn code_actions(
24427        &self,
24428        buffer: &Entity<Buffer>,
24429        range: Range<text::Anchor>,
24430        _window: &mut Window,
24431        cx: &mut App,
24432    ) -> Task<Result<Vec<CodeAction>>> {
24433        self.update(cx, |project, cx| {
24434            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
24435            let code_actions = project.code_actions(buffer, range, None, cx);
24436            cx.background_spawn(async move {
24437                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
24438                Ok(code_lens_actions
24439                    .context("code lens fetch")?
24440                    .into_iter()
24441                    .flatten()
24442                    .chain(
24443                        code_actions
24444                            .context("code action fetch")?
24445                            .into_iter()
24446                            .flatten(),
24447                    )
24448                    .collect())
24449            })
24450        })
24451    }
24452
24453    fn apply_code_action(
24454        &self,
24455        buffer_handle: Entity<Buffer>,
24456        action: CodeAction,
24457        _excerpt_id: ExcerptId,
24458        push_to_history: bool,
24459        _window: &mut Window,
24460        cx: &mut App,
24461    ) -> Task<Result<ProjectTransaction>> {
24462        self.update(cx, |project, cx| {
24463            project.apply_code_action(buffer_handle, action, push_to_history, cx)
24464        })
24465    }
24466}
24467
24468fn snippet_completions(
24469    project: &Project,
24470    buffer: &Entity<Buffer>,
24471    buffer_anchor: text::Anchor,
24472    classifier: CharClassifier,
24473    cx: &mut App,
24474) -> Task<Result<CompletionResponse>> {
24475    let languages = buffer.read(cx).languages_at(buffer_anchor);
24476    let snippet_store = project.snippets().read(cx);
24477
24478    let scopes: Vec<_> = languages
24479        .iter()
24480        .filter_map(|language| {
24481            let language_name = language.lsp_id();
24482            let snippets = snippet_store.snippets_for(Some(language_name), cx);
24483
24484            if snippets.is_empty() {
24485                None
24486            } else {
24487                Some((language.default_scope(), snippets))
24488            }
24489        })
24490        .collect();
24491
24492    if scopes.is_empty() {
24493        return Task::ready(Ok(CompletionResponse {
24494            completions: vec![],
24495            display_options: CompletionDisplayOptions::default(),
24496            is_incomplete: false,
24497        }));
24498    }
24499
24500    let snapshot = buffer.read(cx).text_snapshot();
24501    let executor = cx.background_executor().clone();
24502
24503    cx.background_spawn(async move {
24504        let is_word_char = |c| classifier.is_word(c);
24505
24506        let mut is_incomplete = false;
24507        let mut completions: Vec<Completion> = Vec::new();
24508
24509        const MAX_PREFIX_LEN: usize = 128;
24510        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
24511        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
24512        let window_start = snapshot.clip_offset(window_start, Bias::Left);
24513
24514        let max_buffer_window: String = snapshot
24515            .text_for_range(window_start..buffer_offset)
24516            .collect();
24517
24518        if max_buffer_window.is_empty() {
24519            return Ok(CompletionResponse {
24520                completions: vec![],
24521                display_options: CompletionDisplayOptions::default(),
24522                is_incomplete: true,
24523            });
24524        }
24525
24526        for (_scope, snippets) in scopes.into_iter() {
24527            // Sort snippets by word count to match longer snippet prefixes first.
24528            let mut sorted_snippet_candidates = snippets
24529                .iter()
24530                .enumerate()
24531                .flat_map(|(snippet_ix, snippet)| {
24532                    snippet
24533                        .prefix
24534                        .iter()
24535                        .enumerate()
24536                        .map(move |(prefix_ix, prefix)| {
24537                            let word_count =
24538                                snippet_candidate_suffixes(prefix, is_word_char).count();
24539                            ((snippet_ix, prefix_ix), prefix, word_count)
24540                        })
24541                })
24542                .collect_vec();
24543            sorted_snippet_candidates
24544                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
24545
24546            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
24547
24548            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
24549                .take(
24550                    sorted_snippet_candidates
24551                        .first()
24552                        .map(|(_, _, word_count)| *word_count)
24553                        .unwrap_or_default(),
24554                )
24555                .collect_vec();
24556
24557            const MAX_RESULTS: usize = 100;
24558            // Each match also remembers how many characters from the buffer it consumed
24559            let mut matches: Vec<(StringMatch, usize)> = vec![];
24560
24561            let mut snippet_list_cutoff_index = 0;
24562            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
24563                let word_count = buffer_index + 1;
24564                // Increase `snippet_list_cutoff_index` until we have all of the
24565                // snippets with sufficiently many words.
24566                while sorted_snippet_candidates
24567                    .get(snippet_list_cutoff_index)
24568                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
24569                        *snippet_word_count >= word_count
24570                    })
24571                {
24572                    snippet_list_cutoff_index += 1;
24573                }
24574
24575                // Take only the candidates with at least `word_count` many words
24576                let snippet_candidates_at_word_len =
24577                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
24578
24579                let candidates = snippet_candidates_at_word_len
24580                    .iter()
24581                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
24582                    .enumerate() // index in `sorted_snippet_candidates`
24583                    // First char must match
24584                    .filter(|(_ix, prefix)| {
24585                        itertools::equal(
24586                            prefix
24587                                .chars()
24588                                .next()
24589                                .into_iter()
24590                                .flat_map(|c| c.to_lowercase()),
24591                            buffer_window
24592                                .chars()
24593                                .next()
24594                                .into_iter()
24595                                .flat_map(|c| c.to_lowercase()),
24596                        )
24597                    })
24598                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
24599                    .collect::<Vec<StringMatchCandidate>>();
24600
24601                matches.extend(
24602                    fuzzy::match_strings(
24603                        &candidates,
24604                        &buffer_window,
24605                        buffer_window.chars().any(|c| c.is_uppercase()),
24606                        true,
24607                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
24608                        &Default::default(),
24609                        executor.clone(),
24610                    )
24611                    .await
24612                    .into_iter()
24613                    .map(|string_match| (string_match, buffer_window.len())),
24614                );
24615
24616                if matches.len() >= MAX_RESULTS {
24617                    break;
24618                }
24619            }
24620
24621            let to_lsp = |point: &text::Anchor| {
24622                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
24623                point_to_lsp(end)
24624            };
24625            let lsp_end = to_lsp(&buffer_anchor);
24626
24627            if matches.len() >= MAX_RESULTS {
24628                is_incomplete = true;
24629            }
24630
24631            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
24632                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
24633                    sorted_snippet_candidates[string_match.candidate_id];
24634                let snippet = &snippets[snippet_index];
24635                let start = buffer_offset - buffer_window_len;
24636                let start = snapshot.anchor_before(start);
24637                let range = start..buffer_anchor;
24638                let lsp_start = to_lsp(&start);
24639                let lsp_range = lsp::Range {
24640                    start: lsp_start,
24641                    end: lsp_end,
24642                };
24643                Completion {
24644                    replace_range: range,
24645                    new_text: snippet.body.clone(),
24646                    source: CompletionSource::Lsp {
24647                        insert_range: None,
24648                        server_id: LanguageServerId(usize::MAX),
24649                        resolved: true,
24650                        lsp_completion: Box::new(lsp::CompletionItem {
24651                            label: snippet.prefix.first().unwrap().clone(),
24652                            kind: Some(CompletionItemKind::SNIPPET),
24653                            label_details: snippet.description.as_ref().map(|description| {
24654                                lsp::CompletionItemLabelDetails {
24655                                    detail: Some(description.clone()),
24656                                    description: None,
24657                                }
24658                            }),
24659                            insert_text_format: Some(InsertTextFormat::SNIPPET),
24660                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
24661                                lsp::InsertReplaceEdit {
24662                                    new_text: snippet.body.clone(),
24663                                    insert: lsp_range,
24664                                    replace: lsp_range,
24665                                },
24666                            )),
24667                            filter_text: Some(snippet.body.clone()),
24668                            sort_text: Some(char::MAX.to_string()),
24669                            ..lsp::CompletionItem::default()
24670                        }),
24671                        lsp_defaults: None,
24672                    },
24673                    label: CodeLabel {
24674                        text: matching_prefix.clone(),
24675                        runs: Vec::new(),
24676                        filter_range: 0..matching_prefix.len(),
24677                    },
24678                    icon_path: None,
24679                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
24680                        single_line: snippet.name.clone().into(),
24681                        plain_text: snippet
24682                            .description
24683                            .clone()
24684                            .map(|description| description.into()),
24685                    }),
24686                    insert_text_mode: None,
24687                    confirm: None,
24688                    match_start: Some(start),
24689                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
24690                }
24691            }));
24692        }
24693
24694        Ok(CompletionResponse {
24695            completions,
24696            display_options: CompletionDisplayOptions::default(),
24697            is_incomplete,
24698        })
24699    })
24700}
24701
24702impl CompletionProvider for Entity<Project> {
24703    fn completions(
24704        &self,
24705        _excerpt_id: ExcerptId,
24706        buffer: &Entity<Buffer>,
24707        buffer_position: text::Anchor,
24708        options: CompletionContext,
24709        _window: &mut Window,
24710        cx: &mut Context<Editor>,
24711    ) -> Task<Result<Vec<CompletionResponse>>> {
24712        self.update(cx, |project, cx| {
24713            let task = project.completions(buffer, buffer_position, options, cx);
24714            cx.background_spawn(task)
24715        })
24716    }
24717
24718    fn resolve_completions(
24719        &self,
24720        buffer: Entity<Buffer>,
24721        completion_indices: Vec<usize>,
24722        completions: Rc<RefCell<Box<[Completion]>>>,
24723        cx: &mut Context<Editor>,
24724    ) -> Task<Result<bool>> {
24725        self.update(cx, |project, cx| {
24726            project.lsp_store().update(cx, |lsp_store, cx| {
24727                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
24728            })
24729        })
24730    }
24731
24732    fn apply_additional_edits_for_completion(
24733        &self,
24734        buffer: Entity<Buffer>,
24735        completions: Rc<RefCell<Box<[Completion]>>>,
24736        completion_index: usize,
24737        push_to_history: bool,
24738        cx: &mut Context<Editor>,
24739    ) -> Task<Result<Option<language::Transaction>>> {
24740        self.update(cx, |project, cx| {
24741            project.lsp_store().update(cx, |lsp_store, cx| {
24742                lsp_store.apply_additional_edits_for_completion(
24743                    buffer,
24744                    completions,
24745                    completion_index,
24746                    push_to_history,
24747                    cx,
24748                )
24749            })
24750        })
24751    }
24752
24753    fn is_completion_trigger(
24754        &self,
24755        buffer: &Entity<Buffer>,
24756        position: language::Anchor,
24757        text: &str,
24758        trigger_in_words: bool,
24759        cx: &mut Context<Editor>,
24760    ) -> bool {
24761        let mut chars = text.chars();
24762        let char = if let Some(char) = chars.next() {
24763            char
24764        } else {
24765            return false;
24766        };
24767        if chars.next().is_some() {
24768            return false;
24769        }
24770
24771        let buffer = buffer.read(cx);
24772        let snapshot = buffer.snapshot();
24773        let classifier = snapshot
24774            .char_classifier_at(position)
24775            .scope_context(Some(CharScopeContext::Completion));
24776        if trigger_in_words && classifier.is_word(char) {
24777            return true;
24778        }
24779
24780        buffer.completion_triggers().contains(text)
24781    }
24782
24783    fn show_snippets(&self) -> bool {
24784        true
24785    }
24786}
24787
24788impl SemanticsProvider for Entity<Project> {
24789    fn hover(
24790        &self,
24791        buffer: &Entity<Buffer>,
24792        position: text::Anchor,
24793        cx: &mut App,
24794    ) -> Option<Task<Option<Vec<project::Hover>>>> {
24795        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
24796    }
24797
24798    fn document_highlights(
24799        &self,
24800        buffer: &Entity<Buffer>,
24801        position: text::Anchor,
24802        cx: &mut App,
24803    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
24804        Some(self.update(cx, |project, cx| {
24805            project.document_highlights(buffer, position, cx)
24806        }))
24807    }
24808
24809    fn definitions(
24810        &self,
24811        buffer: &Entity<Buffer>,
24812        position: text::Anchor,
24813        kind: GotoDefinitionKind,
24814        cx: &mut App,
24815    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
24816        Some(self.update(cx, |project, cx| match kind {
24817            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
24818            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
24819            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
24820            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
24821        }))
24822    }
24823
24824    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
24825        self.update(cx, |project, cx| {
24826            if project
24827                .active_debug_session(cx)
24828                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
24829            {
24830                return true;
24831            }
24832
24833            buffer.update(cx, |buffer, cx| {
24834                project.any_language_server_supports_inlay_hints(buffer, cx)
24835            })
24836        })
24837    }
24838
24839    fn inline_values(
24840        &self,
24841        buffer_handle: Entity<Buffer>,
24842        range: Range<text::Anchor>,
24843        cx: &mut App,
24844    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
24845        self.update(cx, |project, cx| {
24846            let (session, active_stack_frame) = project.active_debug_session(cx)?;
24847
24848            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
24849        })
24850    }
24851
24852    fn applicable_inlay_chunks(
24853        &self,
24854        buffer: &Entity<Buffer>,
24855        ranges: &[Range<text::Anchor>],
24856        cx: &mut App,
24857    ) -> Vec<Range<BufferRow>> {
24858        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24859            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
24860        })
24861    }
24862
24863    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
24864        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
24865            lsp_store.invalidate_inlay_hints(for_buffers)
24866        });
24867    }
24868
24869    fn inlay_hints(
24870        &self,
24871        invalidate: InvalidationStrategy,
24872        buffer: Entity<Buffer>,
24873        ranges: Vec<Range<text::Anchor>>,
24874        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24875        cx: &mut App,
24876    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
24877        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24878            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
24879        }))
24880    }
24881
24882    fn range_for_rename(
24883        &self,
24884        buffer: &Entity<Buffer>,
24885        position: text::Anchor,
24886        cx: &mut App,
24887    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
24888        Some(self.update(cx, |project, cx| {
24889            let buffer = buffer.clone();
24890            let task = project.prepare_rename(buffer.clone(), position, cx);
24891            cx.spawn(async move |_, cx| {
24892                Ok(match task.await? {
24893                    PrepareRenameResponse::Success(range) => Some(range),
24894                    PrepareRenameResponse::InvalidPosition => None,
24895                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
24896                        // Fallback on using TreeSitter info to determine identifier range
24897                        buffer.read_with(cx, |buffer, _| {
24898                            let snapshot = buffer.snapshot();
24899                            let (range, kind) = snapshot.surrounding_word(position, None);
24900                            if kind != Some(CharKind::Word) {
24901                                return None;
24902                            }
24903                            Some(
24904                                snapshot.anchor_before(range.start)
24905                                    ..snapshot.anchor_after(range.end),
24906                            )
24907                        })?
24908                    }
24909                })
24910            })
24911        }))
24912    }
24913
24914    fn perform_rename(
24915        &self,
24916        buffer: &Entity<Buffer>,
24917        position: text::Anchor,
24918        new_name: String,
24919        cx: &mut App,
24920    ) -> Option<Task<Result<ProjectTransaction>>> {
24921        Some(self.update(cx, |project, cx| {
24922            project.perform_rename(buffer.clone(), position, new_name, cx)
24923        }))
24924    }
24925}
24926
24927fn consume_contiguous_rows(
24928    contiguous_row_selections: &mut Vec<Selection<Point>>,
24929    selection: &Selection<Point>,
24930    display_map: &DisplaySnapshot,
24931    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
24932) -> (MultiBufferRow, MultiBufferRow) {
24933    contiguous_row_selections.push(selection.clone());
24934    let start_row = starting_row(selection, display_map);
24935    let mut end_row = ending_row(selection, display_map);
24936
24937    while let Some(next_selection) = selections.peek() {
24938        if next_selection.start.row <= end_row.0 {
24939            end_row = ending_row(next_selection, display_map);
24940            contiguous_row_selections.push(selections.next().unwrap().clone());
24941        } else {
24942            break;
24943        }
24944    }
24945    (start_row, end_row)
24946}
24947
24948fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24949    if selection.start.column > 0 {
24950        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
24951    } else {
24952        MultiBufferRow(selection.start.row)
24953    }
24954}
24955
24956fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24957    if next_selection.end.column > 0 || next_selection.is_empty() {
24958        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
24959    } else {
24960        MultiBufferRow(next_selection.end.row)
24961    }
24962}
24963
24964impl EditorSnapshot {
24965    pub fn remote_selections_in_range<'a>(
24966        &'a self,
24967        range: &'a Range<Anchor>,
24968        collaboration_hub: &dyn CollaborationHub,
24969        cx: &'a App,
24970    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24971        let participant_names = collaboration_hub.user_names(cx);
24972        let participant_indices = collaboration_hub.user_participant_indices(cx);
24973        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24974        let collaborators_by_replica_id = collaborators_by_peer_id
24975            .values()
24976            .map(|collaborator| (collaborator.replica_id, collaborator))
24977            .collect::<HashMap<_, _>>();
24978        self.buffer_snapshot()
24979            .selections_in_range(range, false)
24980            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24981                if replica_id == ReplicaId::AGENT {
24982                    Some(RemoteSelection {
24983                        replica_id,
24984                        selection,
24985                        cursor_shape,
24986                        line_mode,
24987                        collaborator_id: CollaboratorId::Agent,
24988                        user_name: Some("Agent".into()),
24989                        color: cx.theme().players().agent(),
24990                    })
24991                } else {
24992                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24993                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24994                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24995                    Some(RemoteSelection {
24996                        replica_id,
24997                        selection,
24998                        cursor_shape,
24999                        line_mode,
25000                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
25001                        user_name,
25002                        color: if let Some(index) = participant_index {
25003                            cx.theme().players().color_for_participant(index.0)
25004                        } else {
25005                            cx.theme().players().absent()
25006                        },
25007                    })
25008                }
25009            })
25010    }
25011
25012    pub fn hunks_for_ranges(
25013        &self,
25014        ranges: impl IntoIterator<Item = Range<Point>>,
25015    ) -> Vec<MultiBufferDiffHunk> {
25016        let mut hunks = Vec::new();
25017        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
25018            HashMap::default();
25019        for query_range in ranges {
25020            let query_rows =
25021                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
25022            for hunk in self.buffer_snapshot().diff_hunks_in_range(
25023                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
25024            ) {
25025                // Include deleted hunks that are adjacent to the query range, because
25026                // otherwise they would be missed.
25027                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
25028                if hunk.status().is_deleted() {
25029                    intersects_range |= hunk.row_range.start == query_rows.end;
25030                    intersects_range |= hunk.row_range.end == query_rows.start;
25031                }
25032                if intersects_range {
25033                    if !processed_buffer_rows
25034                        .entry(hunk.buffer_id)
25035                        .or_default()
25036                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
25037                    {
25038                        continue;
25039                    }
25040                    hunks.push(hunk);
25041                }
25042            }
25043        }
25044
25045        hunks
25046    }
25047
25048    fn display_diff_hunks_for_rows<'a>(
25049        &'a self,
25050        display_rows: Range<DisplayRow>,
25051        folded_buffers: &'a HashSet<BufferId>,
25052    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
25053        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
25054        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
25055
25056        self.buffer_snapshot()
25057            .diff_hunks_in_range(buffer_start..buffer_end)
25058            .filter_map(|hunk| {
25059                if folded_buffers.contains(&hunk.buffer_id) {
25060                    return None;
25061                }
25062
25063                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
25064                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
25065
25066                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
25067                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
25068
25069                let display_hunk = if hunk_display_start.column() != 0 {
25070                    DisplayDiffHunk::Folded {
25071                        display_row: hunk_display_start.row(),
25072                    }
25073                } else {
25074                    let mut end_row = hunk_display_end.row();
25075                    if hunk_display_end.column() > 0 {
25076                        end_row.0 += 1;
25077                    }
25078                    let is_created_file = hunk.is_created_file();
25079
25080                    DisplayDiffHunk::Unfolded {
25081                        status: hunk.status(),
25082                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
25083                            ..hunk.diff_base_byte_range.end.0,
25084                        word_diffs: hunk.word_diffs,
25085                        display_row_range: hunk_display_start.row()..end_row,
25086                        multi_buffer_range: Anchor::range_in_buffer(
25087                            hunk.excerpt_id,
25088                            hunk.buffer_range,
25089                        ),
25090                        is_created_file,
25091                    }
25092                };
25093
25094                Some(display_hunk)
25095            })
25096    }
25097
25098    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
25099        self.display_snapshot
25100            .buffer_snapshot()
25101            .language_at(position)
25102    }
25103
25104    pub fn is_focused(&self) -> bool {
25105        self.is_focused
25106    }
25107
25108    pub fn placeholder_text(&self) -> Option<String> {
25109        self.placeholder_display_snapshot
25110            .as_ref()
25111            .map(|display_map| display_map.text())
25112    }
25113
25114    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
25115        self.scroll_anchor.scroll_position(&self.display_snapshot)
25116    }
25117
25118    pub fn gutter_dimensions(
25119        &self,
25120        font_id: FontId,
25121        font_size: Pixels,
25122        style: &EditorStyle,
25123        window: &mut Window,
25124        cx: &App,
25125    ) -> GutterDimensions {
25126        if self.show_gutter
25127            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
25128            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
25129        {
25130            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
25131                matches!(
25132                    ProjectSettings::get_global(cx).git.git_gutter,
25133                    GitGutterSetting::TrackedFiles
25134                )
25135            });
25136            let gutter_settings = EditorSettings::get_global(cx).gutter;
25137            let show_line_numbers = self
25138                .show_line_numbers
25139                .unwrap_or(gutter_settings.line_numbers);
25140            let line_gutter_width = if show_line_numbers {
25141                // Avoid flicker-like gutter resizes when the line number gains another digit by
25142                // only resizing the gutter on files with > 10**min_line_number_digits lines.
25143                let min_width_for_number_on_gutter =
25144                    ch_advance * gutter_settings.min_line_number_digits as f32;
25145                self.max_line_number_width(style, window)
25146                    .max(min_width_for_number_on_gutter)
25147            } else {
25148                0.0.into()
25149            };
25150
25151            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
25152            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
25153
25154            let git_blame_entries_width =
25155                self.git_blame_gutter_max_author_length
25156                    .map(|max_author_length| {
25157                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
25158                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
25159
25160                        /// The number of characters to dedicate to gaps and margins.
25161                        const SPACING_WIDTH: usize = 4;
25162
25163                        let max_char_count = max_author_length.min(renderer.max_author_length())
25164                            + ::git::SHORT_SHA_LENGTH
25165                            + MAX_RELATIVE_TIMESTAMP.len()
25166                            + SPACING_WIDTH;
25167
25168                        ch_advance * max_char_count
25169                    });
25170
25171            let is_singleton = self.buffer_snapshot().is_singleton();
25172
25173            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
25174            left_padding += if !is_singleton {
25175                ch_width * 4.0
25176            } else if show_runnables || show_breakpoints {
25177                ch_width * 3.0
25178            } else if show_git_gutter && show_line_numbers {
25179                ch_width * 2.0
25180            } else if show_git_gutter || show_line_numbers {
25181                ch_width
25182            } else {
25183                px(0.)
25184            };
25185
25186            let shows_folds = is_singleton && gutter_settings.folds;
25187
25188            let right_padding = if shows_folds && show_line_numbers {
25189                ch_width * 4.0
25190            } else if shows_folds || (!is_singleton && show_line_numbers) {
25191                ch_width * 3.0
25192            } else if show_line_numbers {
25193                ch_width
25194            } else {
25195                px(0.)
25196            };
25197
25198            GutterDimensions {
25199                left_padding,
25200                right_padding,
25201                width: line_gutter_width + left_padding + right_padding,
25202                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
25203                git_blame_entries_width,
25204            }
25205        } else if self.offset_content {
25206            GutterDimensions::default_with_margin(font_id, font_size, cx)
25207        } else {
25208            GutterDimensions::default()
25209        }
25210    }
25211
25212    pub fn render_crease_toggle(
25213        &self,
25214        buffer_row: MultiBufferRow,
25215        row_contains_cursor: bool,
25216        editor: Entity<Editor>,
25217        window: &mut Window,
25218        cx: &mut App,
25219    ) -> Option<AnyElement> {
25220        let folded = self.is_line_folded(buffer_row);
25221        let mut is_foldable = false;
25222
25223        if let Some(crease) = self
25224            .crease_snapshot
25225            .query_row(buffer_row, self.buffer_snapshot())
25226        {
25227            is_foldable = true;
25228            match crease {
25229                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
25230                    if let Some(render_toggle) = render_toggle {
25231                        let toggle_callback =
25232                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
25233                                if folded {
25234                                    editor.update(cx, |editor, cx| {
25235                                        editor.fold_at(buffer_row, window, cx)
25236                                    });
25237                                } else {
25238                                    editor.update(cx, |editor, cx| {
25239                                        editor.unfold_at(buffer_row, window, cx)
25240                                    });
25241                                }
25242                            });
25243                        return Some((render_toggle)(
25244                            buffer_row,
25245                            folded,
25246                            toggle_callback,
25247                            window,
25248                            cx,
25249                        ));
25250                    }
25251                }
25252            }
25253        }
25254
25255        is_foldable |= self.starts_indent(buffer_row);
25256
25257        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
25258            Some(
25259                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
25260                    .toggle_state(folded)
25261                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
25262                        if folded {
25263                            this.unfold_at(buffer_row, window, cx);
25264                        } else {
25265                            this.fold_at(buffer_row, window, cx);
25266                        }
25267                    }))
25268                    .into_any_element(),
25269            )
25270        } else {
25271            None
25272        }
25273    }
25274
25275    pub fn render_crease_trailer(
25276        &self,
25277        buffer_row: MultiBufferRow,
25278        window: &mut Window,
25279        cx: &mut App,
25280    ) -> Option<AnyElement> {
25281        let folded = self.is_line_folded(buffer_row);
25282        if let Crease::Inline { render_trailer, .. } = self
25283            .crease_snapshot
25284            .query_row(buffer_row, self.buffer_snapshot())?
25285        {
25286            let render_trailer = render_trailer.as_ref()?;
25287            Some(render_trailer(buffer_row, folded, window, cx))
25288        } else {
25289            None
25290        }
25291    }
25292
25293    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
25294        let digit_count = self.widest_line_number().ilog10() + 1;
25295        column_pixels(style, digit_count as usize, window)
25296    }
25297}
25298
25299pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
25300    let font_size = style.text.font_size.to_pixels(window.rem_size());
25301    let layout = window.text_system().shape_line(
25302        SharedString::from(" ".repeat(column)),
25303        font_size,
25304        &[TextRun {
25305            len: column,
25306            font: style.text.font(),
25307            color: Hsla::default(),
25308            ..Default::default()
25309        }],
25310        None,
25311    );
25312
25313    layout.width
25314}
25315
25316impl Deref for EditorSnapshot {
25317    type Target = DisplaySnapshot;
25318
25319    fn deref(&self) -> &Self::Target {
25320        &self.display_snapshot
25321    }
25322}
25323
25324#[derive(Clone, Debug, PartialEq, Eq)]
25325pub enum EditorEvent {
25326    InputIgnored {
25327        text: Arc<str>,
25328    },
25329    InputHandled {
25330        utf16_range_to_replace: Option<Range<isize>>,
25331        text: Arc<str>,
25332    },
25333    ExcerptsAdded {
25334        buffer: Entity<Buffer>,
25335        predecessor: ExcerptId,
25336        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
25337    },
25338    ExcerptsRemoved {
25339        ids: Vec<ExcerptId>,
25340        removed_buffer_ids: Vec<BufferId>,
25341    },
25342    BufferFoldToggled {
25343        ids: Vec<ExcerptId>,
25344        folded: bool,
25345    },
25346    ExcerptsEdited {
25347        ids: Vec<ExcerptId>,
25348    },
25349    ExcerptsExpanded {
25350        ids: Vec<ExcerptId>,
25351    },
25352    BufferEdited,
25353    Edited {
25354        transaction_id: clock::Lamport,
25355    },
25356    Reparsed(BufferId),
25357    Focused,
25358    FocusedIn,
25359    Blurred,
25360    DirtyChanged,
25361    Saved,
25362    TitleChanged,
25363    SelectionsChanged {
25364        local: bool,
25365    },
25366    ScrollPositionChanged {
25367        local: bool,
25368        autoscroll: bool,
25369    },
25370    TransactionUndone {
25371        transaction_id: clock::Lamport,
25372    },
25373    TransactionBegun {
25374        transaction_id: clock::Lamport,
25375    },
25376    CursorShapeChanged,
25377    BreadcrumbsChanged,
25378    PushedToNavHistory {
25379        anchor: Anchor,
25380        is_deactivate: bool,
25381    },
25382}
25383
25384impl EventEmitter<EditorEvent> for Editor {}
25385
25386impl Focusable for Editor {
25387    fn focus_handle(&self, _cx: &App) -> FocusHandle {
25388        self.focus_handle.clone()
25389    }
25390}
25391
25392impl Render for Editor {
25393    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25394        EditorElement::new(&cx.entity(), self.create_style(cx))
25395    }
25396}
25397
25398impl EntityInputHandler for Editor {
25399    fn text_for_range(
25400        &mut self,
25401        range_utf16: Range<usize>,
25402        adjusted_range: &mut Option<Range<usize>>,
25403        _: &mut Window,
25404        cx: &mut Context<Self>,
25405    ) -> Option<String> {
25406        let snapshot = self.buffer.read(cx).read(cx);
25407        let start = snapshot.clip_offset_utf16(
25408            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
25409            Bias::Left,
25410        );
25411        let end = snapshot.clip_offset_utf16(
25412            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
25413            Bias::Right,
25414        );
25415        if (start.0.0..end.0.0) != range_utf16 {
25416            adjusted_range.replace(start.0.0..end.0.0);
25417        }
25418        Some(snapshot.text_for_range(start..end).collect())
25419    }
25420
25421    fn selected_text_range(
25422        &mut self,
25423        ignore_disabled_input: bool,
25424        _: &mut Window,
25425        cx: &mut Context<Self>,
25426    ) -> Option<UTF16Selection> {
25427        // Prevent the IME menu from appearing when holding down an alphabetic key
25428        // while input is disabled.
25429        if !ignore_disabled_input && !self.input_enabled {
25430            return None;
25431        }
25432
25433        let selection = self
25434            .selections
25435            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25436        let range = selection.range();
25437
25438        Some(UTF16Selection {
25439            range: range.start.0.0..range.end.0.0,
25440            reversed: selection.reversed,
25441        })
25442    }
25443
25444    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
25445        let snapshot = self.buffer.read(cx).read(cx);
25446        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
25447        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
25448    }
25449
25450    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25451        self.clear_highlights::<InputComposition>(cx);
25452        self.ime_transaction.take();
25453    }
25454
25455    fn replace_text_in_range(
25456        &mut self,
25457        range_utf16: Option<Range<usize>>,
25458        text: &str,
25459        window: &mut Window,
25460        cx: &mut Context<Self>,
25461    ) {
25462        if !self.input_enabled {
25463            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25464            return;
25465        }
25466
25467        self.transact(window, cx, |this, window, cx| {
25468            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
25469                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25470                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25471                Some(this.selection_replacement_ranges(range_utf16, cx))
25472            } else {
25473                this.marked_text_ranges(cx)
25474            };
25475
25476            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
25477                let newest_selection_id = this.selections.newest_anchor().id;
25478                this.selections
25479                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25480                    .iter()
25481                    .zip(ranges_to_replace.iter())
25482                    .find_map(|(selection, range)| {
25483                        if selection.id == newest_selection_id {
25484                            Some(
25485                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25486                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25487                            )
25488                        } else {
25489                            None
25490                        }
25491                    })
25492            });
25493
25494            cx.emit(EditorEvent::InputHandled {
25495                utf16_range_to_replace: range_to_replace,
25496                text: text.into(),
25497            });
25498
25499            if let Some(new_selected_ranges) = new_selected_ranges {
25500                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25501                    selections.select_ranges(new_selected_ranges)
25502                });
25503                this.backspace(&Default::default(), window, cx);
25504            }
25505
25506            this.handle_input(text, window, cx);
25507        });
25508
25509        if let Some(transaction) = self.ime_transaction {
25510            self.buffer.update(cx, |buffer, cx| {
25511                buffer.group_until_transaction(transaction, cx);
25512            });
25513        }
25514
25515        self.unmark_text(window, cx);
25516    }
25517
25518    fn replace_and_mark_text_in_range(
25519        &mut self,
25520        range_utf16: Option<Range<usize>>,
25521        text: &str,
25522        new_selected_range_utf16: Option<Range<usize>>,
25523        window: &mut Window,
25524        cx: &mut Context<Self>,
25525    ) {
25526        if !self.input_enabled {
25527            return;
25528        }
25529
25530        let transaction = self.transact(window, cx, |this, window, cx| {
25531            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
25532                let snapshot = this.buffer.read(cx).read(cx);
25533                if let Some(relative_range_utf16) = range_utf16.as_ref() {
25534                    for marked_range in &mut marked_ranges {
25535                        marked_range.end = marked_range.start + relative_range_utf16.end;
25536                        marked_range.start += relative_range_utf16.start;
25537                        marked_range.start =
25538                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
25539                        marked_range.end =
25540                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
25541                    }
25542                }
25543                Some(marked_ranges)
25544            } else if let Some(range_utf16) = range_utf16 {
25545                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25546                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25547                Some(this.selection_replacement_ranges(range_utf16, cx))
25548            } else {
25549                None
25550            };
25551
25552            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
25553                let newest_selection_id = this.selections.newest_anchor().id;
25554                this.selections
25555                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25556                    .iter()
25557                    .zip(ranges_to_replace.iter())
25558                    .find_map(|(selection, range)| {
25559                        if selection.id == newest_selection_id {
25560                            Some(
25561                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25562                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25563                            )
25564                        } else {
25565                            None
25566                        }
25567                    })
25568            });
25569
25570            cx.emit(EditorEvent::InputHandled {
25571                utf16_range_to_replace: range_to_replace,
25572                text: text.into(),
25573            });
25574
25575            if let Some(ranges) = ranges_to_replace {
25576                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25577                    s.select_ranges(ranges)
25578                });
25579            }
25580
25581            let marked_ranges = {
25582                let snapshot = this.buffer.read(cx).read(cx);
25583                this.selections
25584                    .disjoint_anchors_arc()
25585                    .iter()
25586                    .map(|selection| {
25587                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
25588                    })
25589                    .collect::<Vec<_>>()
25590            };
25591
25592            if text.is_empty() {
25593                this.unmark_text(window, cx);
25594            } else {
25595                this.highlight_text::<InputComposition>(
25596                    marked_ranges.clone(),
25597                    HighlightStyle {
25598                        underline: Some(UnderlineStyle {
25599                            thickness: px(1.),
25600                            color: None,
25601                            wavy: false,
25602                        }),
25603                        ..Default::default()
25604                    },
25605                    cx,
25606                );
25607            }
25608
25609            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
25610            let use_autoclose = this.use_autoclose;
25611            let use_auto_surround = this.use_auto_surround;
25612            this.set_use_autoclose(false);
25613            this.set_use_auto_surround(false);
25614            this.handle_input(text, window, cx);
25615            this.set_use_autoclose(use_autoclose);
25616            this.set_use_auto_surround(use_auto_surround);
25617
25618            if let Some(new_selected_range) = new_selected_range_utf16 {
25619                let snapshot = this.buffer.read(cx).read(cx);
25620                let new_selected_ranges = marked_ranges
25621                    .into_iter()
25622                    .map(|marked_range| {
25623                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
25624                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
25625                            insertion_start.0 + new_selected_range.start,
25626                        ));
25627                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
25628                            insertion_start.0 + new_selected_range.end,
25629                        ));
25630                        snapshot.clip_offset_utf16(new_start, Bias::Left)
25631                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
25632                    })
25633                    .collect::<Vec<_>>();
25634
25635                drop(snapshot);
25636                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25637                    selections.select_ranges(new_selected_ranges)
25638                });
25639            }
25640        });
25641
25642        self.ime_transaction = self.ime_transaction.or(transaction);
25643        if let Some(transaction) = self.ime_transaction {
25644            self.buffer.update(cx, |buffer, cx| {
25645                buffer.group_until_transaction(transaction, cx);
25646            });
25647        }
25648
25649        if self.text_highlights::<InputComposition>(cx).is_none() {
25650            self.ime_transaction.take();
25651        }
25652    }
25653
25654    fn bounds_for_range(
25655        &mut self,
25656        range_utf16: Range<usize>,
25657        element_bounds: gpui::Bounds<Pixels>,
25658        window: &mut Window,
25659        cx: &mut Context<Self>,
25660    ) -> Option<gpui::Bounds<Pixels>> {
25661        let text_layout_details = self.text_layout_details(window);
25662        let CharacterDimensions {
25663            em_width,
25664            em_advance,
25665            line_height,
25666        } = self.character_dimensions(window);
25667
25668        let snapshot = self.snapshot(window, cx);
25669        let scroll_position = snapshot.scroll_position();
25670        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
25671
25672        let start =
25673            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
25674        let x = Pixels::from(
25675            ScrollOffset::from(
25676                snapshot.x_for_display_point(start, &text_layout_details)
25677                    + self.gutter_dimensions.full_width(),
25678            ) - scroll_left,
25679        );
25680        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
25681
25682        Some(Bounds {
25683            origin: element_bounds.origin + point(x, y),
25684            size: size(em_width, line_height),
25685        })
25686    }
25687
25688    fn character_index_for_point(
25689        &mut self,
25690        point: gpui::Point<Pixels>,
25691        _window: &mut Window,
25692        _cx: &mut Context<Self>,
25693    ) -> Option<usize> {
25694        let position_map = self.last_position_map.as_ref()?;
25695        if !position_map.text_hitbox.contains(&point) {
25696            return None;
25697        }
25698        let display_point = position_map.point_for_position(point).previous_valid;
25699        let anchor = position_map
25700            .snapshot
25701            .display_point_to_anchor(display_point, Bias::Left);
25702        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
25703        Some(utf16_offset.0.0)
25704    }
25705
25706    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
25707        self.input_enabled
25708    }
25709}
25710
25711trait SelectionExt {
25712    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
25713    fn spanned_rows(
25714        &self,
25715        include_end_if_at_line_start: bool,
25716        map: &DisplaySnapshot,
25717    ) -> Range<MultiBufferRow>;
25718}
25719
25720impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
25721    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
25722        let start = self
25723            .start
25724            .to_point(map.buffer_snapshot())
25725            .to_display_point(map);
25726        let end = self
25727            .end
25728            .to_point(map.buffer_snapshot())
25729            .to_display_point(map);
25730        if self.reversed {
25731            end..start
25732        } else {
25733            start..end
25734        }
25735    }
25736
25737    fn spanned_rows(
25738        &self,
25739        include_end_if_at_line_start: bool,
25740        map: &DisplaySnapshot,
25741    ) -> Range<MultiBufferRow> {
25742        let start = self.start.to_point(map.buffer_snapshot());
25743        let mut end = self.end.to_point(map.buffer_snapshot());
25744        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
25745            end.row -= 1;
25746        }
25747
25748        let buffer_start = map.prev_line_boundary(start).0;
25749        let buffer_end = map.next_line_boundary(end).0;
25750        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
25751    }
25752}
25753
25754impl<T: InvalidationRegion> InvalidationStack<T> {
25755    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
25756    where
25757        S: Clone + ToOffset,
25758    {
25759        while let Some(region) = self.last() {
25760            let all_selections_inside_invalidation_ranges =
25761                if selections.len() == region.ranges().len() {
25762                    selections
25763                        .iter()
25764                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
25765                        .all(|(selection, invalidation_range)| {
25766                            let head = selection.head().to_offset(buffer);
25767                            invalidation_range.start <= head && invalidation_range.end >= head
25768                        })
25769                } else {
25770                    false
25771                };
25772
25773            if all_selections_inside_invalidation_ranges {
25774                break;
25775            } else {
25776                self.pop();
25777            }
25778        }
25779    }
25780}
25781
25782impl<T> Default for InvalidationStack<T> {
25783    fn default() -> Self {
25784        Self(Default::default())
25785    }
25786}
25787
25788impl<T> Deref for InvalidationStack<T> {
25789    type Target = Vec<T>;
25790
25791    fn deref(&self) -> &Self::Target {
25792        &self.0
25793    }
25794}
25795
25796impl<T> DerefMut for InvalidationStack<T> {
25797    fn deref_mut(&mut self) -> &mut Self::Target {
25798        &mut self.0
25799    }
25800}
25801
25802impl InvalidationRegion for SnippetState {
25803    fn ranges(&self) -> &[Range<Anchor>] {
25804        &self.ranges[self.active_index]
25805    }
25806}
25807
25808fn edit_prediction_edit_text(
25809    current_snapshot: &BufferSnapshot,
25810    edits: &[(Range<Anchor>, impl AsRef<str>)],
25811    edit_preview: &EditPreview,
25812    include_deletions: bool,
25813    cx: &App,
25814) -> HighlightedText {
25815    let edits = edits
25816        .iter()
25817        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
25818        .collect::<Vec<_>>();
25819
25820    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
25821}
25822
25823fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
25824    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
25825    // Just show the raw edit text with basic styling
25826    let mut text = String::new();
25827    let mut highlights = Vec::new();
25828
25829    let insertion_highlight_style = HighlightStyle {
25830        color: Some(cx.theme().colors().text),
25831        ..Default::default()
25832    };
25833
25834    for (_, edit_text) in edits {
25835        let start_offset = text.len();
25836        text.push_str(edit_text);
25837        let end_offset = text.len();
25838
25839        if start_offset < end_offset {
25840            highlights.push((start_offset..end_offset, insertion_highlight_style));
25841        }
25842    }
25843
25844    HighlightedText {
25845        text: text.into(),
25846        highlights,
25847    }
25848}
25849
25850pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
25851    match severity {
25852        lsp::DiagnosticSeverity::ERROR => colors.error,
25853        lsp::DiagnosticSeverity::WARNING => colors.warning,
25854        lsp::DiagnosticSeverity::INFORMATION => colors.info,
25855        lsp::DiagnosticSeverity::HINT => colors.info,
25856        _ => colors.ignored,
25857    }
25858}
25859
25860pub fn styled_runs_for_code_label<'a>(
25861    label: &'a CodeLabel,
25862    syntax_theme: &'a theme::SyntaxTheme,
25863    local_player: &'a theme::PlayerColor,
25864) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
25865    let fade_out = HighlightStyle {
25866        fade_out: Some(0.35),
25867        ..Default::default()
25868    };
25869
25870    let mut prev_end = label.filter_range.end;
25871    label
25872        .runs
25873        .iter()
25874        .enumerate()
25875        .flat_map(move |(ix, (range, highlight_id))| {
25876            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
25877                HighlightStyle {
25878                    color: Some(local_player.cursor),
25879                    ..Default::default()
25880                }
25881            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
25882                HighlightStyle {
25883                    background_color: Some(local_player.selection),
25884                    ..Default::default()
25885                }
25886            } else if let Some(style) = highlight_id.style(syntax_theme) {
25887                style
25888            } else {
25889                return Default::default();
25890            };
25891            let muted_style = style.highlight(fade_out);
25892
25893            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
25894            if range.start >= label.filter_range.end {
25895                if range.start > prev_end {
25896                    runs.push((prev_end..range.start, fade_out));
25897                }
25898                runs.push((range.clone(), muted_style));
25899            } else if range.end <= label.filter_range.end {
25900                runs.push((range.clone(), style));
25901            } else {
25902                runs.push((range.start..label.filter_range.end, style));
25903                runs.push((label.filter_range.end..range.end, muted_style));
25904            }
25905            prev_end = cmp::max(prev_end, range.end);
25906
25907            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
25908                runs.push((prev_end..label.text.len(), fade_out));
25909            }
25910
25911            runs
25912        })
25913}
25914
25915pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
25916    let mut prev_index = 0;
25917    let mut prev_codepoint: Option<char> = None;
25918    text.char_indices()
25919        .chain([(text.len(), '\0')])
25920        .filter_map(move |(index, codepoint)| {
25921            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25922            let is_boundary = index == text.len()
25923                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
25924                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
25925            if is_boundary {
25926                let chunk = &text[prev_index..index];
25927                prev_index = index;
25928                Some(chunk)
25929            } else {
25930                None
25931            }
25932        })
25933}
25934
25935/// Given a string of text immediately before the cursor, iterates over possible
25936/// strings a snippet could match to. More precisely: returns an iterator over
25937/// suffixes of `text` created by splitting at word boundaries (before & after
25938/// every non-word character).
25939///
25940/// Shorter suffixes are returned first.
25941pub(crate) fn snippet_candidate_suffixes(
25942    text: &str,
25943    is_word_char: impl Fn(char) -> bool,
25944) -> impl std::iter::Iterator<Item = &str> {
25945    let mut prev_index = text.len();
25946    let mut prev_codepoint = None;
25947    text.char_indices()
25948        .rev()
25949        .chain([(0, '\0')])
25950        .filter_map(move |(index, codepoint)| {
25951            let prev_index = std::mem::replace(&mut prev_index, index);
25952            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25953            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
25954                None
25955            } else {
25956                let chunk = &text[prev_index..]; // go to end of string
25957                Some(chunk)
25958            }
25959        })
25960}
25961
25962pub trait RangeToAnchorExt: Sized {
25963    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25964
25965    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25966        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25967        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25968    }
25969}
25970
25971impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25972    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25973        let start_offset = self.start.to_offset(snapshot);
25974        let end_offset = self.end.to_offset(snapshot);
25975        if start_offset == end_offset {
25976            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25977        } else {
25978            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25979        }
25980    }
25981}
25982
25983pub trait RowExt {
25984    fn as_f64(&self) -> f64;
25985
25986    fn next_row(&self) -> Self;
25987
25988    fn previous_row(&self) -> Self;
25989
25990    fn minus(&self, other: Self) -> u32;
25991}
25992
25993impl RowExt for DisplayRow {
25994    fn as_f64(&self) -> f64 {
25995        self.0 as _
25996    }
25997
25998    fn next_row(&self) -> Self {
25999        Self(self.0 + 1)
26000    }
26001
26002    fn previous_row(&self) -> Self {
26003        Self(self.0.saturating_sub(1))
26004    }
26005
26006    fn minus(&self, other: Self) -> u32 {
26007        self.0 - other.0
26008    }
26009}
26010
26011impl RowExt for MultiBufferRow {
26012    fn as_f64(&self) -> f64 {
26013        self.0 as _
26014    }
26015
26016    fn next_row(&self) -> Self {
26017        Self(self.0 + 1)
26018    }
26019
26020    fn previous_row(&self) -> Self {
26021        Self(self.0.saturating_sub(1))
26022    }
26023
26024    fn minus(&self, other: Self) -> u32 {
26025        self.0 - other.0
26026    }
26027}
26028
26029trait RowRangeExt {
26030    type Row;
26031
26032    fn len(&self) -> usize;
26033
26034    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
26035}
26036
26037impl RowRangeExt for Range<MultiBufferRow> {
26038    type Row = MultiBufferRow;
26039
26040    fn len(&self) -> usize {
26041        (self.end.0 - self.start.0) as usize
26042    }
26043
26044    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
26045        (self.start.0..self.end.0).map(MultiBufferRow)
26046    }
26047}
26048
26049impl RowRangeExt for Range<DisplayRow> {
26050    type Row = DisplayRow;
26051
26052    fn len(&self) -> usize {
26053        (self.end.0 - self.start.0) as usize
26054    }
26055
26056    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
26057        (self.start.0..self.end.0).map(DisplayRow)
26058    }
26059}
26060
26061/// If select range has more than one line, we
26062/// just point the cursor to range.start.
26063fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
26064    if range.start.row == range.end.row {
26065        range
26066    } else {
26067        range.start..range.start
26068    }
26069}
26070pub struct KillRing(ClipboardItem);
26071impl Global for KillRing {}
26072
26073const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
26074
26075enum BreakpointPromptEditAction {
26076    Log,
26077    Condition,
26078    HitCondition,
26079}
26080
26081struct BreakpointPromptEditor {
26082    pub(crate) prompt: Entity<Editor>,
26083    editor: WeakEntity<Editor>,
26084    breakpoint_anchor: Anchor,
26085    breakpoint: Breakpoint,
26086    edit_action: BreakpointPromptEditAction,
26087    block_ids: HashSet<CustomBlockId>,
26088    editor_margins: Arc<Mutex<EditorMargins>>,
26089    _subscriptions: Vec<Subscription>,
26090}
26091
26092impl BreakpointPromptEditor {
26093    const MAX_LINES: u8 = 4;
26094
26095    fn new(
26096        editor: WeakEntity<Editor>,
26097        breakpoint_anchor: Anchor,
26098        breakpoint: Breakpoint,
26099        edit_action: BreakpointPromptEditAction,
26100        window: &mut Window,
26101        cx: &mut Context<Self>,
26102    ) -> Self {
26103        let base_text = match edit_action {
26104            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
26105            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
26106            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
26107        }
26108        .map(|msg| msg.to_string())
26109        .unwrap_or_default();
26110
26111        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
26112        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
26113
26114        let prompt = cx.new(|cx| {
26115            let mut prompt = Editor::new(
26116                EditorMode::AutoHeight {
26117                    min_lines: 1,
26118                    max_lines: Some(Self::MAX_LINES as usize),
26119                },
26120                buffer,
26121                None,
26122                window,
26123                cx,
26124            );
26125            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
26126            prompt.set_show_cursor_when_unfocused(false, cx);
26127            prompt.set_placeholder_text(
26128                match edit_action {
26129                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
26130                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
26131                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
26132                },
26133                window,
26134                cx,
26135            );
26136
26137            prompt
26138        });
26139
26140        Self {
26141            prompt,
26142            editor,
26143            breakpoint_anchor,
26144            breakpoint,
26145            edit_action,
26146            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
26147            block_ids: Default::default(),
26148            _subscriptions: vec![],
26149        }
26150    }
26151
26152    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
26153        self.block_ids.extend(block_ids)
26154    }
26155
26156    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
26157        if let Some(editor) = self.editor.upgrade() {
26158            let message = self
26159                .prompt
26160                .read(cx)
26161                .buffer
26162                .read(cx)
26163                .as_singleton()
26164                .expect("A multi buffer in breakpoint prompt isn't possible")
26165                .read(cx)
26166                .as_rope()
26167                .to_string();
26168
26169            editor.update(cx, |editor, cx| {
26170                editor.edit_breakpoint_at_anchor(
26171                    self.breakpoint_anchor,
26172                    self.breakpoint.clone(),
26173                    match self.edit_action {
26174                        BreakpointPromptEditAction::Log => {
26175                            BreakpointEditAction::EditLogMessage(message.into())
26176                        }
26177                        BreakpointPromptEditAction::Condition => {
26178                            BreakpointEditAction::EditCondition(message.into())
26179                        }
26180                        BreakpointPromptEditAction::HitCondition => {
26181                            BreakpointEditAction::EditHitCondition(message.into())
26182                        }
26183                    },
26184                    cx,
26185                );
26186
26187                editor.remove_blocks(self.block_ids.clone(), None, cx);
26188                cx.focus_self(window);
26189            });
26190        }
26191    }
26192
26193    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
26194        self.editor
26195            .update(cx, |editor, cx| {
26196                editor.remove_blocks(self.block_ids.clone(), None, cx);
26197                window.focus(&editor.focus_handle, cx);
26198            })
26199            .log_err();
26200    }
26201
26202    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
26203        let settings = ThemeSettings::get_global(cx);
26204        let text_style = TextStyle {
26205            color: if self.prompt.read(cx).read_only(cx) {
26206                cx.theme().colors().text_disabled
26207            } else {
26208                cx.theme().colors().text
26209            },
26210            font_family: settings.buffer_font.family.clone(),
26211            font_fallbacks: settings.buffer_font.fallbacks.clone(),
26212            font_size: settings.buffer_font_size(cx).into(),
26213            font_weight: settings.buffer_font.weight,
26214            line_height: relative(settings.buffer_line_height.value()),
26215            ..Default::default()
26216        };
26217        EditorElement::new(
26218            &self.prompt,
26219            EditorStyle {
26220                background: cx.theme().colors().editor_background,
26221                local_player: cx.theme().players().local(),
26222                text: text_style,
26223                ..Default::default()
26224            },
26225        )
26226    }
26227}
26228
26229impl Render for BreakpointPromptEditor {
26230    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26231        let editor_margins = *self.editor_margins.lock();
26232        let gutter_dimensions = editor_margins.gutter;
26233        h_flex()
26234            .key_context("Editor")
26235            .bg(cx.theme().colors().editor_background)
26236            .border_y_1()
26237            .border_color(cx.theme().status().info_border)
26238            .size_full()
26239            .py(window.line_height() / 2.5)
26240            .on_action(cx.listener(Self::confirm))
26241            .on_action(cx.listener(Self::cancel))
26242            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
26243            .child(div().flex_1().child(self.render_prompt_editor(cx)))
26244    }
26245}
26246
26247impl Focusable for BreakpointPromptEditor {
26248    fn focus_handle(&self, cx: &App) -> FocusHandle {
26249        self.prompt.focus_handle(cx)
26250    }
26251}
26252
26253fn all_edits_insertions_or_deletions(
26254    edits: &Vec<(Range<Anchor>, Arc<str>)>,
26255    snapshot: &MultiBufferSnapshot,
26256) -> bool {
26257    let mut all_insertions = true;
26258    let mut all_deletions = true;
26259
26260    for (range, new_text) in edits.iter() {
26261        let range_is_empty = range.to_offset(snapshot).is_empty();
26262        let text_is_empty = new_text.is_empty();
26263
26264        if range_is_empty != text_is_empty {
26265            if range_is_empty {
26266                all_deletions = false;
26267            } else {
26268                all_insertions = false;
26269            }
26270        } else {
26271            return false;
26272        }
26273
26274        if !all_insertions && !all_deletions {
26275            return false;
26276        }
26277    }
26278    all_insertions || all_deletions
26279}
26280
26281struct MissingEditPredictionKeybindingTooltip;
26282
26283impl Render for MissingEditPredictionKeybindingTooltip {
26284    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26285        ui::tooltip_container(cx, |container, cx| {
26286            container
26287                .flex_shrink_0()
26288                .max_w_80()
26289                .min_h(rems_from_px(124.))
26290                .justify_between()
26291                .child(
26292                    v_flex()
26293                        .flex_1()
26294                        .text_ui_sm(cx)
26295                        .child(Label::new("Conflict with Accept Keybinding"))
26296                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
26297                )
26298                .child(
26299                    h_flex()
26300                        .pb_1()
26301                        .gap_1()
26302                        .items_end()
26303                        .w_full()
26304                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
26305                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
26306                        }))
26307                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
26308                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
26309                        })),
26310                )
26311        })
26312    }
26313}
26314
26315#[derive(Debug, Clone, Copy, PartialEq)]
26316pub struct LineHighlight {
26317    pub background: Background,
26318    pub border: Option<gpui::Hsla>,
26319    pub include_gutter: bool,
26320    pub type_id: Option<TypeId>,
26321}
26322
26323struct LineManipulationResult {
26324    pub new_text: String,
26325    pub line_count_before: usize,
26326    pub line_count_after: usize,
26327}
26328
26329fn render_diff_hunk_controls(
26330    row: u32,
26331    status: &DiffHunkStatus,
26332    hunk_range: Range<Anchor>,
26333    is_created_file: bool,
26334    line_height: Pixels,
26335    editor: &Entity<Editor>,
26336    _window: &mut Window,
26337    cx: &mut App,
26338) -> AnyElement {
26339    h_flex()
26340        .h(line_height)
26341        .mr_1()
26342        .gap_1()
26343        .px_0p5()
26344        .pb_1()
26345        .border_x_1()
26346        .border_b_1()
26347        .border_color(cx.theme().colors().border_variant)
26348        .rounded_b_lg()
26349        .bg(cx.theme().colors().editor_background)
26350        .gap_1()
26351        .block_mouse_except_scroll()
26352        .shadow_md()
26353        .child(if status.has_secondary_hunk() {
26354            Button::new(("stage", row as u64), "Stage")
26355                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26356                .tooltip({
26357                    let focus_handle = editor.focus_handle(cx);
26358                    move |_window, cx| {
26359                        Tooltip::for_action_in(
26360                            "Stage Hunk",
26361                            &::git::ToggleStaged,
26362                            &focus_handle,
26363                            cx,
26364                        )
26365                    }
26366                })
26367                .on_click({
26368                    let editor = editor.clone();
26369                    move |_event, _window, cx| {
26370                        editor.update(cx, |editor, cx| {
26371                            editor.stage_or_unstage_diff_hunks(
26372                                true,
26373                                vec![hunk_range.start..hunk_range.start],
26374                                cx,
26375                            );
26376                        });
26377                    }
26378                })
26379        } else {
26380            Button::new(("unstage", row as u64), "Unstage")
26381                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26382                .tooltip({
26383                    let focus_handle = editor.focus_handle(cx);
26384                    move |_window, cx| {
26385                        Tooltip::for_action_in(
26386                            "Unstage Hunk",
26387                            &::git::ToggleStaged,
26388                            &focus_handle,
26389                            cx,
26390                        )
26391                    }
26392                })
26393                .on_click({
26394                    let editor = editor.clone();
26395                    move |_event, _window, cx| {
26396                        editor.update(cx, |editor, cx| {
26397                            editor.stage_or_unstage_diff_hunks(
26398                                false,
26399                                vec![hunk_range.start..hunk_range.start],
26400                                cx,
26401                            );
26402                        });
26403                    }
26404                })
26405        })
26406        .child(
26407            Button::new(("restore", row as u64), "Restore")
26408                .tooltip({
26409                    let focus_handle = editor.focus_handle(cx);
26410                    move |_window, cx| {
26411                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
26412                    }
26413                })
26414                .on_click({
26415                    let editor = editor.clone();
26416                    move |_event, window, cx| {
26417                        editor.update(cx, |editor, cx| {
26418                            let snapshot = editor.snapshot(window, cx);
26419                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
26420                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
26421                        });
26422                    }
26423                })
26424                .disabled(is_created_file),
26425        )
26426        .when(
26427            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
26428            |el| {
26429                el.child(
26430                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
26431                        .shape(IconButtonShape::Square)
26432                        .icon_size(IconSize::Small)
26433                        // .disabled(!has_multiple_hunks)
26434                        .tooltip({
26435                            let focus_handle = editor.focus_handle(cx);
26436                            move |_window, cx| {
26437                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
26438                            }
26439                        })
26440                        .on_click({
26441                            let editor = editor.clone();
26442                            move |_event, window, cx| {
26443                                editor.update(cx, |editor, cx| {
26444                                    let snapshot = editor.snapshot(window, cx);
26445                                    let position =
26446                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
26447                                    editor.go_to_hunk_before_or_after_position(
26448                                        &snapshot,
26449                                        position,
26450                                        Direction::Next,
26451                                        window,
26452                                        cx,
26453                                    );
26454                                    editor.expand_selected_diff_hunks(cx);
26455                                });
26456                            }
26457                        }),
26458                )
26459                .child(
26460                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
26461                        .shape(IconButtonShape::Square)
26462                        .icon_size(IconSize::Small)
26463                        // .disabled(!has_multiple_hunks)
26464                        .tooltip({
26465                            let focus_handle = editor.focus_handle(cx);
26466                            move |_window, cx| {
26467                                Tooltip::for_action_in(
26468                                    "Previous Hunk",
26469                                    &GoToPreviousHunk,
26470                                    &focus_handle,
26471                                    cx,
26472                                )
26473                            }
26474                        })
26475                        .on_click({
26476                            let editor = editor.clone();
26477                            move |_event, window, cx| {
26478                                editor.update(cx, |editor, cx| {
26479                                    let snapshot = editor.snapshot(window, cx);
26480                                    let point =
26481                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
26482                                    editor.go_to_hunk_before_or_after_position(
26483                                        &snapshot,
26484                                        point,
26485                                        Direction::Prev,
26486                                        window,
26487                                        cx,
26488                                    );
26489                                    editor.expand_selected_diff_hunks(cx);
26490                                });
26491                            }
26492                        }),
26493                )
26494            },
26495        )
26496        .into_any_element()
26497}
26498
26499pub fn multibuffer_context_lines(cx: &App) -> u32 {
26500    EditorSettings::try_get(cx)
26501        .map(|settings| settings.excerpt_context_lines)
26502        .unwrap_or(2)
26503        .min(32)
26504}