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 rpc::{ErrorCode, ErrorExt, proto::PeerId};
  167use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  168use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  169use serde::{Deserialize, Serialize};
  170use settings::{
  171    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  172    update_settings_file,
  173};
  174use smallvec::{SmallVec, smallvec};
  175use snippet::Snippet;
  176use std::{
  177    any::{Any, TypeId},
  178    borrow::Cow,
  179    cell::{OnceCell, RefCell},
  180    cmp::{self, Ordering, Reverse},
  181    collections::hash_map,
  182    iter::{self, Peekable},
  183    mem,
  184    num::NonZeroU32,
  185    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  186    path::{Path, PathBuf},
  187    rc::Rc,
  188    sync::Arc,
  189    time::{Duration, Instant},
  190};
  191use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  192use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  193use theme::{
  194    AccentColors, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  195    observe_buffer_font_size_adjustment,
  196};
  197use ui::{
  198    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  199    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  200};
  201use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  202use workspace::{
  203    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  204    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  205    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  206    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  207    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  208    searchable::SearchEvent,
  209};
  210
  211use crate::{
  212    code_context_menus::CompletionsMenuSource,
  213    editor_settings::MultiCursorModifier,
  214    hover_links::{find_url, find_url_from_range},
  215    inlays::{
  216        InlineValueCache,
  217        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  218    },
  219    scroll::{ScrollOffset, ScrollPixelOffset},
  220    selections_collection::resolve_selections_wrapping_blocks,
  221    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  222};
  223
  224pub const FILE_HEADER_HEIGHT: u32 = 2;
  225pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  226const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  227const MAX_LINE_LEN: usize = 1024;
  228const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  229const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  230pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  231#[doc(hidden)]
  232pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  233pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  234
  235pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  236pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  237pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  238pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  239
  240pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  241pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  242pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  243
  244pub type RenderDiffHunkControlsFn = Arc<
  245    dyn Fn(
  246        u32,
  247        &DiffHunkStatus,
  248        Range<Anchor>,
  249        bool,
  250        Pixels,
  251        &Entity<Editor>,
  252        &mut Window,
  253        &mut App,
  254    ) -> AnyElement,
  255>;
  256
  257enum ReportEditorEvent {
  258    Saved { auto_saved: bool },
  259    EditorOpened,
  260    Closed,
  261}
  262
  263impl ReportEditorEvent {
  264    pub fn event_type(&self) -> &'static str {
  265        match self {
  266            Self::Saved { .. } => "Editor Saved",
  267            Self::EditorOpened => "Editor Opened",
  268            Self::Closed => "Editor Closed",
  269        }
  270    }
  271}
  272
  273pub enum ActiveDebugLine {}
  274pub enum DebugStackFrameLine {}
  275enum DocumentHighlightRead {}
  276enum DocumentHighlightWrite {}
  277enum InputComposition {}
  278pub enum PendingInput {}
  279enum SelectedTextHighlight {}
  280
  281pub enum ConflictsOuter {}
  282pub enum ConflictsOurs {}
  283pub enum ConflictsTheirs {}
  284pub enum ConflictsOursMarker {}
  285pub enum ConflictsTheirsMarker {}
  286
  287pub struct HunkAddedColor;
  288pub struct HunkRemovedColor;
  289
  290#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  291pub enum Navigated {
  292    Yes,
  293    No,
  294}
  295
  296impl Navigated {
  297    pub fn from_bool(yes: bool) -> Navigated {
  298        if yes { Navigated::Yes } else { Navigated::No }
  299    }
  300}
  301
  302#[derive(Debug, Clone, PartialEq, Eq)]
  303enum DisplayDiffHunk {
  304    Folded {
  305        display_row: DisplayRow,
  306    },
  307    Unfolded {
  308        is_created_file: bool,
  309        diff_base_byte_range: Range<usize>,
  310        display_row_range: Range<DisplayRow>,
  311        multi_buffer_range: Range<Anchor>,
  312        status: DiffHunkStatus,
  313        word_diffs: Vec<Range<MultiBufferOffset>>,
  314    },
  315}
  316
  317pub enum HideMouseCursorOrigin {
  318    TypingAction,
  319    MovementAction,
  320}
  321
  322pub fn init(cx: &mut App) {
  323    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  324
  325    workspace::register_project_item::<Editor>(cx);
  326    workspace::FollowableViewRegistry::register::<Editor>(cx);
  327    workspace::register_serializable_item::<Editor>(cx);
  328
  329    cx.observe_new(
  330        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  331            workspace.register_action(Editor::new_file);
  332            workspace.register_action(Editor::new_file_split);
  333            workspace.register_action(Editor::new_file_vertical);
  334            workspace.register_action(Editor::new_file_horizontal);
  335            workspace.register_action(Editor::cancel_language_server_work);
  336            workspace.register_action(Editor::toggle_focus);
  337        },
  338    )
  339    .detach();
  340
  341    cx.on_action(move |_: &workspace::NewFile, cx| {
  342        let app_state = workspace::AppState::global(cx);
  343        if let Some(app_state) = app_state.upgrade() {
  344            workspace::open_new(
  345                Default::default(),
  346                app_state,
  347                cx,
  348                |workspace, window, cx| {
  349                    Editor::new_file(workspace, &Default::default(), window, cx)
  350                },
  351            )
  352            .detach();
  353        }
  354    })
  355    .on_action(move |_: &workspace::NewWindow, cx| {
  356        let app_state = workspace::AppState::global(cx);
  357        if let Some(app_state) = app_state.upgrade() {
  358            workspace::open_new(
  359                Default::default(),
  360                app_state,
  361                cx,
  362                |workspace, window, cx| {
  363                    cx.activate(true);
  364                    Editor::new_file(workspace, &Default::default(), window, cx)
  365                },
  366            )
  367            .detach();
  368        }
  369    });
  370}
  371
  372pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  373    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  374}
  375
  376pub trait DiagnosticRenderer {
  377    fn render_group(
  378        &self,
  379        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  380        buffer_id: BufferId,
  381        snapshot: EditorSnapshot,
  382        editor: WeakEntity<Editor>,
  383        language_registry: Option<Arc<LanguageRegistry>>,
  384        cx: &mut App,
  385    ) -> Vec<BlockProperties<Anchor>>;
  386
  387    fn render_hover(
  388        &self,
  389        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  390        range: Range<Point>,
  391        buffer_id: BufferId,
  392        language_registry: Option<Arc<LanguageRegistry>>,
  393        cx: &mut App,
  394    ) -> Option<Entity<markdown::Markdown>>;
  395
  396    fn open_link(
  397        &self,
  398        editor: &mut Editor,
  399        link: SharedString,
  400        window: &mut Window,
  401        cx: &mut Context<Editor>,
  402    );
  403}
  404
  405pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  406
  407impl GlobalDiagnosticRenderer {
  408    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  409        cx.try_global::<Self>().map(|g| g.0.clone())
  410    }
  411}
  412
  413impl gpui::Global for GlobalDiagnosticRenderer {}
  414pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  415    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  416}
  417
  418pub struct SearchWithinRange;
  419
  420trait InvalidationRegion {
  421    fn ranges(&self) -> &[Range<Anchor>];
  422}
  423
  424#[derive(Clone, Debug, PartialEq)]
  425pub enum SelectPhase {
  426    Begin {
  427        position: DisplayPoint,
  428        add: bool,
  429        click_count: usize,
  430    },
  431    BeginColumnar {
  432        position: DisplayPoint,
  433        reset: bool,
  434        mode: ColumnarMode,
  435        goal_column: u32,
  436    },
  437    Extend {
  438        position: DisplayPoint,
  439        click_count: usize,
  440    },
  441    Update {
  442        position: DisplayPoint,
  443        goal_column: u32,
  444        scroll_delta: gpui::Point<f32>,
  445    },
  446    End,
  447}
  448
  449#[derive(Clone, Debug, PartialEq)]
  450pub enum ColumnarMode {
  451    FromMouse,
  452    FromSelection,
  453}
  454
  455#[derive(Clone, Debug)]
  456pub enum SelectMode {
  457    Character,
  458    Word(Range<Anchor>),
  459    Line(Range<Anchor>),
  460    All,
  461}
  462
  463#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  464pub enum SizingBehavior {
  465    /// The editor will layout itself using `size_full` and will include the vertical
  466    /// scroll margin as requested by user settings.
  467    #[default]
  468    Default,
  469    /// The editor will layout itself using `size_full`, but will not have any
  470    /// vertical overscroll.
  471    ExcludeOverscrollMargin,
  472    /// The editor will request a vertical size according to its content and will be
  473    /// layouted without a vertical scroll margin.
  474    SizeByContent,
  475}
  476
  477#[derive(Clone, PartialEq, Eq, Debug)]
  478pub enum EditorMode {
  479    SingleLine,
  480    AutoHeight {
  481        min_lines: usize,
  482        max_lines: Option<usize>,
  483    },
  484    Full {
  485        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  486        scale_ui_elements_with_buffer_font_size: bool,
  487        /// When set to `true`, the editor will render a background for the active line.
  488        show_active_line_background: bool,
  489        /// Determines the sizing behavior for this editor
  490        sizing_behavior: SizingBehavior,
  491    },
  492    Minimap {
  493        parent: WeakEntity<Editor>,
  494    },
  495}
  496
  497impl EditorMode {
  498    pub fn full() -> Self {
  499        Self::Full {
  500            scale_ui_elements_with_buffer_font_size: true,
  501            show_active_line_background: true,
  502            sizing_behavior: SizingBehavior::Default,
  503        }
  504    }
  505
  506    #[inline]
  507    pub fn is_full(&self) -> bool {
  508        matches!(self, Self::Full { .. })
  509    }
  510
  511    #[inline]
  512    pub fn is_single_line(&self) -> bool {
  513        matches!(self, Self::SingleLine { .. })
  514    }
  515
  516    #[inline]
  517    fn is_minimap(&self) -> bool {
  518        matches!(self, Self::Minimap { .. })
  519    }
  520}
  521
  522#[derive(Copy, Clone, Debug)]
  523pub enum SoftWrap {
  524    /// Prefer not to wrap at all.
  525    ///
  526    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  527    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  528    GitDiff,
  529    /// Prefer a single line generally, unless an overly long line is encountered.
  530    None,
  531    /// Soft wrap lines that exceed the editor width.
  532    EditorWidth,
  533    /// Soft wrap lines at the preferred line length.
  534    Column(u32),
  535    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  536    Bounded(u32),
  537}
  538
  539#[derive(Clone)]
  540pub struct EditorStyle {
  541    pub background: Hsla,
  542    pub border: Hsla,
  543    pub local_player: PlayerColor,
  544    pub text: TextStyle,
  545    pub scrollbar_width: Pixels,
  546    pub syntax: Arc<SyntaxTheme>,
  547    pub status: StatusColors,
  548    pub inlay_hints_style: HighlightStyle,
  549    pub edit_prediction_styles: EditPredictionStyles,
  550    pub unnecessary_code_fade: f32,
  551    pub show_underlines: bool,
  552}
  553
  554impl Default for EditorStyle {
  555    fn default() -> Self {
  556        Self {
  557            background: Hsla::default(),
  558            border: Hsla::default(),
  559            local_player: PlayerColor::default(),
  560            text: TextStyle::default(),
  561            scrollbar_width: Pixels::default(),
  562            syntax: Default::default(),
  563            // HACK: Status colors don't have a real default.
  564            // We should look into removing the status colors from the editor
  565            // style and retrieve them directly from the theme.
  566            status: StatusColors::dark(),
  567            inlay_hints_style: HighlightStyle::default(),
  568            edit_prediction_styles: EditPredictionStyles {
  569                insertion: HighlightStyle::default(),
  570                whitespace: HighlightStyle::default(),
  571            },
  572            unnecessary_code_fade: Default::default(),
  573            show_underlines: true,
  574        }
  575    }
  576}
  577
  578pub fn make_inlay_hints_style(cx: &App) -> HighlightStyle {
  579    let show_background = language_settings::language_settings(None, None, cx)
  580        .inlay_hints
  581        .show_background;
  582
  583    let mut style = cx.theme().syntax().get("hint");
  584
  585    if style.color.is_none() {
  586        style.color = Some(cx.theme().status().hint);
  587    }
  588
  589    if !show_background {
  590        style.background_color = None;
  591        return style;
  592    }
  593
  594    if style.background_color.is_none() {
  595        style.background_color = Some(cx.theme().status().hint_background);
  596    }
  597
  598    style
  599}
  600
  601pub fn make_suggestion_styles(cx: &App) -> EditPredictionStyles {
  602    EditPredictionStyles {
  603        insertion: HighlightStyle {
  604            color: Some(cx.theme().status().predictive),
  605            ..HighlightStyle::default()
  606        },
  607        whitespace: HighlightStyle {
  608            background_color: Some(cx.theme().status().created_background),
  609            ..HighlightStyle::default()
  610        },
  611    }
  612}
  613
  614type CompletionId = usize;
  615
  616pub(crate) enum EditDisplayMode {
  617    TabAccept,
  618    DiffPopover,
  619    Inline,
  620}
  621
  622enum EditPrediction {
  623    Edit {
  624        edits: Vec<(Range<Anchor>, Arc<str>)>,
  625        edit_preview: Option<EditPreview>,
  626        display_mode: EditDisplayMode,
  627        snapshot: BufferSnapshot,
  628    },
  629    /// Move to a specific location in the active editor
  630    MoveWithin {
  631        target: Anchor,
  632        snapshot: BufferSnapshot,
  633    },
  634    /// Move to a specific location in a different editor (not the active one)
  635    MoveOutside {
  636        target: language::Anchor,
  637        snapshot: BufferSnapshot,
  638    },
  639}
  640
  641struct EditPredictionState {
  642    inlay_ids: Vec<InlayId>,
  643    completion: EditPrediction,
  644    completion_id: Option<SharedString>,
  645    invalidation_range: Option<Range<Anchor>>,
  646}
  647
  648enum EditPredictionSettings {
  649    Disabled,
  650    Enabled {
  651        show_in_menu: bool,
  652        preview_requires_modifier: bool,
  653    },
  654}
  655
  656enum EditPredictionHighlight {}
  657
  658#[derive(Debug, Clone)]
  659struct InlineDiagnostic {
  660    message: SharedString,
  661    group_id: usize,
  662    is_primary: bool,
  663    start: Point,
  664    severity: lsp::DiagnosticSeverity,
  665}
  666
  667pub enum MenuEditPredictionsPolicy {
  668    Never,
  669    ByProvider,
  670}
  671
  672pub enum EditPredictionPreview {
  673    /// Modifier is not pressed
  674    Inactive { released_too_fast: bool },
  675    /// Modifier pressed
  676    Active {
  677        since: Instant,
  678        previous_scroll_position: Option<ScrollAnchor>,
  679    },
  680}
  681
  682impl EditPredictionPreview {
  683    pub fn released_too_fast(&self) -> bool {
  684        match self {
  685            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  686            EditPredictionPreview::Active { .. } => false,
  687        }
  688    }
  689
  690    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  691        if let EditPredictionPreview::Active {
  692            previous_scroll_position,
  693            ..
  694        } = self
  695        {
  696            *previous_scroll_position = scroll_position;
  697        }
  698    }
  699}
  700
  701pub struct ContextMenuOptions {
  702    pub min_entries_visible: usize,
  703    pub max_entries_visible: usize,
  704    pub placement: Option<ContextMenuPlacement>,
  705}
  706
  707#[derive(Debug, Clone, PartialEq, Eq)]
  708pub enum ContextMenuPlacement {
  709    Above,
  710    Below,
  711}
  712
  713#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  714struct EditorActionId(usize);
  715
  716impl EditorActionId {
  717    pub fn post_inc(&mut self) -> Self {
  718        let answer = self.0;
  719
  720        *self = Self(answer + 1);
  721
  722        Self(answer)
  723    }
  724}
  725
  726// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  727// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  728
  729type BackgroundHighlight = (
  730    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  731    Arc<[Range<Anchor>]>,
  732);
  733type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  734
  735#[derive(Default)]
  736struct ScrollbarMarkerState {
  737    scrollbar_size: Size<Pixels>,
  738    dirty: bool,
  739    markers: Arc<[PaintQuad]>,
  740    pending_refresh: Option<Task<Result<()>>>,
  741}
  742
  743impl ScrollbarMarkerState {
  744    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  745        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  746    }
  747}
  748
  749#[derive(Clone, Copy, PartialEq, Eq)]
  750pub enum MinimapVisibility {
  751    Disabled,
  752    Enabled {
  753        /// The configuration currently present in the users settings.
  754        setting_configuration: bool,
  755        /// Whether to override the currently set visibility from the users setting.
  756        toggle_override: bool,
  757    },
  758}
  759
  760impl MinimapVisibility {
  761    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  762        if mode.is_full() {
  763            Self::Enabled {
  764                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  765                toggle_override: false,
  766            }
  767        } else {
  768            Self::Disabled
  769        }
  770    }
  771
  772    fn hidden(&self) -> Self {
  773        match *self {
  774            Self::Enabled {
  775                setting_configuration,
  776                ..
  777            } => Self::Enabled {
  778                setting_configuration,
  779                toggle_override: setting_configuration,
  780            },
  781            Self::Disabled => Self::Disabled,
  782        }
  783    }
  784
  785    fn disabled(&self) -> bool {
  786        matches!(*self, Self::Disabled)
  787    }
  788
  789    fn settings_visibility(&self) -> bool {
  790        match *self {
  791            Self::Enabled {
  792                setting_configuration,
  793                ..
  794            } => setting_configuration,
  795            _ => false,
  796        }
  797    }
  798
  799    fn visible(&self) -> bool {
  800        match *self {
  801            Self::Enabled {
  802                setting_configuration,
  803                toggle_override,
  804            } => setting_configuration ^ toggle_override,
  805            _ => false,
  806        }
  807    }
  808
  809    fn toggle_visibility(&self) -> Self {
  810        match *self {
  811            Self::Enabled {
  812                toggle_override,
  813                setting_configuration,
  814            } => Self::Enabled {
  815                setting_configuration,
  816                toggle_override: !toggle_override,
  817            },
  818            Self::Disabled => Self::Disabled,
  819        }
  820    }
  821}
  822
  823#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  824pub enum BufferSerialization {
  825    All,
  826    NonDirtyBuffers,
  827}
  828
  829impl BufferSerialization {
  830    fn new(restore_unsaved_buffers: bool) -> Self {
  831        if restore_unsaved_buffers {
  832            Self::All
  833        } else {
  834            Self::NonDirtyBuffers
  835        }
  836    }
  837}
  838
  839#[derive(Clone, Debug)]
  840struct RunnableTasks {
  841    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  842    offset: multi_buffer::Anchor,
  843    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  844    column: u32,
  845    // Values of all named captures, including those starting with '_'
  846    extra_variables: HashMap<String, String>,
  847    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  848    context_range: Range<BufferOffset>,
  849}
  850
  851impl RunnableTasks {
  852    fn resolve<'a>(
  853        &'a self,
  854        cx: &'a task::TaskContext,
  855    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  856        self.templates.iter().filter_map(|(kind, template)| {
  857            template
  858                .resolve_task(&kind.to_id_base(), cx)
  859                .map(|task| (kind.clone(), task))
  860        })
  861    }
  862}
  863
  864#[derive(Clone)]
  865pub struct ResolvedTasks {
  866    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  867    position: Anchor,
  868}
  869
  870/// Addons allow storing per-editor state in other crates (e.g. Vim)
  871pub trait Addon: 'static {
  872    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  873
  874    fn render_buffer_header_controls(
  875        &self,
  876        _: &ExcerptInfo,
  877        _: &Window,
  878        _: &App,
  879    ) -> Option<AnyElement> {
  880        None
  881    }
  882
  883    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  884        None
  885    }
  886
  887    fn to_any(&self) -> &dyn std::any::Any;
  888
  889    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  890        None
  891    }
  892}
  893
  894struct ChangeLocation {
  895    current: Option<Vec<Anchor>>,
  896    original: Vec<Anchor>,
  897}
  898impl ChangeLocation {
  899    fn locations(&self) -> &[Anchor] {
  900        self.current.as_ref().unwrap_or(&self.original)
  901    }
  902}
  903
  904/// A set of caret positions, registered when the editor was edited.
  905pub struct ChangeList {
  906    changes: Vec<ChangeLocation>,
  907    /// Currently "selected" change.
  908    position: Option<usize>,
  909}
  910
  911impl ChangeList {
  912    pub fn new() -> Self {
  913        Self {
  914            changes: Vec::new(),
  915            position: None,
  916        }
  917    }
  918
  919    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  920    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  921    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  922        if self.changes.is_empty() {
  923            return None;
  924        }
  925
  926        let prev = self.position.unwrap_or(self.changes.len());
  927        let next = if direction == Direction::Prev {
  928            prev.saturating_sub(count)
  929        } else {
  930            (prev + count).min(self.changes.len() - 1)
  931        };
  932        self.position = Some(next);
  933        self.changes.get(next).map(|change| change.locations())
  934    }
  935
  936    /// Adds a new change to the list, resetting the change list position.
  937    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  938        self.position.take();
  939        if let Some(last) = self.changes.last_mut()
  940            && group
  941        {
  942            last.current = Some(new_positions)
  943        } else {
  944            self.changes.push(ChangeLocation {
  945                original: new_positions,
  946                current: None,
  947            });
  948        }
  949    }
  950
  951    pub fn last(&self) -> Option<&[Anchor]> {
  952        self.changes.last().map(|change| change.locations())
  953    }
  954
  955    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  956        self.changes.last().map(|change| change.original.as_slice())
  957    }
  958
  959    pub fn invert_last_group(&mut self) {
  960        if let Some(last) = self.changes.last_mut()
  961            && let Some(current) = last.current.as_mut()
  962        {
  963            mem::swap(&mut last.original, current);
  964        }
  965    }
  966}
  967
  968#[derive(Clone)]
  969struct InlineBlamePopoverState {
  970    scroll_handle: ScrollHandle,
  971    commit_message: Option<ParsedCommitMessage>,
  972    markdown: Entity<Markdown>,
  973}
  974
  975struct InlineBlamePopover {
  976    position: gpui::Point<Pixels>,
  977    hide_task: Option<Task<()>>,
  978    popover_bounds: Option<Bounds<Pixels>>,
  979    popover_state: InlineBlamePopoverState,
  980    keyboard_grace: bool,
  981}
  982
  983enum SelectionDragState {
  984    /// State when no drag related activity is detected.
  985    None,
  986    /// State when the mouse is down on a selection that is about to be dragged.
  987    ReadyToDrag {
  988        selection: Selection<Anchor>,
  989        click_position: gpui::Point<Pixels>,
  990        mouse_down_time: Instant,
  991    },
  992    /// State when the mouse is dragging the selection in the editor.
  993    Dragging {
  994        selection: Selection<Anchor>,
  995        drop_cursor: Selection<Anchor>,
  996        hide_drop_cursor: bool,
  997    },
  998}
  999
 1000enum ColumnarSelectionState {
 1001    FromMouse {
 1002        selection_tail: Anchor,
 1003        display_point: Option<DisplayPoint>,
 1004    },
 1005    FromSelection {
 1006        selection_tail: Anchor,
 1007    },
 1008}
 1009
 1010/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1011/// a breakpoint on them.
 1012#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1013struct PhantomBreakpointIndicator {
 1014    display_row: DisplayRow,
 1015    /// There's a small debounce between hovering over the line and showing the indicator.
 1016    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1017    is_active: bool,
 1018    collides_with_existing_breakpoint: bool,
 1019}
 1020
 1021/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1022///
 1023/// See the [module level documentation](self) for more information.
 1024pub struct Editor {
 1025    focus_handle: FocusHandle,
 1026    last_focused_descendant: Option<WeakFocusHandle>,
 1027    /// The text buffer being edited
 1028    buffer: Entity<MultiBuffer>,
 1029    /// Map of how text in the buffer should be displayed.
 1030    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1031    pub display_map: Entity<DisplayMap>,
 1032    placeholder_display_map: Option<Entity<DisplayMap>>,
 1033    pub selections: SelectionsCollection,
 1034    pub scroll_manager: ScrollManager,
 1035    /// When inline assist editors are linked, they all render cursors because
 1036    /// typing enters text into each of them, even the ones that aren't focused.
 1037    pub(crate) show_cursor_when_unfocused: bool,
 1038    columnar_selection_state: Option<ColumnarSelectionState>,
 1039    add_selections_state: Option<AddSelectionsState>,
 1040    select_next_state: Option<SelectNextState>,
 1041    select_prev_state: Option<SelectNextState>,
 1042    selection_history: SelectionHistory,
 1043    defer_selection_effects: bool,
 1044    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1045    autoclose_regions: Vec<AutocloseRegion>,
 1046    snippet_stack: InvalidationStack<SnippetState>,
 1047    select_syntax_node_history: SelectSyntaxNodeHistory,
 1048    ime_transaction: Option<TransactionId>,
 1049    pub diagnostics_max_severity: DiagnosticSeverity,
 1050    active_diagnostics: ActiveDiagnostic,
 1051    show_inline_diagnostics: bool,
 1052    inline_diagnostics_update: Task<()>,
 1053    inline_diagnostics_enabled: bool,
 1054    diagnostics_enabled: bool,
 1055    word_completions_enabled: bool,
 1056    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1057    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1058    hard_wrap: Option<usize>,
 1059    project: Option<Entity<Project>>,
 1060    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1061    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1062    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1063    blink_manager: Entity<BlinkManager>,
 1064    show_cursor_names: bool,
 1065    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1066    pub show_local_selections: bool,
 1067    mode: EditorMode,
 1068    show_breadcrumbs: bool,
 1069    show_gutter: bool,
 1070    show_scrollbars: ScrollbarAxes,
 1071    minimap_visibility: MinimapVisibility,
 1072    offset_content: bool,
 1073    disable_expand_excerpt_buttons: bool,
 1074    show_line_numbers: Option<bool>,
 1075    use_relative_line_numbers: Option<bool>,
 1076    show_git_diff_gutter: Option<bool>,
 1077    show_code_actions: Option<bool>,
 1078    show_runnables: Option<bool>,
 1079    show_breakpoints: Option<bool>,
 1080    show_wrap_guides: Option<bool>,
 1081    show_indent_guides: Option<bool>,
 1082    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1083    highlight_order: usize,
 1084    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1085    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1086    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1087    scrollbar_marker_state: ScrollbarMarkerState,
 1088    active_indent_guides_state: ActiveIndentGuidesState,
 1089    nav_history: Option<ItemNavHistory>,
 1090    context_menu: RefCell<Option<CodeContextMenu>>,
 1091    context_menu_options: Option<ContextMenuOptions>,
 1092    mouse_context_menu: Option<MouseContextMenu>,
 1093    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1094    inline_blame_popover: Option<InlineBlamePopover>,
 1095    inline_blame_popover_show_task: Option<Task<()>>,
 1096    signature_help_state: SignatureHelpState,
 1097    auto_signature_help: Option<bool>,
 1098    find_all_references_task_sources: Vec<Anchor>,
 1099    next_completion_id: CompletionId,
 1100    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1101    code_actions_task: Option<Task<Result<()>>>,
 1102    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1103    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1104    document_highlights_task: Option<Task<()>>,
 1105    linked_editing_range_task: Option<Task<Option<()>>>,
 1106    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1107    pending_rename: Option<RenameState>,
 1108    searchable: bool,
 1109    cursor_shape: CursorShape,
 1110    /// Whether the cursor is offset one character to the left when something is
 1111    /// selected (needed for vim visual mode)
 1112    cursor_offset_on_selection: bool,
 1113    current_line_highlight: Option<CurrentLineHighlight>,
 1114    pub collapse_matches: bool,
 1115    autoindent_mode: Option<AutoindentMode>,
 1116    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1117    input_enabled: bool,
 1118    use_modal_editing: bool,
 1119    read_only: bool,
 1120    leader_id: Option<CollaboratorId>,
 1121    remote_id: Option<ViewId>,
 1122    pub hover_state: HoverState,
 1123    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1124    prev_pressure_stage: Option<PressureStage>,
 1125    gutter_hovered: bool,
 1126    hovered_link_state: Option<HoveredLinkState>,
 1127    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1128    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1129    active_edit_prediction: Option<EditPredictionState>,
 1130    /// Used to prevent flickering as the user types while the menu is open
 1131    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1132    edit_prediction_settings: EditPredictionSettings,
 1133    edit_predictions_hidden_for_vim_mode: bool,
 1134    show_edit_predictions_override: Option<bool>,
 1135    show_completions_on_input_override: Option<bool>,
 1136    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1137    edit_prediction_preview: EditPredictionPreview,
 1138    edit_prediction_indent_conflict: bool,
 1139    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1140    next_inlay_id: usize,
 1141    next_color_inlay_id: usize,
 1142    _subscriptions: Vec<Subscription>,
 1143    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1144    gutter_dimensions: GutterDimensions,
 1145    style: Option<EditorStyle>,
 1146    text_style_refinement: Option<TextStyleRefinement>,
 1147    next_editor_action_id: EditorActionId,
 1148    editor_actions: Rc<
 1149        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1150    >,
 1151    use_autoclose: bool,
 1152    use_auto_surround: bool,
 1153    auto_replace_emoji_shortcode: bool,
 1154    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1155    show_git_blame_gutter: bool,
 1156    show_git_blame_inline: bool,
 1157    show_git_blame_inline_delay_task: Option<Task<()>>,
 1158    git_blame_inline_enabled: bool,
 1159    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1160    buffer_serialization: Option<BufferSerialization>,
 1161    show_selection_menu: Option<bool>,
 1162    blame: Option<Entity<GitBlame>>,
 1163    blame_subscription: Option<Subscription>,
 1164    custom_context_menu: Option<
 1165        Box<
 1166            dyn 'static
 1167                + Fn(
 1168                    &mut Self,
 1169                    DisplayPoint,
 1170                    &mut Window,
 1171                    &mut Context<Self>,
 1172                ) -> Option<Entity<ui::ContextMenu>>,
 1173        >,
 1174    >,
 1175    last_bounds: Option<Bounds<Pixels>>,
 1176    last_position_map: Option<Rc<PositionMap>>,
 1177    expect_bounds_change: Option<Bounds<Pixels>>,
 1178    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1179    tasks_update_task: Option<Task<()>>,
 1180    breakpoint_store: Option<Entity<BreakpointStore>>,
 1181    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1182    hovered_diff_hunk_row: Option<DisplayRow>,
 1183    pull_diagnostics_task: Task<()>,
 1184    pull_diagnostics_background_task: Task<()>,
 1185    in_project_search: bool,
 1186    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1187    breadcrumb_header: Option<String>,
 1188    focused_block: Option<FocusedBlock>,
 1189    next_scroll_position: NextScrollCursorCenterTopBottom,
 1190    addons: HashMap<TypeId, Box<dyn Addon>>,
 1191    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1192    load_diff_task: Option<Shared<Task<()>>>,
 1193    /// Whether we are temporarily displaying a diff other than git's
 1194    temporary_diff_override: bool,
 1195    selection_mark_mode: bool,
 1196    toggle_fold_multiple_buffers: Task<()>,
 1197    _scroll_cursor_center_top_bottom_task: Task<()>,
 1198    serialize_selections: Task<()>,
 1199    serialize_folds: Task<()>,
 1200    mouse_cursor_hidden: bool,
 1201    minimap: Option<Entity<Self>>,
 1202    hide_mouse_mode: HideMouseMode,
 1203    pub change_list: ChangeList,
 1204    inline_value_cache: InlineValueCache,
 1205
 1206    selection_drag_state: SelectionDragState,
 1207    colors: Option<LspColorData>,
 1208    post_scroll_update: Task<()>,
 1209    refresh_colors_task: Task<()>,
 1210    inlay_hints: Option<LspInlayHintData>,
 1211    folding_newlines: Task<()>,
 1212    select_next_is_case_sensitive: Option<bool>,
 1213    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1214    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1215    accent_data: Option<AccentData>,
 1216    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1217    use_base_text_line_numbers: bool,
 1218}
 1219
 1220#[derive(Debug, PartialEq)]
 1221struct AccentData {
 1222    colors: AccentColors,
 1223    overrides: Vec<SharedString>,
 1224}
 1225
 1226fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1227    if debounce_ms > 0 {
 1228        Some(Duration::from_millis(debounce_ms))
 1229    } else {
 1230        None
 1231    }
 1232}
 1233
 1234#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1235enum NextScrollCursorCenterTopBottom {
 1236    #[default]
 1237    Center,
 1238    Top,
 1239    Bottom,
 1240}
 1241
 1242impl NextScrollCursorCenterTopBottom {
 1243    fn next(&self) -> Self {
 1244        match self {
 1245            Self::Center => Self::Top,
 1246            Self::Top => Self::Bottom,
 1247            Self::Bottom => Self::Center,
 1248        }
 1249    }
 1250}
 1251
 1252#[derive(Clone)]
 1253pub struct EditorSnapshot {
 1254    pub mode: EditorMode,
 1255    show_gutter: bool,
 1256    offset_content: bool,
 1257    show_line_numbers: Option<bool>,
 1258    show_git_diff_gutter: Option<bool>,
 1259    show_code_actions: Option<bool>,
 1260    show_runnables: Option<bool>,
 1261    show_breakpoints: Option<bool>,
 1262    git_blame_gutter_max_author_length: Option<usize>,
 1263    pub display_snapshot: DisplaySnapshot,
 1264    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1265    is_focused: bool,
 1266    scroll_anchor: ScrollAnchor,
 1267    ongoing_scroll: OngoingScroll,
 1268    current_line_highlight: CurrentLineHighlight,
 1269    gutter_hovered: bool,
 1270}
 1271
 1272#[derive(Default, Debug, Clone, Copy)]
 1273pub struct GutterDimensions {
 1274    pub left_padding: Pixels,
 1275    pub right_padding: Pixels,
 1276    pub width: Pixels,
 1277    pub margin: Pixels,
 1278    pub git_blame_entries_width: Option<Pixels>,
 1279}
 1280
 1281impl GutterDimensions {
 1282    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1283        Self {
 1284            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1285            ..Default::default()
 1286        }
 1287    }
 1288
 1289    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1290        -cx.text_system().descent(font_id, font_size)
 1291    }
 1292    /// The full width of the space taken up by the gutter.
 1293    pub fn full_width(&self) -> Pixels {
 1294        self.margin + self.width
 1295    }
 1296
 1297    /// The width of the space reserved for the fold indicators,
 1298    /// use alongside 'justify_end' and `gutter_width` to
 1299    /// right align content with the line numbers
 1300    pub fn fold_area_width(&self) -> Pixels {
 1301        self.margin + self.right_padding
 1302    }
 1303}
 1304
 1305struct CharacterDimensions {
 1306    em_width: Pixels,
 1307    em_advance: Pixels,
 1308    line_height: Pixels,
 1309}
 1310
 1311#[derive(Debug)]
 1312pub struct RemoteSelection {
 1313    pub replica_id: ReplicaId,
 1314    pub selection: Selection<Anchor>,
 1315    pub cursor_shape: CursorShape,
 1316    pub collaborator_id: CollaboratorId,
 1317    pub line_mode: bool,
 1318    pub user_name: Option<SharedString>,
 1319    pub color: PlayerColor,
 1320}
 1321
 1322#[derive(Clone, Debug)]
 1323struct SelectionHistoryEntry {
 1324    selections: Arc<[Selection<Anchor>]>,
 1325    select_next_state: Option<SelectNextState>,
 1326    select_prev_state: Option<SelectNextState>,
 1327    add_selections_state: Option<AddSelectionsState>,
 1328}
 1329
 1330#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1331enum SelectionHistoryMode {
 1332    #[default]
 1333    Normal,
 1334    Undoing,
 1335    Redoing,
 1336    Skipping,
 1337}
 1338
 1339#[derive(Clone, PartialEq, Eq, Hash)]
 1340struct HoveredCursor {
 1341    replica_id: ReplicaId,
 1342    selection_id: usize,
 1343}
 1344
 1345#[derive(Debug)]
 1346/// SelectionEffects controls the side-effects of updating the selection.
 1347///
 1348/// The default behaviour does "what you mostly want":
 1349/// - it pushes to the nav history if the cursor moved by >10 lines
 1350/// - it re-triggers completion requests
 1351/// - it scrolls to fit
 1352///
 1353/// You might want to modify these behaviours. For example when doing a "jump"
 1354/// like go to definition, we always want to add to nav history; but when scrolling
 1355/// in vim mode we never do.
 1356///
 1357/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1358/// move.
 1359#[derive(Clone)]
 1360pub struct SelectionEffects {
 1361    nav_history: Option<bool>,
 1362    completions: bool,
 1363    scroll: Option<Autoscroll>,
 1364}
 1365
 1366impl Default for SelectionEffects {
 1367    fn default() -> Self {
 1368        Self {
 1369            nav_history: None,
 1370            completions: true,
 1371            scroll: Some(Autoscroll::fit()),
 1372        }
 1373    }
 1374}
 1375impl SelectionEffects {
 1376    pub fn scroll(scroll: Autoscroll) -> Self {
 1377        Self {
 1378            scroll: Some(scroll),
 1379            ..Default::default()
 1380        }
 1381    }
 1382
 1383    pub fn no_scroll() -> Self {
 1384        Self {
 1385            scroll: None,
 1386            ..Default::default()
 1387        }
 1388    }
 1389
 1390    pub fn completions(self, completions: bool) -> Self {
 1391        Self {
 1392            completions,
 1393            ..self
 1394        }
 1395    }
 1396
 1397    pub fn nav_history(self, nav_history: bool) -> Self {
 1398        Self {
 1399            nav_history: Some(nav_history),
 1400            ..self
 1401        }
 1402    }
 1403}
 1404
 1405struct DeferredSelectionEffectsState {
 1406    changed: bool,
 1407    effects: SelectionEffects,
 1408    old_cursor_position: Anchor,
 1409    history_entry: SelectionHistoryEntry,
 1410}
 1411
 1412#[derive(Default)]
 1413struct SelectionHistory {
 1414    #[allow(clippy::type_complexity)]
 1415    selections_by_transaction:
 1416        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1417    mode: SelectionHistoryMode,
 1418    undo_stack: VecDeque<SelectionHistoryEntry>,
 1419    redo_stack: VecDeque<SelectionHistoryEntry>,
 1420}
 1421
 1422impl SelectionHistory {
 1423    #[track_caller]
 1424    fn insert_transaction(
 1425        &mut self,
 1426        transaction_id: TransactionId,
 1427        selections: Arc<[Selection<Anchor>]>,
 1428    ) {
 1429        if selections.is_empty() {
 1430            log::error!(
 1431                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1432                std::panic::Location::caller()
 1433            );
 1434            return;
 1435        }
 1436        self.selections_by_transaction
 1437            .insert(transaction_id, (selections, None));
 1438    }
 1439
 1440    #[allow(clippy::type_complexity)]
 1441    fn transaction(
 1442        &self,
 1443        transaction_id: TransactionId,
 1444    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1445        self.selections_by_transaction.get(&transaction_id)
 1446    }
 1447
 1448    #[allow(clippy::type_complexity)]
 1449    fn transaction_mut(
 1450        &mut self,
 1451        transaction_id: TransactionId,
 1452    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1453        self.selections_by_transaction.get_mut(&transaction_id)
 1454    }
 1455
 1456    fn push(&mut self, entry: SelectionHistoryEntry) {
 1457        if !entry.selections.is_empty() {
 1458            match self.mode {
 1459                SelectionHistoryMode::Normal => {
 1460                    self.push_undo(entry);
 1461                    self.redo_stack.clear();
 1462                }
 1463                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1464                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1465                SelectionHistoryMode::Skipping => {}
 1466            }
 1467        }
 1468    }
 1469
 1470    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1471        if self
 1472            .undo_stack
 1473            .back()
 1474            .is_none_or(|e| e.selections != entry.selections)
 1475        {
 1476            self.undo_stack.push_back(entry);
 1477            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1478                self.undo_stack.pop_front();
 1479            }
 1480        }
 1481    }
 1482
 1483    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1484        if self
 1485            .redo_stack
 1486            .back()
 1487            .is_none_or(|e| e.selections != entry.selections)
 1488        {
 1489            self.redo_stack.push_back(entry);
 1490            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1491                self.redo_stack.pop_front();
 1492            }
 1493        }
 1494    }
 1495}
 1496
 1497#[derive(Clone, Copy)]
 1498pub struct RowHighlightOptions {
 1499    pub autoscroll: bool,
 1500    pub include_gutter: bool,
 1501}
 1502
 1503impl Default for RowHighlightOptions {
 1504    fn default() -> Self {
 1505        Self {
 1506            autoscroll: Default::default(),
 1507            include_gutter: true,
 1508        }
 1509    }
 1510}
 1511
 1512struct RowHighlight {
 1513    index: usize,
 1514    range: Range<Anchor>,
 1515    color: Hsla,
 1516    options: RowHighlightOptions,
 1517    type_id: TypeId,
 1518}
 1519
 1520#[derive(Clone, Debug)]
 1521struct AddSelectionsState {
 1522    groups: Vec<AddSelectionsGroup>,
 1523}
 1524
 1525#[derive(Clone, Debug)]
 1526struct AddSelectionsGroup {
 1527    above: bool,
 1528    stack: Vec<usize>,
 1529}
 1530
 1531#[derive(Clone)]
 1532struct SelectNextState {
 1533    query: AhoCorasick,
 1534    wordwise: bool,
 1535    done: bool,
 1536}
 1537
 1538impl std::fmt::Debug for SelectNextState {
 1539    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1540        f.debug_struct(std::any::type_name::<Self>())
 1541            .field("wordwise", &self.wordwise)
 1542            .field("done", &self.done)
 1543            .finish()
 1544    }
 1545}
 1546
 1547#[derive(Debug)]
 1548struct AutocloseRegion {
 1549    selection_id: usize,
 1550    range: Range<Anchor>,
 1551    pair: BracketPair,
 1552}
 1553
 1554#[derive(Debug)]
 1555struct SnippetState {
 1556    ranges: Vec<Vec<Range<Anchor>>>,
 1557    active_index: usize,
 1558    choices: Vec<Option<Vec<String>>>,
 1559}
 1560
 1561#[doc(hidden)]
 1562pub struct RenameState {
 1563    pub range: Range<Anchor>,
 1564    pub old_name: Arc<str>,
 1565    pub editor: Entity<Editor>,
 1566    block_id: CustomBlockId,
 1567}
 1568
 1569struct InvalidationStack<T>(Vec<T>);
 1570
 1571struct RegisteredEditPredictionDelegate {
 1572    provider: Arc<dyn EditPredictionDelegateHandle>,
 1573    _subscription: Subscription,
 1574}
 1575
 1576#[derive(Debug, PartialEq, Eq)]
 1577pub struct ActiveDiagnosticGroup {
 1578    pub active_range: Range<Anchor>,
 1579    pub active_message: String,
 1580    pub group_id: usize,
 1581    pub blocks: HashSet<CustomBlockId>,
 1582}
 1583
 1584#[derive(Debug, PartialEq, Eq)]
 1585
 1586pub(crate) enum ActiveDiagnostic {
 1587    None,
 1588    All,
 1589    Group(ActiveDiagnosticGroup),
 1590}
 1591
 1592#[derive(Serialize, Deserialize, Clone, Debug)]
 1593pub struct ClipboardSelection {
 1594    /// The number of bytes in this selection.
 1595    pub len: usize,
 1596    /// Whether this was a full-line selection.
 1597    pub is_entire_line: bool,
 1598    /// The indentation of the first line when this content was originally copied.
 1599    pub first_line_indent: u32,
 1600    #[serde(default)]
 1601    pub file_path: Option<PathBuf>,
 1602    #[serde(default)]
 1603    pub line_range: Option<RangeInclusive<u32>>,
 1604}
 1605
 1606impl ClipboardSelection {
 1607    pub fn for_buffer(
 1608        len: usize,
 1609        is_entire_line: bool,
 1610        range: Range<Point>,
 1611        buffer: &MultiBufferSnapshot,
 1612        project: Option<&Entity<Project>>,
 1613        cx: &App,
 1614    ) -> Self {
 1615        let first_line_indent = buffer
 1616            .indent_size_for_line(MultiBufferRow(range.start.row))
 1617            .len;
 1618
 1619        let file_path = util::maybe!({
 1620            let project = project?.read(cx);
 1621            let file = buffer.file_at(range.start)?;
 1622            let project_path = ProjectPath {
 1623                worktree_id: file.worktree_id(cx),
 1624                path: file.path().clone(),
 1625            };
 1626            project.absolute_path(&project_path, cx)
 1627        });
 1628
 1629        let line_range = file_path.as_ref().map(|_| range.start.row..=range.end.row);
 1630
 1631        Self {
 1632            len,
 1633            is_entire_line,
 1634            first_line_indent,
 1635            file_path,
 1636            line_range,
 1637        }
 1638    }
 1639}
 1640
 1641// selections, scroll behavior, was newest selection reversed
 1642type SelectSyntaxNodeHistoryState = (
 1643    Box<[Selection<MultiBufferOffset>]>,
 1644    SelectSyntaxNodeScrollBehavior,
 1645    bool,
 1646);
 1647
 1648#[derive(Default)]
 1649struct SelectSyntaxNodeHistory {
 1650    stack: Vec<SelectSyntaxNodeHistoryState>,
 1651    // disable temporarily to allow changing selections without losing the stack
 1652    pub disable_clearing: bool,
 1653}
 1654
 1655impl SelectSyntaxNodeHistory {
 1656    pub fn try_clear(&mut self) {
 1657        if !self.disable_clearing {
 1658            self.stack.clear();
 1659        }
 1660    }
 1661
 1662    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1663        self.stack.push(selection);
 1664    }
 1665
 1666    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1667        self.stack.pop()
 1668    }
 1669}
 1670
 1671enum SelectSyntaxNodeScrollBehavior {
 1672    CursorTop,
 1673    FitSelection,
 1674    CursorBottom,
 1675}
 1676
 1677#[derive(Debug)]
 1678pub(crate) struct NavigationData {
 1679    cursor_anchor: Anchor,
 1680    cursor_position: Point,
 1681    scroll_anchor: ScrollAnchor,
 1682    scroll_top_row: u32,
 1683}
 1684
 1685#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1686pub enum GotoDefinitionKind {
 1687    Symbol,
 1688    Declaration,
 1689    Type,
 1690    Implementation,
 1691}
 1692
 1693pub enum FormatTarget {
 1694    Buffers(HashSet<Entity<Buffer>>),
 1695    Ranges(Vec<Range<MultiBufferPoint>>),
 1696}
 1697
 1698pub(crate) struct FocusedBlock {
 1699    id: BlockId,
 1700    focus_handle: WeakFocusHandle,
 1701}
 1702
 1703#[derive(Clone, Debug)]
 1704enum JumpData {
 1705    MultiBufferRow {
 1706        row: MultiBufferRow,
 1707        line_offset_from_top: u32,
 1708    },
 1709    MultiBufferPoint {
 1710        excerpt_id: ExcerptId,
 1711        position: Point,
 1712        anchor: text::Anchor,
 1713        line_offset_from_top: u32,
 1714    },
 1715}
 1716
 1717pub enum MultibufferSelectionMode {
 1718    First,
 1719    All,
 1720}
 1721
 1722#[derive(Clone, Copy, Debug, Default)]
 1723pub struct RewrapOptions {
 1724    pub override_language_settings: bool,
 1725    pub preserve_existing_whitespace: bool,
 1726}
 1727
 1728impl Editor {
 1729    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1730        let buffer = cx.new(|cx| Buffer::local("", cx));
 1731        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1732        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1733    }
 1734
 1735    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1736        let buffer = cx.new(|cx| Buffer::local("", cx));
 1737        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1738        Self::new(EditorMode::full(), buffer, None, window, cx)
 1739    }
 1740
 1741    pub fn auto_height(
 1742        min_lines: usize,
 1743        max_lines: usize,
 1744        window: &mut Window,
 1745        cx: &mut Context<Self>,
 1746    ) -> Self {
 1747        let buffer = cx.new(|cx| Buffer::local("", cx));
 1748        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1749        Self::new(
 1750            EditorMode::AutoHeight {
 1751                min_lines,
 1752                max_lines: Some(max_lines),
 1753            },
 1754            buffer,
 1755            None,
 1756            window,
 1757            cx,
 1758        )
 1759    }
 1760
 1761    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1762    /// The editor grows as tall as needed to fit its content.
 1763    pub fn auto_height_unbounded(
 1764        min_lines: usize,
 1765        window: &mut Window,
 1766        cx: &mut Context<Self>,
 1767    ) -> Self {
 1768        let buffer = cx.new(|cx| Buffer::local("", cx));
 1769        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1770        Self::new(
 1771            EditorMode::AutoHeight {
 1772                min_lines,
 1773                max_lines: None,
 1774            },
 1775            buffer,
 1776            None,
 1777            window,
 1778            cx,
 1779        )
 1780    }
 1781
 1782    pub fn for_buffer(
 1783        buffer: Entity<Buffer>,
 1784        project: Option<Entity<Project>>,
 1785        window: &mut Window,
 1786        cx: &mut Context<Self>,
 1787    ) -> Self {
 1788        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1789        Self::new(EditorMode::full(), buffer, project, window, cx)
 1790    }
 1791
 1792    pub fn for_multibuffer(
 1793        buffer: Entity<MultiBuffer>,
 1794        project: Option<Entity<Project>>,
 1795        window: &mut Window,
 1796        cx: &mut Context<Self>,
 1797    ) -> Self {
 1798        Self::new(EditorMode::full(), buffer, project, window, cx)
 1799    }
 1800
 1801    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1802        let mut clone = Self::new(
 1803            self.mode.clone(),
 1804            self.buffer.clone(),
 1805            self.project.clone(),
 1806            window,
 1807            cx,
 1808        );
 1809        self.display_map.update(cx, |display_map, cx| {
 1810            let snapshot = display_map.snapshot(cx);
 1811            clone.display_map.update(cx, |display_map, cx| {
 1812                display_map.set_state(&snapshot, cx);
 1813            });
 1814        });
 1815        clone.folds_did_change(cx);
 1816        clone.selections.clone_state(&self.selections);
 1817        clone.scroll_manager.clone_state(&self.scroll_manager);
 1818        clone.searchable = self.searchable;
 1819        clone.read_only = self.read_only;
 1820        clone
 1821    }
 1822
 1823    pub fn new(
 1824        mode: EditorMode,
 1825        buffer: Entity<MultiBuffer>,
 1826        project: Option<Entity<Project>>,
 1827        window: &mut Window,
 1828        cx: &mut Context<Self>,
 1829    ) -> Self {
 1830        Editor::new_internal(mode, buffer, project, None, window, cx)
 1831    }
 1832
 1833    pub fn sticky_headers(
 1834        &self,
 1835        style: &EditorStyle,
 1836        cx: &App,
 1837    ) -> Option<Vec<OutlineItem<Anchor>>> {
 1838        let multi_buffer = self.buffer().read(cx);
 1839        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1840        let multi_buffer_visible_start = self
 1841            .scroll_manager
 1842            .anchor()
 1843            .anchor
 1844            .to_point(&multi_buffer_snapshot);
 1845        let max_row = multi_buffer_snapshot.max_point().row;
 1846
 1847        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1848        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1849
 1850        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1851            let outline_items = buffer
 1852                .outline_items_containing(
 1853                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1854                    true,
 1855                    Some(style.syntax.as_ref()),
 1856                )
 1857                .into_iter()
 1858                .map(|outline_item| OutlineItem {
 1859                    depth: outline_item.depth,
 1860                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1861                    source_range_for_text: Anchor::range_in_buffer(
 1862                        *excerpt_id,
 1863                        outline_item.source_range_for_text,
 1864                    ),
 1865                    text: outline_item.text,
 1866                    highlight_ranges: outline_item.highlight_ranges,
 1867                    name_ranges: outline_item.name_ranges,
 1868                    body_range: outline_item
 1869                        .body_range
 1870                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1871                    annotation_range: outline_item
 1872                        .annotation_range
 1873                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1874                });
 1875            return Some(outline_items.collect());
 1876        }
 1877
 1878        None
 1879    }
 1880
 1881    fn new_internal(
 1882        mode: EditorMode,
 1883        multi_buffer: Entity<MultiBuffer>,
 1884        project: Option<Entity<Project>>,
 1885        display_map: Option<Entity<DisplayMap>>,
 1886        window: &mut Window,
 1887        cx: &mut Context<Self>,
 1888    ) -> Self {
 1889        debug_assert!(
 1890            display_map.is_none() || mode.is_minimap(),
 1891            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1892        );
 1893
 1894        let full_mode = mode.is_full();
 1895        let is_minimap = mode.is_minimap();
 1896        let diagnostics_max_severity = if full_mode {
 1897            EditorSettings::get_global(cx)
 1898                .diagnostics_max_severity
 1899                .unwrap_or(DiagnosticSeverity::Hint)
 1900        } else {
 1901            DiagnosticSeverity::Off
 1902        };
 1903        let style = window.text_style();
 1904        let font_size = style.font_size.to_pixels(window.rem_size());
 1905        let editor = cx.entity().downgrade();
 1906        let fold_placeholder = FoldPlaceholder {
 1907            constrain_width: false,
 1908            render: Arc::new(move |fold_id, fold_range, cx| {
 1909                let editor = editor.clone();
 1910                div()
 1911                    .id(fold_id)
 1912                    .bg(cx.theme().colors().ghost_element_background)
 1913                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1914                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1915                    .rounded_xs()
 1916                    .size_full()
 1917                    .cursor_pointer()
 1918                    .child("")
 1919                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1920                    .on_click(move |_, _window, cx| {
 1921                        editor
 1922                            .update(cx, |editor, cx| {
 1923                                editor.unfold_ranges(
 1924                                    &[fold_range.start..fold_range.end],
 1925                                    true,
 1926                                    false,
 1927                                    cx,
 1928                                );
 1929                                cx.stop_propagation();
 1930                            })
 1931                            .ok();
 1932                    })
 1933                    .into_any()
 1934            }),
 1935            merge_adjacent: true,
 1936            ..FoldPlaceholder::default()
 1937        };
 1938        let display_map = display_map.unwrap_or_else(|| {
 1939            cx.new(|cx| {
 1940                DisplayMap::new(
 1941                    multi_buffer.clone(),
 1942                    style.font(),
 1943                    font_size,
 1944                    None,
 1945                    FILE_HEADER_HEIGHT,
 1946                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1947                    fold_placeholder,
 1948                    diagnostics_max_severity,
 1949                    cx,
 1950                )
 1951            })
 1952        });
 1953
 1954        let selections = SelectionsCollection::new();
 1955
 1956        let blink_manager = cx.new(|cx| {
 1957            let mut blink_manager = BlinkManager::new(
 1958                CURSOR_BLINK_INTERVAL,
 1959                |cx| EditorSettings::get_global(cx).cursor_blink,
 1960                cx,
 1961            );
 1962            if is_minimap {
 1963                blink_manager.disable(cx);
 1964            }
 1965            blink_manager
 1966        });
 1967
 1968        let soft_wrap_mode_override =
 1969            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1970
 1971        let mut project_subscriptions = Vec::new();
 1972        if full_mode && let Some(project) = project.as_ref() {
 1973            project_subscriptions.push(cx.subscribe_in(
 1974                project,
 1975                window,
 1976                |editor, _, event, window, cx| match event {
 1977                    project::Event::RefreshCodeLens => {
 1978                        // we always query lens with actions, without storing them, always refreshing them
 1979                    }
 1980                    project::Event::RefreshInlayHints {
 1981                        server_id,
 1982                        request_id,
 1983                    } => {
 1984                        editor.refresh_inlay_hints(
 1985                            InlayHintRefreshReason::RefreshRequested {
 1986                                server_id: *server_id,
 1987                                request_id: *request_id,
 1988                            },
 1989                            cx,
 1990                        );
 1991                    }
 1992                    project::Event::LanguageServerRemoved(..) => {
 1993                        if editor.tasks_update_task.is_none() {
 1994                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1995                        }
 1996                        editor.registered_buffers.clear();
 1997                        editor.register_visible_buffers(cx);
 1998                    }
 1999                    project::Event::LanguageServerAdded(..) => {
 2000                        if editor.tasks_update_task.is_none() {
 2001                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2002                        }
 2003                    }
 2004                    project::Event::SnippetEdit(id, snippet_edits) => {
 2005                        // todo(lw): Non singletons
 2006                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2007                            let snapshot = buffer.read(cx).snapshot();
 2008                            let focus_handle = editor.focus_handle(cx);
 2009                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2010                                for (range, snippet) in snippet_edits {
 2011                                    let buffer_range =
 2012                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2013                                    editor
 2014                                        .insert_snippet(
 2015                                            &[MultiBufferOffset(buffer_range.start)
 2016                                                ..MultiBufferOffset(buffer_range.end)],
 2017                                            snippet.clone(),
 2018                                            window,
 2019                                            cx,
 2020                                        )
 2021                                        .ok();
 2022                                }
 2023                            }
 2024                        }
 2025                    }
 2026                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2027                        let buffer_id = *buffer_id;
 2028                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2029                            editor.register_buffer(buffer_id, cx);
 2030                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2031                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2032                            refresh_linked_ranges(editor, window, cx);
 2033                            editor.refresh_code_actions(window, cx);
 2034                            editor.refresh_document_highlights(cx);
 2035                        }
 2036                    }
 2037
 2038                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2039                        let Some(workspace) = editor.workspace() else {
 2040                            return;
 2041                        };
 2042                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2043                        else {
 2044                            return;
 2045                        };
 2046
 2047                        if active_editor.entity_id() == cx.entity_id() {
 2048                            let entity_id = cx.entity_id();
 2049                            workspace.update(cx, |this, cx| {
 2050                                this.panes_mut()
 2051                                    .iter_mut()
 2052                                    .filter(|pane| pane.entity_id() != entity_id)
 2053                                    .for_each(|p| {
 2054                                        p.update(cx, |pane, _| {
 2055                                            pane.nav_history_mut().rename_item(
 2056                                                entity_id,
 2057                                                project_path.clone(),
 2058                                                abs_path.clone().into(),
 2059                                            );
 2060                                        })
 2061                                    });
 2062                            });
 2063
 2064                            Self::open_transaction_for_hidden_buffers(
 2065                                workspace,
 2066                                transaction.clone(),
 2067                                "Rename".to_string(),
 2068                                window,
 2069                                cx,
 2070                            );
 2071                        }
 2072                    }
 2073
 2074                    project::Event::WorkspaceEditApplied(transaction) => {
 2075                        let Some(workspace) = editor.workspace() else {
 2076                            return;
 2077                        };
 2078                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2079                        else {
 2080                            return;
 2081                        };
 2082
 2083                        if active_editor.entity_id() == cx.entity_id() {
 2084                            Self::open_transaction_for_hidden_buffers(
 2085                                workspace,
 2086                                transaction.clone(),
 2087                                "LSP Edit".to_string(),
 2088                                window,
 2089                                cx,
 2090                            );
 2091                        }
 2092                    }
 2093
 2094                    _ => {}
 2095                },
 2096            ));
 2097            if let Some(task_inventory) = project
 2098                .read(cx)
 2099                .task_store()
 2100                .read(cx)
 2101                .task_inventory()
 2102                .cloned()
 2103            {
 2104                project_subscriptions.push(cx.observe_in(
 2105                    &task_inventory,
 2106                    window,
 2107                    |editor, _, window, cx| {
 2108                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2109                    },
 2110                ));
 2111            };
 2112
 2113            project_subscriptions.push(cx.subscribe_in(
 2114                &project.read(cx).breakpoint_store(),
 2115                window,
 2116                |editor, _, event, window, cx| match event {
 2117                    BreakpointStoreEvent::ClearDebugLines => {
 2118                        editor.clear_row_highlights::<ActiveDebugLine>();
 2119                        editor.refresh_inline_values(cx);
 2120                    }
 2121                    BreakpointStoreEvent::SetDebugLine => {
 2122                        if editor.go_to_active_debug_line(window, cx) {
 2123                            cx.stop_propagation();
 2124                        }
 2125
 2126                        editor.refresh_inline_values(cx);
 2127                    }
 2128                    _ => {}
 2129                },
 2130            ));
 2131            let git_store = project.read(cx).git_store().clone();
 2132            let project = project.clone();
 2133            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2134                if let GitStoreEvent::RepositoryAdded = event {
 2135                    this.load_diff_task = Some(
 2136                        update_uncommitted_diff_for_buffer(
 2137                            cx.entity(),
 2138                            &project,
 2139                            this.buffer.read(cx).all_buffers(),
 2140                            this.buffer.clone(),
 2141                            cx,
 2142                        )
 2143                        .shared(),
 2144                    );
 2145                }
 2146            }));
 2147        }
 2148
 2149        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2150
 2151        let inlay_hint_settings =
 2152            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2153        let focus_handle = cx.focus_handle();
 2154        if !is_minimap {
 2155            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2156                .detach();
 2157            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2158                .detach();
 2159            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2160                .detach();
 2161            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2162                .detach();
 2163            cx.observe_pending_input(window, Self::observe_pending_input)
 2164                .detach();
 2165        }
 2166
 2167        let show_indent_guides =
 2168            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2169                Some(false)
 2170            } else {
 2171                None
 2172            };
 2173
 2174        let breakpoint_store = match (&mode, project.as_ref()) {
 2175            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2176            _ => None,
 2177        };
 2178
 2179        let mut code_action_providers = Vec::new();
 2180        let mut load_uncommitted_diff = None;
 2181        if let Some(project) = project.clone() {
 2182            load_uncommitted_diff = Some(
 2183                update_uncommitted_diff_for_buffer(
 2184                    cx.entity(),
 2185                    &project,
 2186                    multi_buffer.read(cx).all_buffers(),
 2187                    multi_buffer.clone(),
 2188                    cx,
 2189                )
 2190                .shared(),
 2191            );
 2192            code_action_providers.push(Rc::new(project) as Rc<_>);
 2193        }
 2194
 2195        let mut editor = Self {
 2196            focus_handle,
 2197            show_cursor_when_unfocused: false,
 2198            last_focused_descendant: None,
 2199            buffer: multi_buffer.clone(),
 2200            display_map: display_map.clone(),
 2201            placeholder_display_map: None,
 2202            selections,
 2203            scroll_manager: ScrollManager::new(cx),
 2204            columnar_selection_state: None,
 2205            add_selections_state: None,
 2206            select_next_state: None,
 2207            select_prev_state: None,
 2208            selection_history: SelectionHistory::default(),
 2209            defer_selection_effects: false,
 2210            deferred_selection_effects_state: None,
 2211            autoclose_regions: Vec::new(),
 2212            snippet_stack: InvalidationStack::default(),
 2213            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2214            ime_transaction: None,
 2215            active_diagnostics: ActiveDiagnostic::None,
 2216            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2217            inline_diagnostics_update: Task::ready(()),
 2218            inline_diagnostics: Vec::new(),
 2219            soft_wrap_mode_override,
 2220            diagnostics_max_severity,
 2221            hard_wrap: None,
 2222            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2223            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2224            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2225            project,
 2226            blink_manager: blink_manager.clone(),
 2227            show_local_selections: true,
 2228            show_scrollbars: ScrollbarAxes {
 2229                horizontal: full_mode,
 2230                vertical: full_mode,
 2231            },
 2232            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2233            offset_content: !matches!(mode, EditorMode::SingleLine),
 2234            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2235            show_gutter: full_mode,
 2236            show_line_numbers: (!full_mode).then_some(false),
 2237            use_relative_line_numbers: None,
 2238            disable_expand_excerpt_buttons: !full_mode,
 2239            show_git_diff_gutter: None,
 2240            show_code_actions: None,
 2241            show_runnables: None,
 2242            show_breakpoints: None,
 2243            show_wrap_guides: None,
 2244            show_indent_guides,
 2245            buffers_with_disabled_indent_guides: HashSet::default(),
 2246            highlight_order: 0,
 2247            highlighted_rows: HashMap::default(),
 2248            background_highlights: HashMap::default(),
 2249            gutter_highlights: HashMap::default(),
 2250            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2251            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2252            nav_history: None,
 2253            context_menu: RefCell::new(None),
 2254            context_menu_options: None,
 2255            mouse_context_menu: None,
 2256            completion_tasks: Vec::new(),
 2257            inline_blame_popover: None,
 2258            inline_blame_popover_show_task: None,
 2259            signature_help_state: SignatureHelpState::default(),
 2260            auto_signature_help: None,
 2261            find_all_references_task_sources: Vec::new(),
 2262            next_completion_id: 0,
 2263            next_inlay_id: 0,
 2264            code_action_providers,
 2265            available_code_actions: None,
 2266            code_actions_task: None,
 2267            quick_selection_highlight_task: None,
 2268            debounced_selection_highlight_task: None,
 2269            document_highlights_task: None,
 2270            linked_editing_range_task: None,
 2271            pending_rename: None,
 2272            searchable: !is_minimap,
 2273            cursor_shape: EditorSettings::get_global(cx)
 2274                .cursor_shape
 2275                .unwrap_or_default(),
 2276            cursor_offset_on_selection: false,
 2277            current_line_highlight: None,
 2278            autoindent_mode: Some(AutoindentMode::EachLine),
 2279            collapse_matches: false,
 2280            workspace: None,
 2281            input_enabled: !is_minimap,
 2282            use_modal_editing: full_mode,
 2283            read_only: is_minimap,
 2284            use_autoclose: true,
 2285            use_auto_surround: true,
 2286            auto_replace_emoji_shortcode: false,
 2287            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2288            leader_id: None,
 2289            remote_id: None,
 2290            hover_state: HoverState::default(),
 2291            pending_mouse_down: None,
 2292            prev_pressure_stage: None,
 2293            hovered_link_state: None,
 2294            edit_prediction_provider: None,
 2295            active_edit_prediction: None,
 2296            stale_edit_prediction_in_menu: None,
 2297            edit_prediction_preview: EditPredictionPreview::Inactive {
 2298                released_too_fast: false,
 2299            },
 2300            inline_diagnostics_enabled: full_mode,
 2301            diagnostics_enabled: full_mode,
 2302            word_completions_enabled: full_mode,
 2303            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2304            gutter_hovered: false,
 2305            pixel_position_of_newest_cursor: None,
 2306            last_bounds: None,
 2307            last_position_map: None,
 2308            expect_bounds_change: None,
 2309            gutter_dimensions: GutterDimensions::default(),
 2310            style: None,
 2311            show_cursor_names: false,
 2312            hovered_cursors: HashMap::default(),
 2313            next_editor_action_id: EditorActionId::default(),
 2314            editor_actions: Rc::default(),
 2315            edit_predictions_hidden_for_vim_mode: false,
 2316            show_edit_predictions_override: None,
 2317            show_completions_on_input_override: None,
 2318            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2319            edit_prediction_settings: EditPredictionSettings::Disabled,
 2320            edit_prediction_indent_conflict: false,
 2321            edit_prediction_requires_modifier_in_indent_conflict: true,
 2322            custom_context_menu: None,
 2323            show_git_blame_gutter: false,
 2324            show_git_blame_inline: false,
 2325            show_selection_menu: None,
 2326            show_git_blame_inline_delay_task: None,
 2327            git_blame_inline_enabled: full_mode
 2328                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2329            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2330            buffer_serialization: is_minimap.not().then(|| {
 2331                BufferSerialization::new(
 2332                    ProjectSettings::get_global(cx)
 2333                        .session
 2334                        .restore_unsaved_buffers,
 2335                )
 2336            }),
 2337            blame: None,
 2338            blame_subscription: None,
 2339            tasks: BTreeMap::default(),
 2340
 2341            breakpoint_store,
 2342            gutter_breakpoint_indicator: (None, None),
 2343            hovered_diff_hunk_row: None,
 2344            _subscriptions: (!is_minimap)
 2345                .then(|| {
 2346                    vec![
 2347                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2348                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2349                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2350                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2351                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2352                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2353                        cx.observe_window_activation(window, |editor, window, cx| {
 2354                            let active = window.is_window_active();
 2355                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2356                                if active {
 2357                                    blink_manager.enable(cx);
 2358                                } else {
 2359                                    blink_manager.disable(cx);
 2360                                }
 2361                            });
 2362                            if active {
 2363                                editor.show_mouse_cursor(cx);
 2364                            }
 2365                        }),
 2366                    ]
 2367                })
 2368                .unwrap_or_default(),
 2369            tasks_update_task: None,
 2370            pull_diagnostics_task: Task::ready(()),
 2371            pull_diagnostics_background_task: Task::ready(()),
 2372            colors: None,
 2373            refresh_colors_task: Task::ready(()),
 2374            inlay_hints: None,
 2375            next_color_inlay_id: 0,
 2376            post_scroll_update: Task::ready(()),
 2377            linked_edit_ranges: Default::default(),
 2378            in_project_search: false,
 2379            previous_search_ranges: None,
 2380            breadcrumb_header: None,
 2381            focused_block: None,
 2382            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2383            addons: HashMap::default(),
 2384            registered_buffers: HashMap::default(),
 2385            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2386            selection_mark_mode: false,
 2387            toggle_fold_multiple_buffers: Task::ready(()),
 2388            serialize_selections: Task::ready(()),
 2389            serialize_folds: Task::ready(()),
 2390            text_style_refinement: None,
 2391            load_diff_task: load_uncommitted_diff,
 2392            temporary_diff_override: false,
 2393            mouse_cursor_hidden: false,
 2394            minimap: None,
 2395            hide_mouse_mode: EditorSettings::get_global(cx)
 2396                .hide_mouse
 2397                .unwrap_or_default(),
 2398            change_list: ChangeList::new(),
 2399            mode,
 2400            selection_drag_state: SelectionDragState::None,
 2401            folding_newlines: Task::ready(()),
 2402            lookup_key: None,
 2403            select_next_is_case_sensitive: None,
 2404            applicable_language_settings: HashMap::default(),
 2405            accent_data: None,
 2406            fetched_tree_sitter_chunks: HashMap::default(),
 2407            use_base_text_line_numbers: false,
 2408        };
 2409
 2410        if is_minimap {
 2411            return editor;
 2412        }
 2413
 2414        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2415        editor.accent_data = editor.fetch_accent_data(cx);
 2416
 2417        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2418            editor
 2419                ._subscriptions
 2420                .push(cx.observe(breakpoints, |_, _, cx| {
 2421                    cx.notify();
 2422                }));
 2423        }
 2424        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2425        editor._subscriptions.extend(project_subscriptions);
 2426
 2427        editor._subscriptions.push(cx.subscribe_in(
 2428            &cx.entity(),
 2429            window,
 2430            |editor, _, e: &EditorEvent, window, cx| match e {
 2431                EditorEvent::ScrollPositionChanged { local, .. } => {
 2432                    if *local {
 2433                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2434                        editor.inline_blame_popover.take();
 2435                        let new_anchor = editor.scroll_manager.anchor();
 2436                        let snapshot = editor.snapshot(window, cx);
 2437                        editor.update_restoration_data(cx, move |data| {
 2438                            data.scroll_position = (
 2439                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2440                                new_anchor.offset,
 2441                            );
 2442                        });
 2443
 2444                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2445                            cx.background_executor()
 2446                                .timer(Duration::from_millis(50))
 2447                                .await;
 2448                            editor
 2449                                .update_in(cx, |editor, window, cx| {
 2450                                    editor.register_visible_buffers(cx);
 2451                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2452                                    editor.refresh_inlay_hints(
 2453                                        InlayHintRefreshReason::NewLinesShown,
 2454                                        cx,
 2455                                    );
 2456                                    editor.colorize_brackets(false, cx);
 2457                                })
 2458                                .ok();
 2459                        });
 2460                    }
 2461                }
 2462                EditorEvent::Edited { .. } => {
 2463                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2464                        .map(|vim_mode| vim_mode.0)
 2465                        .unwrap_or(false);
 2466                    if !vim_mode {
 2467                        let display_map = editor.display_snapshot(cx);
 2468                        let selections = editor.selections.all_adjusted_display(&display_map);
 2469                        let pop_state = editor
 2470                            .change_list
 2471                            .last()
 2472                            .map(|previous| {
 2473                                previous.len() == selections.len()
 2474                                    && previous.iter().enumerate().all(|(ix, p)| {
 2475                                        p.to_display_point(&display_map).row()
 2476                                            == selections[ix].head().row()
 2477                                    })
 2478                            })
 2479                            .unwrap_or(false);
 2480                        let new_positions = selections
 2481                            .into_iter()
 2482                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2483                            .collect();
 2484                        editor
 2485                            .change_list
 2486                            .push_to_change_list(pop_state, new_positions);
 2487                    }
 2488                }
 2489                _ => (),
 2490            },
 2491        ));
 2492
 2493        if let Some(dap_store) = editor
 2494            .project
 2495            .as_ref()
 2496            .map(|project| project.read(cx).dap_store())
 2497        {
 2498            let weak_editor = cx.weak_entity();
 2499
 2500            editor
 2501                ._subscriptions
 2502                .push(
 2503                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2504                        let session_entity = cx.entity();
 2505                        weak_editor
 2506                            .update(cx, |editor, cx| {
 2507                                editor._subscriptions.push(
 2508                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2509                                );
 2510                            })
 2511                            .ok();
 2512                    }),
 2513                );
 2514
 2515            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2516                editor
 2517                    ._subscriptions
 2518                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2519            }
 2520        }
 2521
 2522        // skip adding the initial selection to selection history
 2523        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2524        editor.end_selection(window, cx);
 2525        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2526
 2527        editor.scroll_manager.show_scrollbars(window, cx);
 2528        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2529
 2530        if full_mode {
 2531            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2532            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2533
 2534            if editor.git_blame_inline_enabled {
 2535                editor.start_git_blame_inline(false, window, cx);
 2536            }
 2537
 2538            editor.go_to_active_debug_line(window, cx);
 2539
 2540            editor.minimap =
 2541                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2542            editor.colors = Some(LspColorData::new(cx));
 2543            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2544
 2545            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2546                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2547            }
 2548            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2549        }
 2550
 2551        editor
 2552    }
 2553
 2554    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2555        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2556    }
 2557
 2558    pub fn deploy_mouse_context_menu(
 2559        &mut self,
 2560        position: gpui::Point<Pixels>,
 2561        context_menu: Entity<ContextMenu>,
 2562        window: &mut Window,
 2563        cx: &mut Context<Self>,
 2564    ) {
 2565        self.mouse_context_menu = Some(MouseContextMenu::new(
 2566            self,
 2567            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2568            context_menu,
 2569            window,
 2570            cx,
 2571        ));
 2572    }
 2573
 2574    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2575        self.mouse_context_menu
 2576            .as_ref()
 2577            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2578    }
 2579
 2580    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2581        if self
 2582            .selections
 2583            .pending_anchor()
 2584            .is_some_and(|pending_selection| {
 2585                let snapshot = self.buffer().read(cx).snapshot(cx);
 2586                pending_selection.range().includes(range, &snapshot)
 2587            })
 2588        {
 2589            return true;
 2590        }
 2591
 2592        self.selections
 2593            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2594            .into_iter()
 2595            .any(|selection| {
 2596                // This is needed to cover a corner case, if we just check for an existing
 2597                // selection in the fold range, having a cursor at the start of the fold
 2598                // marks it as selected. Non-empty selections don't cause this.
 2599                let length = selection.end - selection.start;
 2600                length > 0
 2601            })
 2602    }
 2603
 2604    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2605        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2606    }
 2607
 2608    fn key_context_internal(
 2609        &self,
 2610        has_active_edit_prediction: bool,
 2611        window: &mut Window,
 2612        cx: &mut App,
 2613    ) -> KeyContext {
 2614        let mut key_context = KeyContext::new_with_defaults();
 2615        key_context.add("Editor");
 2616        let mode = match self.mode {
 2617            EditorMode::SingleLine => "single_line",
 2618            EditorMode::AutoHeight { .. } => "auto_height",
 2619            EditorMode::Minimap { .. } => "minimap",
 2620            EditorMode::Full { .. } => "full",
 2621        };
 2622
 2623        if EditorSettings::jupyter_enabled(cx) {
 2624            key_context.add("jupyter");
 2625        }
 2626
 2627        key_context.set("mode", mode);
 2628        if self.pending_rename.is_some() {
 2629            key_context.add("renaming");
 2630        }
 2631
 2632        if let Some(snippet_stack) = self.snippet_stack.last() {
 2633            key_context.add("in_snippet");
 2634
 2635            if snippet_stack.active_index > 0 {
 2636                key_context.add("has_previous_tabstop");
 2637            }
 2638
 2639            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2640                key_context.add("has_next_tabstop");
 2641            }
 2642        }
 2643
 2644        match self.context_menu.borrow().as_ref() {
 2645            Some(CodeContextMenu::Completions(menu)) => {
 2646                if menu.visible() {
 2647                    key_context.add("menu");
 2648                    key_context.add("showing_completions");
 2649                }
 2650            }
 2651            Some(CodeContextMenu::CodeActions(menu)) => {
 2652                if menu.visible() {
 2653                    key_context.add("menu");
 2654                    key_context.add("showing_code_actions")
 2655                }
 2656            }
 2657            None => {}
 2658        }
 2659
 2660        if self.signature_help_state.has_multiple_signatures() {
 2661            key_context.add("showing_signature_help");
 2662        }
 2663
 2664        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2665        if !self.focus_handle(cx).contains_focused(window, cx)
 2666            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2667        {
 2668            for addon in self.addons.values() {
 2669                addon.extend_key_context(&mut key_context, cx)
 2670            }
 2671        }
 2672
 2673        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2674            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2675                Some(
 2676                    file.full_path(cx)
 2677                        .extension()?
 2678                        .to_string_lossy()
 2679                        .into_owned(),
 2680                )
 2681            }) {
 2682                key_context.set("extension", extension);
 2683            }
 2684        } else {
 2685            key_context.add("multibuffer");
 2686        }
 2687
 2688        if has_active_edit_prediction {
 2689            if self.edit_prediction_in_conflict() {
 2690                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2691            } else {
 2692                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2693                key_context.add("copilot_suggestion");
 2694            }
 2695        }
 2696
 2697        if self.selection_mark_mode {
 2698            key_context.add("selection_mode");
 2699        }
 2700
 2701        let disjoint = self.selections.disjoint_anchors();
 2702        let snapshot = self.snapshot(window, cx);
 2703        let snapshot = snapshot.buffer_snapshot();
 2704        if self.mode == EditorMode::SingleLine
 2705            && let [selection] = disjoint
 2706            && selection.start == selection.end
 2707            && selection.end.to_offset(snapshot) == snapshot.len()
 2708        {
 2709            key_context.add("end_of_input");
 2710        }
 2711
 2712        if self.has_any_expanded_diff_hunks(cx) {
 2713            key_context.add("diffs_expanded");
 2714        }
 2715
 2716        key_context
 2717    }
 2718
 2719    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2720        self.last_bounds.as_ref()
 2721    }
 2722
 2723    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2724        if self.mouse_cursor_hidden {
 2725            self.mouse_cursor_hidden = false;
 2726            cx.notify();
 2727        }
 2728    }
 2729
 2730    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2731        let hide_mouse_cursor = match origin {
 2732            HideMouseCursorOrigin::TypingAction => {
 2733                matches!(
 2734                    self.hide_mouse_mode,
 2735                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2736                )
 2737            }
 2738            HideMouseCursorOrigin::MovementAction => {
 2739                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2740            }
 2741        };
 2742        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2743            self.mouse_cursor_hidden = hide_mouse_cursor;
 2744            cx.notify();
 2745        }
 2746    }
 2747
 2748    pub fn edit_prediction_in_conflict(&self) -> bool {
 2749        if !self.show_edit_predictions_in_menu() {
 2750            return false;
 2751        }
 2752
 2753        let showing_completions = self
 2754            .context_menu
 2755            .borrow()
 2756            .as_ref()
 2757            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2758
 2759        showing_completions
 2760            || self.edit_prediction_requires_modifier()
 2761            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2762            // bindings to insert tab characters.
 2763            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2764    }
 2765
 2766    pub fn accept_edit_prediction_keybind(
 2767        &self,
 2768        granularity: EditPredictionGranularity,
 2769        window: &mut Window,
 2770        cx: &mut App,
 2771    ) -> AcceptEditPredictionBinding {
 2772        let key_context = self.key_context_internal(true, window, cx);
 2773        let in_conflict = self.edit_prediction_in_conflict();
 2774
 2775        let bindings =
 2776            match granularity {
 2777                EditPredictionGranularity::Word => window
 2778                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2779                EditPredictionGranularity::Line => window
 2780                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2781                EditPredictionGranularity::Full => {
 2782                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2783                }
 2784            };
 2785
 2786        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2787            !in_conflict
 2788                || binding
 2789                    .keystrokes()
 2790                    .first()
 2791                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2792        }))
 2793    }
 2794
 2795    pub fn new_file(
 2796        workspace: &mut Workspace,
 2797        _: &workspace::NewFile,
 2798        window: &mut Window,
 2799        cx: &mut Context<Workspace>,
 2800    ) {
 2801        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2802            "Failed to create buffer",
 2803            window,
 2804            cx,
 2805            |e, _, _| match e.error_code() {
 2806                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2807                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2808                e.error_tag("required").unwrap_or("the latest version")
 2809            )),
 2810                _ => None,
 2811            },
 2812        );
 2813    }
 2814
 2815    pub fn new_in_workspace(
 2816        workspace: &mut Workspace,
 2817        window: &mut Window,
 2818        cx: &mut Context<Workspace>,
 2819    ) -> Task<Result<Entity<Editor>>> {
 2820        let project = workspace.project().clone();
 2821        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2822
 2823        cx.spawn_in(window, async move |workspace, cx| {
 2824            let buffer = create.await?;
 2825            workspace.update_in(cx, |workspace, window, cx| {
 2826                let editor =
 2827                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2828                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2829                editor
 2830            })
 2831        })
 2832    }
 2833
 2834    fn new_file_vertical(
 2835        workspace: &mut Workspace,
 2836        _: &workspace::NewFileSplitVertical,
 2837        window: &mut Window,
 2838        cx: &mut Context<Workspace>,
 2839    ) {
 2840        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2841    }
 2842
 2843    fn new_file_horizontal(
 2844        workspace: &mut Workspace,
 2845        _: &workspace::NewFileSplitHorizontal,
 2846        window: &mut Window,
 2847        cx: &mut Context<Workspace>,
 2848    ) {
 2849        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2850    }
 2851
 2852    fn new_file_split(
 2853        workspace: &mut Workspace,
 2854        action: &workspace::NewFileSplit,
 2855        window: &mut Window,
 2856        cx: &mut Context<Workspace>,
 2857    ) {
 2858        Self::new_file_in_direction(workspace, action.0, window, cx)
 2859    }
 2860
 2861    fn new_file_in_direction(
 2862        workspace: &mut Workspace,
 2863        direction: SplitDirection,
 2864        window: &mut Window,
 2865        cx: &mut Context<Workspace>,
 2866    ) {
 2867        let project = workspace.project().clone();
 2868        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2869
 2870        cx.spawn_in(window, async move |workspace, cx| {
 2871            let buffer = create.await?;
 2872            workspace.update_in(cx, move |workspace, window, cx| {
 2873                workspace.split_item(
 2874                    direction,
 2875                    Box::new(
 2876                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2877                    ),
 2878                    window,
 2879                    cx,
 2880                )
 2881            })?;
 2882            anyhow::Ok(())
 2883        })
 2884        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2885            match e.error_code() {
 2886                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2887                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2888                e.error_tag("required").unwrap_or("the latest version")
 2889            )),
 2890                _ => None,
 2891            }
 2892        });
 2893    }
 2894
 2895    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2896        self.leader_id
 2897    }
 2898
 2899    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2900        &self.buffer
 2901    }
 2902
 2903    pub fn project(&self) -> Option<&Entity<Project>> {
 2904        self.project.as_ref()
 2905    }
 2906
 2907    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2908        self.workspace.as_ref()?.0.upgrade()
 2909    }
 2910
 2911    /// Returns the workspace serialization ID if this editor should be serialized.
 2912    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2913        self.workspace
 2914            .as_ref()
 2915            .filter(|_| self.should_serialize_buffer())
 2916            .and_then(|workspace| workspace.1)
 2917    }
 2918
 2919    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2920        self.buffer().read(cx).title(cx)
 2921    }
 2922
 2923    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2924        let git_blame_gutter_max_author_length = self
 2925            .render_git_blame_gutter(cx)
 2926            .then(|| {
 2927                if let Some(blame) = self.blame.as_ref() {
 2928                    let max_author_length =
 2929                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2930                    Some(max_author_length)
 2931                } else {
 2932                    None
 2933                }
 2934            })
 2935            .flatten();
 2936
 2937        EditorSnapshot {
 2938            mode: self.mode.clone(),
 2939            show_gutter: self.show_gutter,
 2940            offset_content: self.offset_content,
 2941            show_line_numbers: self.show_line_numbers,
 2942            show_git_diff_gutter: self.show_git_diff_gutter,
 2943            show_code_actions: self.show_code_actions,
 2944            show_runnables: self.show_runnables,
 2945            show_breakpoints: self.show_breakpoints,
 2946            git_blame_gutter_max_author_length,
 2947            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2948            placeholder_display_snapshot: self
 2949                .placeholder_display_map
 2950                .as_ref()
 2951                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2952            scroll_anchor: self.scroll_manager.anchor(),
 2953            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2954            is_focused: self.focus_handle.is_focused(window),
 2955            current_line_highlight: self
 2956                .current_line_highlight
 2957                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2958            gutter_hovered: self.gutter_hovered,
 2959        }
 2960    }
 2961
 2962    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2963        self.buffer.read(cx).language_at(point, cx)
 2964    }
 2965
 2966    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2967        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2968    }
 2969
 2970    pub fn active_excerpt(
 2971        &self,
 2972        cx: &App,
 2973    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2974        self.buffer
 2975            .read(cx)
 2976            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2977    }
 2978
 2979    pub fn mode(&self) -> &EditorMode {
 2980        &self.mode
 2981    }
 2982
 2983    pub fn set_mode(&mut self, mode: EditorMode) {
 2984        self.mode = mode;
 2985    }
 2986
 2987    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2988        self.collaboration_hub.as_deref()
 2989    }
 2990
 2991    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2992        self.collaboration_hub = Some(hub);
 2993    }
 2994
 2995    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2996        self.in_project_search = in_project_search;
 2997    }
 2998
 2999    pub fn set_custom_context_menu(
 3000        &mut self,
 3001        f: impl 'static
 3002        + Fn(
 3003            &mut Self,
 3004            DisplayPoint,
 3005            &mut Window,
 3006            &mut Context<Self>,
 3007        ) -> Option<Entity<ui::ContextMenu>>,
 3008    ) {
 3009        self.custom_context_menu = Some(Box::new(f))
 3010    }
 3011
 3012    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3013        self.completion_provider = provider;
 3014    }
 3015
 3016    #[cfg(any(test, feature = "test-support"))]
 3017    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3018        self.completion_provider.clone()
 3019    }
 3020
 3021    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3022        self.semantics_provider.clone()
 3023    }
 3024
 3025    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3026        self.semantics_provider = provider;
 3027    }
 3028
 3029    pub fn set_edit_prediction_provider<T>(
 3030        &mut self,
 3031        provider: Option<Entity<T>>,
 3032        window: &mut Window,
 3033        cx: &mut Context<Self>,
 3034    ) where
 3035        T: EditPredictionDelegate,
 3036    {
 3037        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3038            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3039                if this.focus_handle.is_focused(window) {
 3040                    this.update_visible_edit_prediction(window, cx);
 3041                }
 3042            }),
 3043            provider: Arc::new(provider),
 3044        });
 3045        self.update_edit_prediction_settings(cx);
 3046        self.refresh_edit_prediction(false, false, window, cx);
 3047    }
 3048
 3049    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3050        self.placeholder_display_map
 3051            .as_ref()
 3052            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3053    }
 3054
 3055    pub fn set_placeholder_text(
 3056        &mut self,
 3057        placeholder_text: &str,
 3058        window: &mut Window,
 3059        cx: &mut Context<Self>,
 3060    ) {
 3061        let multibuffer = cx
 3062            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3063
 3064        let style = window.text_style();
 3065
 3066        self.placeholder_display_map = Some(cx.new(|cx| {
 3067            DisplayMap::new(
 3068                multibuffer,
 3069                style.font(),
 3070                style.font_size.to_pixels(window.rem_size()),
 3071                None,
 3072                FILE_HEADER_HEIGHT,
 3073                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3074                Default::default(),
 3075                DiagnosticSeverity::Off,
 3076                cx,
 3077            )
 3078        }));
 3079        cx.notify();
 3080    }
 3081
 3082    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3083        self.cursor_shape = cursor_shape;
 3084
 3085        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3086        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3087
 3088        cx.notify();
 3089    }
 3090
 3091    pub fn cursor_shape(&self) -> CursorShape {
 3092        self.cursor_shape
 3093    }
 3094
 3095    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3096        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3097    }
 3098
 3099    pub fn set_current_line_highlight(
 3100        &mut self,
 3101        current_line_highlight: Option<CurrentLineHighlight>,
 3102    ) {
 3103        self.current_line_highlight = current_line_highlight;
 3104    }
 3105
 3106    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3107        self.collapse_matches = collapse_matches;
 3108    }
 3109
 3110    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3111        if self.collapse_matches {
 3112            return range.start..range.start;
 3113        }
 3114        range.clone()
 3115    }
 3116
 3117    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3118        self.display_map.read(cx).clip_at_line_ends
 3119    }
 3120
 3121    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3122        if self.display_map.read(cx).clip_at_line_ends != clip {
 3123            self.display_map
 3124                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3125        }
 3126    }
 3127
 3128    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3129        self.input_enabled = input_enabled;
 3130    }
 3131
 3132    pub fn set_edit_predictions_hidden_for_vim_mode(
 3133        &mut self,
 3134        hidden: bool,
 3135        window: &mut Window,
 3136        cx: &mut Context<Self>,
 3137    ) {
 3138        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3139            self.edit_predictions_hidden_for_vim_mode = hidden;
 3140            if hidden {
 3141                self.update_visible_edit_prediction(window, cx);
 3142            } else {
 3143                self.refresh_edit_prediction(true, false, window, cx);
 3144            }
 3145        }
 3146    }
 3147
 3148    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3149        self.menu_edit_predictions_policy = value;
 3150    }
 3151
 3152    pub fn set_autoindent(&mut self, autoindent: bool) {
 3153        if autoindent {
 3154            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3155        } else {
 3156            self.autoindent_mode = None;
 3157        }
 3158    }
 3159
 3160    pub fn read_only(&self, cx: &App) -> bool {
 3161        self.read_only || self.buffer.read(cx).read_only()
 3162    }
 3163
 3164    pub fn set_read_only(&mut self, read_only: bool) {
 3165        self.read_only = read_only;
 3166    }
 3167
 3168    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3169        self.use_autoclose = autoclose;
 3170    }
 3171
 3172    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3173        self.use_auto_surround = auto_surround;
 3174    }
 3175
 3176    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3177        self.auto_replace_emoji_shortcode = auto_replace;
 3178    }
 3179
 3180    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3181        self.buffer_serialization = should_serialize.then(|| {
 3182            BufferSerialization::new(
 3183                ProjectSettings::get_global(cx)
 3184                    .session
 3185                    .restore_unsaved_buffers,
 3186            )
 3187        })
 3188    }
 3189
 3190    fn should_serialize_buffer(&self) -> bool {
 3191        self.buffer_serialization.is_some()
 3192    }
 3193
 3194    pub fn toggle_edit_predictions(
 3195        &mut self,
 3196        _: &ToggleEditPrediction,
 3197        window: &mut Window,
 3198        cx: &mut Context<Self>,
 3199    ) {
 3200        if self.show_edit_predictions_override.is_some() {
 3201            self.set_show_edit_predictions(None, window, cx);
 3202        } else {
 3203            let show_edit_predictions = !self.edit_predictions_enabled();
 3204            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3205        }
 3206    }
 3207
 3208    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3209        self.show_completions_on_input_override = show_completions_on_input;
 3210    }
 3211
 3212    pub fn set_show_edit_predictions(
 3213        &mut self,
 3214        show_edit_predictions: Option<bool>,
 3215        window: &mut Window,
 3216        cx: &mut Context<Self>,
 3217    ) {
 3218        self.show_edit_predictions_override = show_edit_predictions;
 3219        self.update_edit_prediction_settings(cx);
 3220
 3221        if let Some(false) = show_edit_predictions {
 3222            self.discard_edit_prediction(false, cx);
 3223        } else {
 3224            self.refresh_edit_prediction(false, true, window, cx);
 3225        }
 3226    }
 3227
 3228    fn edit_predictions_disabled_in_scope(
 3229        &self,
 3230        buffer: &Entity<Buffer>,
 3231        buffer_position: language::Anchor,
 3232        cx: &App,
 3233    ) -> bool {
 3234        let snapshot = buffer.read(cx).snapshot();
 3235        let settings = snapshot.settings_at(buffer_position, cx);
 3236
 3237        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3238            return false;
 3239        };
 3240
 3241        scope.override_name().is_some_and(|scope_name| {
 3242            settings
 3243                .edit_predictions_disabled_in
 3244                .iter()
 3245                .any(|s| s == scope_name)
 3246        })
 3247    }
 3248
 3249    pub fn set_use_modal_editing(&mut self, to: bool) {
 3250        self.use_modal_editing = to;
 3251    }
 3252
 3253    pub fn use_modal_editing(&self) -> bool {
 3254        self.use_modal_editing
 3255    }
 3256
 3257    fn selections_did_change(
 3258        &mut self,
 3259        local: bool,
 3260        old_cursor_position: &Anchor,
 3261        effects: SelectionEffects,
 3262        window: &mut Window,
 3263        cx: &mut Context<Self>,
 3264    ) {
 3265        window.invalidate_character_coordinates();
 3266
 3267        // Copy selections to primary selection buffer
 3268        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3269        if local {
 3270            let selections = self
 3271                .selections
 3272                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3273            let buffer_handle = self.buffer.read(cx).read(cx);
 3274
 3275            let mut text = String::new();
 3276            for (index, selection) in selections.iter().enumerate() {
 3277                let text_for_selection = buffer_handle
 3278                    .text_for_range(selection.start..selection.end)
 3279                    .collect::<String>();
 3280
 3281                text.push_str(&text_for_selection);
 3282                if index != selections.len() - 1 {
 3283                    text.push('\n');
 3284                }
 3285            }
 3286
 3287            if !text.is_empty() {
 3288                cx.write_to_primary(ClipboardItem::new_string(text));
 3289            }
 3290        }
 3291
 3292        let selection_anchors = self.selections.disjoint_anchors_arc();
 3293
 3294        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3295            self.buffer.update(cx, |buffer, cx| {
 3296                buffer.set_active_selections(
 3297                    &selection_anchors,
 3298                    self.selections.line_mode(),
 3299                    self.cursor_shape,
 3300                    cx,
 3301                )
 3302            });
 3303        }
 3304        let display_map = self
 3305            .display_map
 3306            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3307        let buffer = display_map.buffer_snapshot();
 3308        if self.selections.count() == 1 {
 3309            self.add_selections_state = None;
 3310        }
 3311        self.select_next_state = None;
 3312        self.select_prev_state = None;
 3313        self.select_syntax_node_history.try_clear();
 3314        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3315        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3316        self.take_rename(false, window, cx);
 3317
 3318        let newest_selection = self.selections.newest_anchor();
 3319        let new_cursor_position = newest_selection.head();
 3320        let selection_start = newest_selection.start;
 3321
 3322        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3323            self.push_to_nav_history(
 3324                *old_cursor_position,
 3325                Some(new_cursor_position.to_point(buffer)),
 3326                false,
 3327                effects.nav_history == Some(true),
 3328                cx,
 3329            );
 3330        }
 3331
 3332        if local {
 3333            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3334                self.register_buffer(buffer_id, cx);
 3335            }
 3336
 3337            let mut context_menu = self.context_menu.borrow_mut();
 3338            let completion_menu = match context_menu.as_ref() {
 3339                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3340                Some(CodeContextMenu::CodeActions(_)) => {
 3341                    *context_menu = None;
 3342                    None
 3343                }
 3344                None => None,
 3345            };
 3346            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3347            drop(context_menu);
 3348
 3349            if effects.completions
 3350                && let Some(completion_position) = completion_position
 3351            {
 3352                let start_offset = selection_start.to_offset(buffer);
 3353                let position_matches = start_offset == completion_position.to_offset(buffer);
 3354                let continue_showing = if position_matches {
 3355                    if self.snippet_stack.is_empty() {
 3356                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3357                            == Some(CharKind::Word)
 3358                    } else {
 3359                        // Snippet choices can be shown even when the cursor is in whitespace.
 3360                        // Dismissing the menu with actions like backspace is handled by
 3361                        // invalidation regions.
 3362                        true
 3363                    }
 3364                } else {
 3365                    false
 3366                };
 3367
 3368                if continue_showing {
 3369                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3370                } else {
 3371                    self.hide_context_menu(window, cx);
 3372                }
 3373            }
 3374
 3375            hide_hover(self, cx);
 3376
 3377            if old_cursor_position.to_display_point(&display_map).row()
 3378                != new_cursor_position.to_display_point(&display_map).row()
 3379            {
 3380                self.available_code_actions.take();
 3381            }
 3382            self.refresh_code_actions(window, cx);
 3383            self.refresh_document_highlights(cx);
 3384            refresh_linked_ranges(self, window, cx);
 3385
 3386            self.refresh_selected_text_highlights(false, window, cx);
 3387            self.refresh_matching_bracket_highlights(window, cx);
 3388            self.update_visible_edit_prediction(window, cx);
 3389            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3390            self.inline_blame_popover.take();
 3391            if self.git_blame_inline_enabled {
 3392                self.start_inline_blame_timer(window, cx);
 3393            }
 3394        }
 3395
 3396        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3397        cx.emit(EditorEvent::SelectionsChanged { local });
 3398
 3399        let selections = &self.selections.disjoint_anchors_arc();
 3400        if selections.len() == 1 {
 3401            cx.emit(SearchEvent::ActiveMatchChanged)
 3402        }
 3403        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3404            let inmemory_selections = selections
 3405                .iter()
 3406                .map(|s| {
 3407                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3408                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3409                })
 3410                .collect();
 3411            self.update_restoration_data(cx, |data| {
 3412                data.selections = inmemory_selections;
 3413            });
 3414
 3415            if WorkspaceSettings::get(None, cx).restore_on_startup
 3416                != RestoreOnStartupBehavior::EmptyTab
 3417                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3418            {
 3419                let snapshot = self.buffer().read(cx).snapshot(cx);
 3420                let selections = selections.clone();
 3421                let background_executor = cx.background_executor().clone();
 3422                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3423                self.serialize_selections = cx.background_spawn(async move {
 3424                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3425                    let db_selections = selections
 3426                        .iter()
 3427                        .map(|selection| {
 3428                            (
 3429                                selection.start.to_offset(&snapshot).0,
 3430                                selection.end.to_offset(&snapshot).0,
 3431                            )
 3432                        })
 3433                        .collect();
 3434
 3435                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3436                        .await
 3437                        .with_context(|| {
 3438                            format!(
 3439                                "persisting editor selections for editor {editor_id}, \
 3440                                workspace {workspace_id:?}"
 3441                            )
 3442                        })
 3443                        .log_err();
 3444                });
 3445            }
 3446        }
 3447
 3448        cx.notify();
 3449    }
 3450
 3451    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3452        use text::ToOffset as _;
 3453        use text::ToPoint as _;
 3454
 3455        if self.mode.is_minimap()
 3456            || WorkspaceSettings::get(None, cx).restore_on_startup
 3457                == RestoreOnStartupBehavior::EmptyTab
 3458        {
 3459            return;
 3460        }
 3461
 3462        if !self.buffer().read(cx).is_singleton() {
 3463            return;
 3464        }
 3465
 3466        let display_snapshot = self
 3467            .display_map
 3468            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3469        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3470            return;
 3471        };
 3472        let inmemory_folds = display_snapshot
 3473            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3474            .map(|fold| {
 3475                fold.range.start.text_anchor.to_point(&snapshot)
 3476                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3477            })
 3478            .collect();
 3479        self.update_restoration_data(cx, |data| {
 3480            data.folds = inmemory_folds;
 3481        });
 3482
 3483        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3484            return;
 3485        };
 3486        let background_executor = cx.background_executor().clone();
 3487        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3488        let db_folds = display_snapshot
 3489            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3490            .map(|fold| {
 3491                (
 3492                    fold.range.start.text_anchor.to_offset(&snapshot),
 3493                    fold.range.end.text_anchor.to_offset(&snapshot),
 3494                )
 3495            })
 3496            .collect();
 3497        self.serialize_folds = cx.background_spawn(async move {
 3498            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3499            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3500                .await
 3501                .with_context(|| {
 3502                    format!(
 3503                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3504                    )
 3505                })
 3506                .log_err();
 3507        });
 3508    }
 3509
 3510    pub fn sync_selections(
 3511        &mut self,
 3512        other: Entity<Editor>,
 3513        cx: &mut Context<Self>,
 3514    ) -> gpui::Subscription {
 3515        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3516        if !other_selections.is_empty() {
 3517            self.selections
 3518                .change_with(&self.display_snapshot(cx), |selections| {
 3519                    selections.select_anchors(other_selections);
 3520                });
 3521        }
 3522
 3523        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3524            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3525                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3526                if other_selections.is_empty() {
 3527                    return;
 3528                }
 3529                let snapshot = this.display_snapshot(cx);
 3530                this.selections.change_with(&snapshot, |selections| {
 3531                    selections.select_anchors(other_selections);
 3532                });
 3533            }
 3534        });
 3535
 3536        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3537            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3538                let these_selections = this.selections.disjoint_anchors().to_vec();
 3539                if these_selections.is_empty() {
 3540                    return;
 3541                }
 3542                other.update(cx, |other_editor, cx| {
 3543                    let snapshot = other_editor.display_snapshot(cx);
 3544                    other_editor
 3545                        .selections
 3546                        .change_with(&snapshot, |selections| {
 3547                            selections.select_anchors(these_selections);
 3548                        })
 3549                });
 3550            }
 3551        });
 3552
 3553        Subscription::join(other_subscription, this_subscription)
 3554    }
 3555
 3556    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3557        if self.buffer().read(cx).is_singleton() {
 3558            return;
 3559        }
 3560        let snapshot = self.buffer.read(cx).snapshot(cx);
 3561        let buffer_ids: HashSet<BufferId> = self
 3562            .selections
 3563            .disjoint_anchor_ranges()
 3564            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3565            .collect();
 3566        for buffer_id in buffer_ids {
 3567            self.unfold_buffer(buffer_id, cx);
 3568        }
 3569    }
 3570
 3571    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3572    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3573    /// effects of selection change occur at the end of the transaction.
 3574    pub fn change_selections<R>(
 3575        &mut self,
 3576        effects: SelectionEffects,
 3577        window: &mut Window,
 3578        cx: &mut Context<Self>,
 3579        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3580    ) -> R {
 3581        let snapshot = self.display_snapshot(cx);
 3582        if let Some(state) = &mut self.deferred_selection_effects_state {
 3583            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3584            state.effects.completions = effects.completions;
 3585            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3586            let (changed, result) = self.selections.change_with(&snapshot, change);
 3587            state.changed |= changed;
 3588            return result;
 3589        }
 3590        let mut state = DeferredSelectionEffectsState {
 3591            changed: false,
 3592            effects,
 3593            old_cursor_position: self.selections.newest_anchor().head(),
 3594            history_entry: SelectionHistoryEntry {
 3595                selections: self.selections.disjoint_anchors_arc(),
 3596                select_next_state: self.select_next_state.clone(),
 3597                select_prev_state: self.select_prev_state.clone(),
 3598                add_selections_state: self.add_selections_state.clone(),
 3599            },
 3600        };
 3601        let (changed, result) = self.selections.change_with(&snapshot, change);
 3602        state.changed = state.changed || changed;
 3603        if self.defer_selection_effects {
 3604            self.deferred_selection_effects_state = Some(state);
 3605        } else {
 3606            self.apply_selection_effects(state, window, cx);
 3607        }
 3608        result
 3609    }
 3610
 3611    /// Defers the effects of selection change, so that the effects of multiple calls to
 3612    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3613    /// to selection history and the state of popovers based on selection position aren't
 3614    /// erroneously updated.
 3615    pub fn with_selection_effects_deferred<R>(
 3616        &mut self,
 3617        window: &mut Window,
 3618        cx: &mut Context<Self>,
 3619        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3620    ) -> R {
 3621        let already_deferred = self.defer_selection_effects;
 3622        self.defer_selection_effects = true;
 3623        let result = update(self, window, cx);
 3624        if !already_deferred {
 3625            self.defer_selection_effects = false;
 3626            if let Some(state) = self.deferred_selection_effects_state.take() {
 3627                self.apply_selection_effects(state, window, cx);
 3628            }
 3629        }
 3630        result
 3631    }
 3632
 3633    fn apply_selection_effects(
 3634        &mut self,
 3635        state: DeferredSelectionEffectsState,
 3636        window: &mut Window,
 3637        cx: &mut Context<Self>,
 3638    ) {
 3639        if state.changed {
 3640            self.selection_history.push(state.history_entry);
 3641
 3642            if let Some(autoscroll) = state.effects.scroll {
 3643                self.request_autoscroll(autoscroll, cx);
 3644            }
 3645
 3646            let old_cursor_position = &state.old_cursor_position;
 3647
 3648            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3649
 3650            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3651                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3652            }
 3653        }
 3654    }
 3655
 3656    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3657    where
 3658        I: IntoIterator<Item = (Range<S>, T)>,
 3659        S: ToOffset,
 3660        T: Into<Arc<str>>,
 3661    {
 3662        if self.read_only(cx) {
 3663            return;
 3664        }
 3665
 3666        self.buffer
 3667            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3668    }
 3669
 3670    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3671    where
 3672        I: IntoIterator<Item = (Range<S>, T)>,
 3673        S: ToOffset,
 3674        T: Into<Arc<str>>,
 3675    {
 3676        if self.read_only(cx) {
 3677            return;
 3678        }
 3679
 3680        self.buffer.update(cx, |buffer, cx| {
 3681            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3682        });
 3683    }
 3684
 3685    pub fn edit_with_block_indent<I, S, T>(
 3686        &mut self,
 3687        edits: I,
 3688        original_indent_columns: Vec<Option<u32>>,
 3689        cx: &mut Context<Self>,
 3690    ) where
 3691        I: IntoIterator<Item = (Range<S>, T)>,
 3692        S: ToOffset,
 3693        T: Into<Arc<str>>,
 3694    {
 3695        if self.read_only(cx) {
 3696            return;
 3697        }
 3698
 3699        self.buffer.update(cx, |buffer, cx| {
 3700            buffer.edit(
 3701                edits,
 3702                Some(AutoindentMode::Block {
 3703                    original_indent_columns,
 3704                }),
 3705                cx,
 3706            )
 3707        });
 3708    }
 3709
 3710    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3711        self.hide_context_menu(window, cx);
 3712
 3713        match phase {
 3714            SelectPhase::Begin {
 3715                position,
 3716                add,
 3717                click_count,
 3718            } => self.begin_selection(position, add, click_count, window, cx),
 3719            SelectPhase::BeginColumnar {
 3720                position,
 3721                goal_column,
 3722                reset,
 3723                mode,
 3724            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3725            SelectPhase::Extend {
 3726                position,
 3727                click_count,
 3728            } => self.extend_selection(position, click_count, window, cx),
 3729            SelectPhase::Update {
 3730                position,
 3731                goal_column,
 3732                scroll_delta,
 3733            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3734            SelectPhase::End => self.end_selection(window, cx),
 3735        }
 3736    }
 3737
 3738    fn extend_selection(
 3739        &mut self,
 3740        position: DisplayPoint,
 3741        click_count: usize,
 3742        window: &mut Window,
 3743        cx: &mut Context<Self>,
 3744    ) {
 3745        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3746        let tail = self
 3747            .selections
 3748            .newest::<MultiBufferOffset>(&display_map)
 3749            .tail();
 3750        let click_count = click_count.max(match self.selections.select_mode() {
 3751            SelectMode::Character => 1,
 3752            SelectMode::Word(_) => 2,
 3753            SelectMode::Line(_) => 3,
 3754            SelectMode::All => 4,
 3755        });
 3756        self.begin_selection(position, false, click_count, window, cx);
 3757
 3758        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3759
 3760        let current_selection = match self.selections.select_mode() {
 3761            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3762            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3763        };
 3764
 3765        let mut pending_selection = self
 3766            .selections
 3767            .pending_anchor()
 3768            .cloned()
 3769            .expect("extend_selection not called with pending selection");
 3770
 3771        if pending_selection
 3772            .start
 3773            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3774            == Ordering::Greater
 3775        {
 3776            pending_selection.start = current_selection.start;
 3777        }
 3778        if pending_selection
 3779            .end
 3780            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3781            == Ordering::Less
 3782        {
 3783            pending_selection.end = current_selection.end;
 3784            pending_selection.reversed = true;
 3785        }
 3786
 3787        let mut pending_mode = self.selections.pending_mode().unwrap();
 3788        match &mut pending_mode {
 3789            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3790            _ => {}
 3791        }
 3792
 3793        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3794            SelectionEffects::scroll(Autoscroll::fit())
 3795        } else {
 3796            SelectionEffects::no_scroll()
 3797        };
 3798
 3799        self.change_selections(effects, window, cx, |s| {
 3800            s.set_pending(pending_selection.clone(), pending_mode);
 3801            s.set_is_extending(true);
 3802        });
 3803    }
 3804
 3805    fn begin_selection(
 3806        &mut self,
 3807        position: DisplayPoint,
 3808        add: bool,
 3809        click_count: usize,
 3810        window: &mut Window,
 3811        cx: &mut Context<Self>,
 3812    ) {
 3813        if !self.focus_handle.is_focused(window) {
 3814            self.last_focused_descendant = None;
 3815            window.focus(&self.focus_handle, cx);
 3816        }
 3817
 3818        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3819        let buffer = display_map.buffer_snapshot();
 3820        let position = display_map.clip_point(position, Bias::Left);
 3821
 3822        let start;
 3823        let end;
 3824        let mode;
 3825        let mut auto_scroll;
 3826        match click_count {
 3827            1 => {
 3828                start = buffer.anchor_before(position.to_point(&display_map));
 3829                end = start;
 3830                mode = SelectMode::Character;
 3831                auto_scroll = true;
 3832            }
 3833            2 => {
 3834                let position = display_map
 3835                    .clip_point(position, Bias::Left)
 3836                    .to_offset(&display_map, Bias::Left);
 3837                let (range, _) = buffer.surrounding_word(position, None);
 3838                start = buffer.anchor_before(range.start);
 3839                end = buffer.anchor_before(range.end);
 3840                mode = SelectMode::Word(start..end);
 3841                auto_scroll = true;
 3842            }
 3843            3 => {
 3844                let position = display_map
 3845                    .clip_point(position, Bias::Left)
 3846                    .to_point(&display_map);
 3847                let line_start = display_map.prev_line_boundary(position).0;
 3848                let next_line_start = buffer.clip_point(
 3849                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3850                    Bias::Left,
 3851                );
 3852                start = buffer.anchor_before(line_start);
 3853                end = buffer.anchor_before(next_line_start);
 3854                mode = SelectMode::Line(start..end);
 3855                auto_scroll = true;
 3856            }
 3857            _ => {
 3858                start = buffer.anchor_before(MultiBufferOffset(0));
 3859                end = buffer.anchor_before(buffer.len());
 3860                mode = SelectMode::All;
 3861                auto_scroll = false;
 3862            }
 3863        }
 3864        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3865
 3866        let point_to_delete: Option<usize> = {
 3867            let selected_points: Vec<Selection<Point>> =
 3868                self.selections.disjoint_in_range(start..end, &display_map);
 3869
 3870            if !add || click_count > 1 {
 3871                None
 3872            } else if !selected_points.is_empty() {
 3873                Some(selected_points[0].id)
 3874            } else {
 3875                let clicked_point_already_selected =
 3876                    self.selections.disjoint_anchors().iter().find(|selection| {
 3877                        selection.start.to_point(buffer) == start.to_point(buffer)
 3878                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3879                    });
 3880
 3881                clicked_point_already_selected.map(|selection| selection.id)
 3882            }
 3883        };
 3884
 3885        let selections_count = self.selections.count();
 3886        let effects = if auto_scroll {
 3887            SelectionEffects::default()
 3888        } else {
 3889            SelectionEffects::no_scroll()
 3890        };
 3891
 3892        self.change_selections(effects, window, cx, |s| {
 3893            if let Some(point_to_delete) = point_to_delete {
 3894                s.delete(point_to_delete);
 3895
 3896                if selections_count == 1 {
 3897                    s.set_pending_anchor_range(start..end, mode);
 3898                }
 3899            } else {
 3900                if !add {
 3901                    s.clear_disjoint();
 3902                }
 3903
 3904                s.set_pending_anchor_range(start..end, mode);
 3905            }
 3906        });
 3907    }
 3908
 3909    fn begin_columnar_selection(
 3910        &mut self,
 3911        position: DisplayPoint,
 3912        goal_column: u32,
 3913        reset: bool,
 3914        mode: ColumnarMode,
 3915        window: &mut Window,
 3916        cx: &mut Context<Self>,
 3917    ) {
 3918        if !self.focus_handle.is_focused(window) {
 3919            self.last_focused_descendant = None;
 3920            window.focus(&self.focus_handle, cx);
 3921        }
 3922
 3923        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3924
 3925        if reset {
 3926            let pointer_position = display_map
 3927                .buffer_snapshot()
 3928                .anchor_before(position.to_point(&display_map));
 3929
 3930            self.change_selections(
 3931                SelectionEffects::scroll(Autoscroll::newest()),
 3932                window,
 3933                cx,
 3934                |s| {
 3935                    s.clear_disjoint();
 3936                    s.set_pending_anchor_range(
 3937                        pointer_position..pointer_position,
 3938                        SelectMode::Character,
 3939                    );
 3940                },
 3941            );
 3942        };
 3943
 3944        let tail = self.selections.newest::<Point>(&display_map).tail();
 3945        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3946        self.columnar_selection_state = match mode {
 3947            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3948                selection_tail: selection_anchor,
 3949                display_point: if reset {
 3950                    if position.column() != goal_column {
 3951                        Some(DisplayPoint::new(position.row(), goal_column))
 3952                    } else {
 3953                        None
 3954                    }
 3955                } else {
 3956                    None
 3957                },
 3958            }),
 3959            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3960                selection_tail: selection_anchor,
 3961            }),
 3962        };
 3963
 3964        if !reset {
 3965            self.select_columns(position, goal_column, &display_map, window, cx);
 3966        }
 3967    }
 3968
 3969    fn update_selection(
 3970        &mut self,
 3971        position: DisplayPoint,
 3972        goal_column: u32,
 3973        scroll_delta: gpui::Point<f32>,
 3974        window: &mut Window,
 3975        cx: &mut Context<Self>,
 3976    ) {
 3977        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3978
 3979        if self.columnar_selection_state.is_some() {
 3980            self.select_columns(position, goal_column, &display_map, window, cx);
 3981        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3982            let buffer = display_map.buffer_snapshot();
 3983            let head;
 3984            let tail;
 3985            let mode = self.selections.pending_mode().unwrap();
 3986            match &mode {
 3987                SelectMode::Character => {
 3988                    head = position.to_point(&display_map);
 3989                    tail = pending.tail().to_point(buffer);
 3990                }
 3991                SelectMode::Word(original_range) => {
 3992                    let offset = display_map
 3993                        .clip_point(position, Bias::Left)
 3994                        .to_offset(&display_map, Bias::Left);
 3995                    let original_range = original_range.to_offset(buffer);
 3996
 3997                    let head_offset = if buffer.is_inside_word(offset, None)
 3998                        || original_range.contains(&offset)
 3999                    {
 4000                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4001                        if word_range.start < original_range.start {
 4002                            word_range.start
 4003                        } else {
 4004                            word_range.end
 4005                        }
 4006                    } else {
 4007                        offset
 4008                    };
 4009
 4010                    head = head_offset.to_point(buffer);
 4011                    if head_offset <= original_range.start {
 4012                        tail = original_range.end.to_point(buffer);
 4013                    } else {
 4014                        tail = original_range.start.to_point(buffer);
 4015                    }
 4016                }
 4017                SelectMode::Line(original_range) => {
 4018                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4019
 4020                    let position = display_map
 4021                        .clip_point(position, Bias::Left)
 4022                        .to_point(&display_map);
 4023                    let line_start = display_map.prev_line_boundary(position).0;
 4024                    let next_line_start = buffer.clip_point(
 4025                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4026                        Bias::Left,
 4027                    );
 4028
 4029                    if line_start < original_range.start {
 4030                        head = line_start
 4031                    } else {
 4032                        head = next_line_start
 4033                    }
 4034
 4035                    if head <= original_range.start {
 4036                        tail = original_range.end;
 4037                    } else {
 4038                        tail = original_range.start;
 4039                    }
 4040                }
 4041                SelectMode::All => {
 4042                    return;
 4043                }
 4044            };
 4045
 4046            if head < tail {
 4047                pending.start = buffer.anchor_before(head);
 4048                pending.end = buffer.anchor_before(tail);
 4049                pending.reversed = true;
 4050            } else {
 4051                pending.start = buffer.anchor_before(tail);
 4052                pending.end = buffer.anchor_before(head);
 4053                pending.reversed = false;
 4054            }
 4055
 4056            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4057                s.set_pending(pending.clone(), mode);
 4058            });
 4059        } else {
 4060            log::error!("update_selection dispatched with no pending selection");
 4061            return;
 4062        }
 4063
 4064        self.apply_scroll_delta(scroll_delta, window, cx);
 4065        cx.notify();
 4066    }
 4067
 4068    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4069        self.columnar_selection_state.take();
 4070        if let Some(pending_mode) = self.selections.pending_mode() {
 4071            let selections = self
 4072                .selections
 4073                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4074            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4075                s.select(selections);
 4076                s.clear_pending();
 4077                if s.is_extending() {
 4078                    s.set_is_extending(false);
 4079                } else {
 4080                    s.set_select_mode(pending_mode);
 4081                }
 4082            });
 4083        }
 4084    }
 4085
 4086    fn select_columns(
 4087        &mut self,
 4088        head: DisplayPoint,
 4089        goal_column: u32,
 4090        display_map: &DisplaySnapshot,
 4091        window: &mut Window,
 4092        cx: &mut Context<Self>,
 4093    ) {
 4094        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4095            return;
 4096        };
 4097
 4098        let tail = match columnar_state {
 4099            ColumnarSelectionState::FromMouse {
 4100                selection_tail,
 4101                display_point,
 4102            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4103            ColumnarSelectionState::FromSelection { selection_tail } => {
 4104                selection_tail.to_display_point(display_map)
 4105            }
 4106        };
 4107
 4108        let start_row = cmp::min(tail.row(), head.row());
 4109        let end_row = cmp::max(tail.row(), head.row());
 4110        let start_column = cmp::min(tail.column(), goal_column);
 4111        let end_column = cmp::max(tail.column(), goal_column);
 4112        let reversed = start_column < tail.column();
 4113
 4114        let selection_ranges = (start_row.0..=end_row.0)
 4115            .map(DisplayRow)
 4116            .filter_map(|row| {
 4117                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4118                    || start_column <= display_map.line_len(row))
 4119                    && !display_map.is_block_line(row)
 4120                {
 4121                    let start = display_map
 4122                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4123                        .to_point(display_map);
 4124                    let end = display_map
 4125                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4126                        .to_point(display_map);
 4127                    if reversed {
 4128                        Some(end..start)
 4129                    } else {
 4130                        Some(start..end)
 4131                    }
 4132                } else {
 4133                    None
 4134                }
 4135            })
 4136            .collect::<Vec<_>>();
 4137        if selection_ranges.is_empty() {
 4138            return;
 4139        }
 4140
 4141        let ranges = match columnar_state {
 4142            ColumnarSelectionState::FromMouse { .. } => {
 4143                let mut non_empty_ranges = selection_ranges
 4144                    .iter()
 4145                    .filter(|selection_range| selection_range.start != selection_range.end)
 4146                    .peekable();
 4147                if non_empty_ranges.peek().is_some() {
 4148                    non_empty_ranges.cloned().collect()
 4149                } else {
 4150                    selection_ranges
 4151                }
 4152            }
 4153            _ => selection_ranges,
 4154        };
 4155
 4156        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4157            s.select_ranges(ranges);
 4158        });
 4159        cx.notify();
 4160    }
 4161
 4162    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4163        self.selections
 4164            .all_adjusted(snapshot)
 4165            .iter()
 4166            .any(|selection| !selection.is_empty())
 4167    }
 4168
 4169    pub fn has_pending_nonempty_selection(&self) -> bool {
 4170        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4171            Some(Selection { start, end, .. }) => start != end,
 4172            None => false,
 4173        };
 4174
 4175        pending_nonempty_selection
 4176            || (self.columnar_selection_state.is_some()
 4177                && self.selections.disjoint_anchors().len() > 1)
 4178    }
 4179
 4180    pub fn has_pending_selection(&self) -> bool {
 4181        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4182    }
 4183
 4184    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4185        self.selection_mark_mode = false;
 4186        self.selection_drag_state = SelectionDragState::None;
 4187
 4188        if self.dismiss_menus_and_popups(true, window, cx) {
 4189            cx.notify();
 4190            return;
 4191        }
 4192        if self.clear_expanded_diff_hunks(cx) {
 4193            cx.notify();
 4194            return;
 4195        }
 4196        if self.show_git_blame_gutter {
 4197            self.show_git_blame_gutter = false;
 4198            cx.notify();
 4199            return;
 4200        }
 4201
 4202        if self.mode.is_full()
 4203            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4204        {
 4205            cx.notify();
 4206            return;
 4207        }
 4208
 4209        cx.propagate();
 4210    }
 4211
 4212    pub fn dismiss_menus_and_popups(
 4213        &mut self,
 4214        is_user_requested: bool,
 4215        window: &mut Window,
 4216        cx: &mut Context<Self>,
 4217    ) -> bool {
 4218        let mut dismissed = false;
 4219
 4220        dismissed |= self.take_rename(false, window, cx).is_some();
 4221        dismissed |= self.hide_blame_popover(true, cx);
 4222        dismissed |= hide_hover(self, cx);
 4223        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4224        dismissed |= self.hide_context_menu(window, cx).is_some();
 4225        dismissed |= self.mouse_context_menu.take().is_some();
 4226        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4227        dismissed |= self.snippet_stack.pop().is_some();
 4228
 4229        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4230            self.dismiss_diagnostics(cx);
 4231            dismissed = true;
 4232        }
 4233
 4234        dismissed
 4235    }
 4236
 4237    fn linked_editing_ranges_for(
 4238        &self,
 4239        selection: Range<text::Anchor>,
 4240        cx: &App,
 4241    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4242        if self.linked_edit_ranges.is_empty() {
 4243            return None;
 4244        }
 4245        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4246            selection.end.buffer_id.and_then(|end_buffer_id| {
 4247                if selection.start.buffer_id != Some(end_buffer_id) {
 4248                    return None;
 4249                }
 4250                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4251                let snapshot = buffer.read(cx).snapshot();
 4252                self.linked_edit_ranges
 4253                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4254                    .map(|ranges| (ranges, snapshot, buffer))
 4255            })?;
 4256        use text::ToOffset as TO;
 4257        // find offset from the start of current range to current cursor position
 4258        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4259
 4260        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4261        let start_difference = start_offset - start_byte_offset;
 4262        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4263        let end_difference = end_offset - start_byte_offset;
 4264        // Current range has associated linked ranges.
 4265        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4266        for range in linked_ranges.iter() {
 4267            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4268            let end_offset = start_offset + end_difference;
 4269            let start_offset = start_offset + start_difference;
 4270            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4271                continue;
 4272            }
 4273            if self.selections.disjoint_anchor_ranges().any(|s| {
 4274                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4275                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4276                {
 4277                    return false;
 4278                }
 4279                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4280                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4281            }) {
 4282                continue;
 4283            }
 4284            let start = buffer_snapshot.anchor_after(start_offset);
 4285            let end = buffer_snapshot.anchor_after(end_offset);
 4286            linked_edits
 4287                .entry(buffer.clone())
 4288                .or_default()
 4289                .push(start..end);
 4290        }
 4291        Some(linked_edits)
 4292    }
 4293
 4294    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4295        let text: Arc<str> = text.into();
 4296
 4297        if self.read_only(cx) {
 4298            return;
 4299        }
 4300
 4301        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4302
 4303        self.unfold_buffers_with_selections(cx);
 4304
 4305        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4306        let mut bracket_inserted = false;
 4307        let mut edits = Vec::new();
 4308        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4309        let mut new_selections = Vec::with_capacity(selections.len());
 4310        let mut new_autoclose_regions = Vec::new();
 4311        let snapshot = self.buffer.read(cx).read(cx);
 4312        let mut clear_linked_edit_ranges = false;
 4313
 4314        for (selection, autoclose_region) in
 4315            self.selections_with_autoclose_regions(selections, &snapshot)
 4316        {
 4317            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4318                // Determine if the inserted text matches the opening or closing
 4319                // bracket of any of this language's bracket pairs.
 4320                let mut bracket_pair = None;
 4321                let mut is_bracket_pair_start = false;
 4322                let mut is_bracket_pair_end = false;
 4323                if !text.is_empty() {
 4324                    let mut bracket_pair_matching_end = None;
 4325                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4326                    //  and they are removing the character that triggered IME popup.
 4327                    for (pair, enabled) in scope.brackets() {
 4328                        if !pair.close && !pair.surround {
 4329                            continue;
 4330                        }
 4331
 4332                        if enabled && pair.start.ends_with(text.as_ref()) {
 4333                            let prefix_len = pair.start.len() - text.len();
 4334                            let preceding_text_matches_prefix = prefix_len == 0
 4335                                || (selection.start.column >= (prefix_len as u32)
 4336                                    && snapshot.contains_str_at(
 4337                                        Point::new(
 4338                                            selection.start.row,
 4339                                            selection.start.column - (prefix_len as u32),
 4340                                        ),
 4341                                        &pair.start[..prefix_len],
 4342                                    ));
 4343                            if preceding_text_matches_prefix {
 4344                                bracket_pair = Some(pair.clone());
 4345                                is_bracket_pair_start = true;
 4346                                break;
 4347                            }
 4348                        }
 4349                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4350                        {
 4351                            // take first bracket pair matching end, but don't break in case a later bracket
 4352                            // pair matches start
 4353                            bracket_pair_matching_end = Some(pair.clone());
 4354                        }
 4355                    }
 4356                    if let Some(end) = bracket_pair_matching_end
 4357                        && bracket_pair.is_none()
 4358                    {
 4359                        bracket_pair = Some(end);
 4360                        is_bracket_pair_end = true;
 4361                    }
 4362                }
 4363
 4364                if let Some(bracket_pair) = bracket_pair {
 4365                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4366                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4367                    let auto_surround =
 4368                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4369                    if selection.is_empty() {
 4370                        if is_bracket_pair_start {
 4371                            // If the inserted text is a suffix of an opening bracket and the
 4372                            // selection is preceded by the rest of the opening bracket, then
 4373                            // insert the closing bracket.
 4374                            let following_text_allows_autoclose = snapshot
 4375                                .chars_at(selection.start)
 4376                                .next()
 4377                                .is_none_or(|c| scope.should_autoclose_before(c));
 4378
 4379                            let preceding_text_allows_autoclose = selection.start.column == 0
 4380                                || snapshot
 4381                                    .reversed_chars_at(selection.start)
 4382                                    .next()
 4383                                    .is_none_or(|c| {
 4384                                        bracket_pair.start != bracket_pair.end
 4385                                            || !snapshot
 4386                                                .char_classifier_at(selection.start)
 4387                                                .is_word(c)
 4388                                    });
 4389
 4390                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4391                                && bracket_pair.start.len() == 1
 4392                            {
 4393                                let target = bracket_pair.start.chars().next().unwrap();
 4394                                let mut byte_offset = 0u32;
 4395                                let current_line_count = snapshot
 4396                                    .reversed_chars_at(selection.start)
 4397                                    .take_while(|&c| c != '\n')
 4398                                    .filter(|c| {
 4399                                        byte_offset += c.len_utf8() as u32;
 4400                                        if *c != target {
 4401                                            return false;
 4402                                        }
 4403
 4404                                        let point = Point::new(
 4405                                            selection.start.row,
 4406                                            selection.start.column.saturating_sub(byte_offset),
 4407                                        );
 4408
 4409                                        let is_enabled = snapshot
 4410                                            .language_scope_at(point)
 4411                                            .and_then(|scope| {
 4412                                                scope
 4413                                                    .brackets()
 4414                                                    .find(|(pair, _)| {
 4415                                                        pair.start == bracket_pair.start
 4416                                                    })
 4417                                                    .map(|(_, enabled)| enabled)
 4418                                            })
 4419                                            .unwrap_or(true);
 4420
 4421                                        let is_delimiter = snapshot
 4422                                            .language_scope_at(Point::new(
 4423                                                point.row,
 4424                                                point.column + 1,
 4425                                            ))
 4426                                            .and_then(|scope| {
 4427                                                scope
 4428                                                    .brackets()
 4429                                                    .find(|(pair, _)| {
 4430                                                        pair.start == bracket_pair.start
 4431                                                    })
 4432                                                    .map(|(_, enabled)| !enabled)
 4433                                            })
 4434                                            .unwrap_or(false);
 4435
 4436                                        is_enabled && !is_delimiter
 4437                                    })
 4438                                    .count();
 4439                                current_line_count % 2 == 1
 4440                            } else {
 4441                                false
 4442                            };
 4443
 4444                            if autoclose
 4445                                && bracket_pair.close
 4446                                && following_text_allows_autoclose
 4447                                && preceding_text_allows_autoclose
 4448                                && !is_closing_quote
 4449                            {
 4450                                let anchor = snapshot.anchor_before(selection.end);
 4451                                new_selections.push((selection.map(|_| anchor), text.len()));
 4452                                new_autoclose_regions.push((
 4453                                    anchor,
 4454                                    text.len(),
 4455                                    selection.id,
 4456                                    bracket_pair.clone(),
 4457                                ));
 4458                                edits.push((
 4459                                    selection.range(),
 4460                                    format!("{}{}", text, bracket_pair.end).into(),
 4461                                ));
 4462                                bracket_inserted = true;
 4463                                continue;
 4464                            }
 4465                        }
 4466
 4467                        if let Some(region) = autoclose_region {
 4468                            // If the selection is followed by an auto-inserted closing bracket,
 4469                            // then don't insert that closing bracket again; just move the selection
 4470                            // past the closing bracket.
 4471                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4472                                && text.as_ref() == region.pair.end.as_str()
 4473                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4474                            if should_skip {
 4475                                let anchor = snapshot.anchor_after(selection.end);
 4476                                new_selections
 4477                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4478                                continue;
 4479                            }
 4480                        }
 4481
 4482                        let always_treat_brackets_as_autoclosed = snapshot
 4483                            .language_settings_at(selection.start, cx)
 4484                            .always_treat_brackets_as_autoclosed;
 4485                        if always_treat_brackets_as_autoclosed
 4486                            && is_bracket_pair_end
 4487                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4488                        {
 4489                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4490                            // and the inserted text is a closing bracket and the selection is followed
 4491                            // by the closing bracket then move the selection past the closing bracket.
 4492                            let anchor = snapshot.anchor_after(selection.end);
 4493                            new_selections.push((selection.map(|_| anchor), text.len()));
 4494                            continue;
 4495                        }
 4496                    }
 4497                    // If an opening bracket is 1 character long and is typed while
 4498                    // text is selected, then surround that text with the bracket pair.
 4499                    else if auto_surround
 4500                        && bracket_pair.surround
 4501                        && is_bracket_pair_start
 4502                        && bracket_pair.start.chars().count() == 1
 4503                    {
 4504                        edits.push((selection.start..selection.start, text.clone()));
 4505                        edits.push((
 4506                            selection.end..selection.end,
 4507                            bracket_pair.end.as_str().into(),
 4508                        ));
 4509                        bracket_inserted = true;
 4510                        new_selections.push((
 4511                            Selection {
 4512                                id: selection.id,
 4513                                start: snapshot.anchor_after(selection.start),
 4514                                end: snapshot.anchor_before(selection.end),
 4515                                reversed: selection.reversed,
 4516                                goal: selection.goal,
 4517                            },
 4518                            0,
 4519                        ));
 4520                        continue;
 4521                    }
 4522                }
 4523            }
 4524
 4525            if self.auto_replace_emoji_shortcode
 4526                && selection.is_empty()
 4527                && text.as_ref().ends_with(':')
 4528                && let Some(possible_emoji_short_code) =
 4529                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4530                && !possible_emoji_short_code.is_empty()
 4531                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4532            {
 4533                let emoji_shortcode_start = Point::new(
 4534                    selection.start.row,
 4535                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4536                );
 4537
 4538                // Remove shortcode from buffer
 4539                edits.push((
 4540                    emoji_shortcode_start..selection.start,
 4541                    "".to_string().into(),
 4542                ));
 4543                new_selections.push((
 4544                    Selection {
 4545                        id: selection.id,
 4546                        start: snapshot.anchor_after(emoji_shortcode_start),
 4547                        end: snapshot.anchor_before(selection.start),
 4548                        reversed: selection.reversed,
 4549                        goal: selection.goal,
 4550                    },
 4551                    0,
 4552                ));
 4553
 4554                // Insert emoji
 4555                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4556                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4557                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4558
 4559                continue;
 4560            }
 4561
 4562            // If not handling any auto-close operation, then just replace the selected
 4563            // text with the given input and move the selection to the end of the
 4564            // newly inserted text.
 4565            let anchor = snapshot.anchor_after(selection.end);
 4566            if !self.linked_edit_ranges.is_empty() {
 4567                let start_anchor = snapshot.anchor_before(selection.start);
 4568
 4569                let is_word_char = text.chars().next().is_none_or(|char| {
 4570                    let classifier = snapshot
 4571                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4572                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4573                    classifier.is_word(char)
 4574                });
 4575
 4576                if is_word_char {
 4577                    if let Some(ranges) = self
 4578                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4579                    {
 4580                        for (buffer, edits) in ranges {
 4581                            linked_edits
 4582                                .entry(buffer.clone())
 4583                                .or_default()
 4584                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4585                        }
 4586                    }
 4587                } else {
 4588                    clear_linked_edit_ranges = true;
 4589                }
 4590            }
 4591
 4592            new_selections.push((selection.map(|_| anchor), 0));
 4593            edits.push((selection.start..selection.end, text.clone()));
 4594        }
 4595
 4596        drop(snapshot);
 4597
 4598        self.transact(window, cx, |this, window, cx| {
 4599            if clear_linked_edit_ranges {
 4600                this.linked_edit_ranges.clear();
 4601            }
 4602            let initial_buffer_versions =
 4603                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4604
 4605            this.buffer.update(cx, |buffer, cx| {
 4606                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4607            });
 4608            for (buffer, edits) in linked_edits {
 4609                buffer.update(cx, |buffer, cx| {
 4610                    let snapshot = buffer.snapshot();
 4611                    let edits = edits
 4612                        .into_iter()
 4613                        .map(|(range, text)| {
 4614                            use text::ToPoint as TP;
 4615                            let end_point = TP::to_point(&range.end, &snapshot);
 4616                            let start_point = TP::to_point(&range.start, &snapshot);
 4617                            (start_point..end_point, text)
 4618                        })
 4619                        .sorted_by_key(|(range, _)| range.start);
 4620                    buffer.edit(edits, None, cx);
 4621                })
 4622            }
 4623            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4624            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4625            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4626            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4627                new_anchor_selections,
 4628                &map,
 4629            )
 4630            .zip(new_selection_deltas)
 4631            .map(|(selection, delta)| Selection {
 4632                id: selection.id,
 4633                start: selection.start + delta,
 4634                end: selection.end + delta,
 4635                reversed: selection.reversed,
 4636                goal: SelectionGoal::None,
 4637            })
 4638            .collect::<Vec<_>>();
 4639
 4640            let mut i = 0;
 4641            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4642                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4643                let start = map.buffer_snapshot().anchor_before(position);
 4644                let end = map.buffer_snapshot().anchor_after(position);
 4645                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4646                    match existing_state
 4647                        .range
 4648                        .start
 4649                        .cmp(&start, map.buffer_snapshot())
 4650                    {
 4651                        Ordering::Less => i += 1,
 4652                        Ordering::Greater => break,
 4653                        Ordering::Equal => {
 4654                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4655                                Ordering::Less => i += 1,
 4656                                Ordering::Equal => break,
 4657                                Ordering::Greater => break,
 4658                            }
 4659                        }
 4660                    }
 4661                }
 4662                this.autoclose_regions.insert(
 4663                    i,
 4664                    AutocloseRegion {
 4665                        selection_id,
 4666                        range: start..end,
 4667                        pair,
 4668                    },
 4669                );
 4670            }
 4671
 4672            let had_active_edit_prediction = this.has_active_edit_prediction();
 4673            this.change_selections(
 4674                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4675                window,
 4676                cx,
 4677                |s| s.select(new_selections),
 4678            );
 4679
 4680            if !bracket_inserted
 4681                && let Some(on_type_format_task) =
 4682                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4683            {
 4684                on_type_format_task.detach_and_log_err(cx);
 4685            }
 4686
 4687            let editor_settings = EditorSettings::get_global(cx);
 4688            if bracket_inserted
 4689                && (editor_settings.auto_signature_help
 4690                    || editor_settings.show_signature_help_after_edits)
 4691            {
 4692                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4693            }
 4694
 4695            let trigger_in_words =
 4696                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4697            if this.hard_wrap.is_some() {
 4698                let latest: Range<Point> = this.selections.newest(&map).range();
 4699                if latest.is_empty()
 4700                    && this
 4701                        .buffer()
 4702                        .read(cx)
 4703                        .snapshot(cx)
 4704                        .line_len(MultiBufferRow(latest.start.row))
 4705                        == latest.start.column
 4706                {
 4707                    this.rewrap_impl(
 4708                        RewrapOptions {
 4709                            override_language_settings: true,
 4710                            preserve_existing_whitespace: true,
 4711                        },
 4712                        cx,
 4713                    )
 4714                }
 4715            }
 4716            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4717            refresh_linked_ranges(this, window, cx);
 4718            this.refresh_edit_prediction(true, false, window, cx);
 4719            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4720        });
 4721    }
 4722
 4723    fn find_possible_emoji_shortcode_at_position(
 4724        snapshot: &MultiBufferSnapshot,
 4725        position: Point,
 4726    ) -> Option<String> {
 4727        let mut chars = Vec::new();
 4728        let mut found_colon = false;
 4729        for char in snapshot.reversed_chars_at(position).take(100) {
 4730            // Found a possible emoji shortcode in the middle of the buffer
 4731            if found_colon {
 4732                if char.is_whitespace() {
 4733                    chars.reverse();
 4734                    return Some(chars.iter().collect());
 4735                }
 4736                // If the previous character is not a whitespace, we are in the middle of a word
 4737                // and we only want to complete the shortcode if the word is made up of other emojis
 4738                let mut containing_word = String::new();
 4739                for ch in snapshot
 4740                    .reversed_chars_at(position)
 4741                    .skip(chars.len() + 1)
 4742                    .take(100)
 4743                {
 4744                    if ch.is_whitespace() {
 4745                        break;
 4746                    }
 4747                    containing_word.push(ch);
 4748                }
 4749                let containing_word = containing_word.chars().rev().collect::<String>();
 4750                if util::word_consists_of_emojis(containing_word.as_str()) {
 4751                    chars.reverse();
 4752                    return Some(chars.iter().collect());
 4753                }
 4754            }
 4755
 4756            if char.is_whitespace() || !char.is_ascii() {
 4757                return None;
 4758            }
 4759            if char == ':' {
 4760                found_colon = true;
 4761            } else {
 4762                chars.push(char);
 4763            }
 4764        }
 4765        // Found a possible emoji shortcode at the beginning of the buffer
 4766        chars.reverse();
 4767        Some(chars.iter().collect())
 4768    }
 4769
 4770    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4771        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4772        self.transact(window, cx, |this, window, cx| {
 4773            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4774                let selections = this
 4775                    .selections
 4776                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4777                let multi_buffer = this.buffer.read(cx);
 4778                let buffer = multi_buffer.snapshot(cx);
 4779                selections
 4780                    .iter()
 4781                    .map(|selection| {
 4782                        let start_point = selection.start.to_point(&buffer);
 4783                        let mut existing_indent =
 4784                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4785                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4786                        let start = selection.start;
 4787                        let end = selection.end;
 4788                        let selection_is_empty = start == end;
 4789                        let language_scope = buffer.language_scope_at(start);
 4790                        let (comment_delimiter, doc_delimiter, newline_formatting) =
 4791                            if let Some(language) = &language_scope {
 4792                                let mut newline_formatting =
 4793                                    NewlineFormatting::new(&buffer, start..end, language);
 4794
 4795                                // Comment extension on newline is allowed only for cursor selections
 4796                                let comment_delimiter = maybe!({
 4797                                    if !selection_is_empty {
 4798                                        return None;
 4799                                    }
 4800
 4801                                    if !multi_buffer.language_settings(cx).extend_comment_on_newline
 4802                                    {
 4803                                        return None;
 4804                                    }
 4805
 4806                                    return comment_delimiter_for_newline(
 4807                                        &start_point,
 4808                                        &buffer,
 4809                                        language,
 4810                                    );
 4811                                });
 4812
 4813                                let doc_delimiter = maybe!({
 4814                                    if !selection_is_empty {
 4815                                        return None;
 4816                                    }
 4817
 4818                                    if !multi_buffer.language_settings(cx).extend_comment_on_newline
 4819                                    {
 4820                                        return None;
 4821                                    }
 4822
 4823                                    return documentation_delimiter_for_newline(
 4824                                        &start_point,
 4825                                        &buffer,
 4826                                        language,
 4827                                        &mut newline_formatting,
 4828                                    );
 4829                                });
 4830
 4831                                (comment_delimiter, doc_delimiter, newline_formatting)
 4832                            } else {
 4833                                (None, None, NewlineFormatting::default())
 4834                            };
 4835
 4836                        let prevent_auto_indent = doc_delimiter.is_some();
 4837                        let delimiter = comment_delimiter.or(doc_delimiter);
 4838
 4839                        let capacity_for_delimiter =
 4840                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4841                        let mut new_text = String::with_capacity(
 4842                            1 + capacity_for_delimiter
 4843                                + existing_indent.len as usize
 4844                                + newline_formatting.indent_on_newline.len as usize
 4845                                + newline_formatting.indent_on_extra_newline.len as usize,
 4846                        );
 4847                        new_text.push('\n');
 4848                        new_text.extend(existing_indent.chars());
 4849                        new_text.extend(newline_formatting.indent_on_newline.chars());
 4850
 4851                        if let Some(delimiter) = &delimiter {
 4852                            new_text.push_str(delimiter);
 4853                        }
 4854
 4855                        if newline_formatting.insert_extra_newline {
 4856                            new_text.push('\n');
 4857                            new_text.extend(existing_indent.chars());
 4858                            new_text.extend(newline_formatting.indent_on_extra_newline.chars());
 4859                        }
 4860
 4861                        let anchor = buffer.anchor_after(end);
 4862                        let new_selection = selection.map(|_| anchor);
 4863                        (
 4864                            ((start..end, new_text), prevent_auto_indent),
 4865                            (newline_formatting.insert_extra_newline, new_selection),
 4866                        )
 4867                    })
 4868                    .unzip()
 4869            };
 4870
 4871            let mut auto_indent_edits = Vec::new();
 4872            let mut edits = Vec::new();
 4873            for (edit, prevent_auto_indent) in edits_with_flags {
 4874                if prevent_auto_indent {
 4875                    edits.push(edit);
 4876                } else {
 4877                    auto_indent_edits.push(edit);
 4878                }
 4879            }
 4880            if !edits.is_empty() {
 4881                this.edit(edits, cx);
 4882            }
 4883            if !auto_indent_edits.is_empty() {
 4884                this.edit_with_autoindent(auto_indent_edits, cx);
 4885            }
 4886
 4887            let buffer = this.buffer.read(cx).snapshot(cx);
 4888            let new_selections = selection_info
 4889                .into_iter()
 4890                .map(|(extra_newline_inserted, new_selection)| {
 4891                    let mut cursor = new_selection.end.to_point(&buffer);
 4892                    if extra_newline_inserted {
 4893                        cursor.row -= 1;
 4894                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4895                    }
 4896                    new_selection.map(|_| cursor)
 4897                })
 4898                .collect();
 4899
 4900            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4901            this.refresh_edit_prediction(true, false, window, cx);
 4902            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 4903                task.detach_and_log_err(cx);
 4904            }
 4905        });
 4906    }
 4907
 4908    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4909        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4910
 4911        let buffer = self.buffer.read(cx);
 4912        let snapshot = buffer.snapshot(cx);
 4913
 4914        let mut edits = Vec::new();
 4915        let mut rows = Vec::new();
 4916
 4917        for (rows_inserted, selection) in self
 4918            .selections
 4919            .all_adjusted(&self.display_snapshot(cx))
 4920            .into_iter()
 4921            .enumerate()
 4922        {
 4923            let cursor = selection.head();
 4924            let row = cursor.row;
 4925
 4926            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4927
 4928            let newline = "\n".to_string();
 4929            edits.push((start_of_line..start_of_line, newline));
 4930
 4931            rows.push(row + rows_inserted as u32);
 4932        }
 4933
 4934        self.transact(window, cx, |editor, window, cx| {
 4935            editor.edit(edits, cx);
 4936
 4937            editor.change_selections(Default::default(), window, cx, |s| {
 4938                let mut index = 0;
 4939                s.move_cursors_with(|map, _, _| {
 4940                    let row = rows[index];
 4941                    index += 1;
 4942
 4943                    let point = Point::new(row, 0);
 4944                    let boundary = map.next_line_boundary(point).1;
 4945                    let clipped = map.clip_point(boundary, Bias::Left);
 4946
 4947                    (clipped, SelectionGoal::None)
 4948                });
 4949            });
 4950
 4951            let mut indent_edits = Vec::new();
 4952            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4953            for row in rows {
 4954                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4955                for (row, indent) in indents {
 4956                    if indent.len == 0 {
 4957                        continue;
 4958                    }
 4959
 4960                    let text = match indent.kind {
 4961                        IndentKind::Space => " ".repeat(indent.len as usize),
 4962                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4963                    };
 4964                    let point = Point::new(row.0, 0);
 4965                    indent_edits.push((point..point, text));
 4966                }
 4967            }
 4968            editor.edit(indent_edits, cx);
 4969            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 4970                format.detach_and_log_err(cx);
 4971            }
 4972        });
 4973    }
 4974
 4975    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4976        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4977
 4978        let buffer = self.buffer.read(cx);
 4979        let snapshot = buffer.snapshot(cx);
 4980
 4981        let mut edits = Vec::new();
 4982        let mut rows = Vec::new();
 4983        let mut rows_inserted = 0;
 4984
 4985        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4986            let cursor = selection.head();
 4987            let row = cursor.row;
 4988
 4989            let point = Point::new(row + 1, 0);
 4990            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4991
 4992            let newline = "\n".to_string();
 4993            edits.push((start_of_line..start_of_line, newline));
 4994
 4995            rows_inserted += 1;
 4996            rows.push(row + rows_inserted);
 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 insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5041        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5042            original_indent_columns: Vec::new(),
 5043        });
 5044        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5045    }
 5046
 5047    fn insert_with_autoindent_mode(
 5048        &mut self,
 5049        text: &str,
 5050        autoindent_mode: Option<AutoindentMode>,
 5051        window: &mut Window,
 5052        cx: &mut Context<Self>,
 5053    ) {
 5054        if self.read_only(cx) {
 5055            return;
 5056        }
 5057
 5058        let text: Arc<str> = text.into();
 5059        self.transact(window, cx, |this, window, cx| {
 5060            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5061            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5062                let anchors = {
 5063                    let snapshot = buffer.read(cx);
 5064                    old_selections
 5065                        .iter()
 5066                        .map(|s| {
 5067                            let anchor = snapshot.anchor_after(s.head());
 5068                            s.map(|_| anchor)
 5069                        })
 5070                        .collect::<Vec<_>>()
 5071                };
 5072                buffer.edit(
 5073                    old_selections
 5074                        .iter()
 5075                        .map(|s| (s.start..s.end, text.clone())),
 5076                    autoindent_mode,
 5077                    cx,
 5078                );
 5079                anchors
 5080            });
 5081
 5082            this.change_selections(Default::default(), window, cx, |s| {
 5083                s.select_anchors(selection_anchors);
 5084            });
 5085
 5086            cx.notify();
 5087        });
 5088    }
 5089
 5090    fn trigger_completion_on_input(
 5091        &mut self,
 5092        text: &str,
 5093        trigger_in_words: bool,
 5094        window: &mut Window,
 5095        cx: &mut Context<Self>,
 5096    ) {
 5097        let completions_source = self
 5098            .context_menu
 5099            .borrow()
 5100            .as_ref()
 5101            .and_then(|menu| match menu {
 5102                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5103                CodeContextMenu::CodeActions(_) => None,
 5104            });
 5105
 5106        match completions_source {
 5107            Some(CompletionsMenuSource::Words { .. }) => {
 5108                self.open_or_update_completions_menu(
 5109                    Some(CompletionsMenuSource::Words {
 5110                        ignore_threshold: false,
 5111                    }),
 5112                    None,
 5113                    trigger_in_words,
 5114                    window,
 5115                    cx,
 5116                );
 5117            }
 5118            _ => self.open_or_update_completions_menu(
 5119                None,
 5120                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5121                true,
 5122                window,
 5123                cx,
 5124            ),
 5125        }
 5126    }
 5127
 5128    /// If any empty selections is touching the start of its innermost containing autoclose
 5129    /// region, expand it to select the brackets.
 5130    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5131        let selections = self
 5132            .selections
 5133            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5134        let buffer = self.buffer.read(cx).read(cx);
 5135        let new_selections = self
 5136            .selections_with_autoclose_regions(selections, &buffer)
 5137            .map(|(mut selection, region)| {
 5138                if !selection.is_empty() {
 5139                    return selection;
 5140                }
 5141
 5142                if let Some(region) = region {
 5143                    let mut range = region.range.to_offset(&buffer);
 5144                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5145                        range.start -= region.pair.start.len();
 5146                        if buffer.contains_str_at(range.start, &region.pair.start)
 5147                            && buffer.contains_str_at(range.end, &region.pair.end)
 5148                        {
 5149                            range.end += region.pair.end.len();
 5150                            selection.start = range.start;
 5151                            selection.end = range.end;
 5152
 5153                            return selection;
 5154                        }
 5155                    }
 5156                }
 5157
 5158                let always_treat_brackets_as_autoclosed = buffer
 5159                    .language_settings_at(selection.start, cx)
 5160                    .always_treat_brackets_as_autoclosed;
 5161
 5162                if !always_treat_brackets_as_autoclosed {
 5163                    return selection;
 5164                }
 5165
 5166                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5167                    for (pair, enabled) in scope.brackets() {
 5168                        if !enabled || !pair.close {
 5169                            continue;
 5170                        }
 5171
 5172                        if buffer.contains_str_at(selection.start, &pair.end) {
 5173                            let pair_start_len = pair.start.len();
 5174                            if buffer.contains_str_at(
 5175                                selection.start.saturating_sub_usize(pair_start_len),
 5176                                &pair.start,
 5177                            ) {
 5178                                selection.start -= pair_start_len;
 5179                                selection.end += pair.end.len();
 5180
 5181                                return selection;
 5182                            }
 5183                        }
 5184                    }
 5185                }
 5186
 5187                selection
 5188            })
 5189            .collect();
 5190
 5191        drop(buffer);
 5192        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5193            selections.select(new_selections)
 5194        });
 5195    }
 5196
 5197    /// Iterate the given selections, and for each one, find the smallest surrounding
 5198    /// autoclose region. This uses the ordering of the selections and the autoclose
 5199    /// regions to avoid repeated comparisons.
 5200    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5201        &'a self,
 5202        selections: impl IntoIterator<Item = Selection<D>>,
 5203        buffer: &'a MultiBufferSnapshot,
 5204    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5205        let mut i = 0;
 5206        let mut regions = self.autoclose_regions.as_slice();
 5207        selections.into_iter().map(move |selection| {
 5208            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5209
 5210            let mut enclosing = None;
 5211            while let Some(pair_state) = regions.get(i) {
 5212                if pair_state.range.end.to_offset(buffer) < range.start {
 5213                    regions = &regions[i + 1..];
 5214                    i = 0;
 5215                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5216                    break;
 5217                } else {
 5218                    if pair_state.selection_id == selection.id {
 5219                        enclosing = Some(pair_state);
 5220                    }
 5221                    i += 1;
 5222                }
 5223            }
 5224
 5225            (selection, enclosing)
 5226        })
 5227    }
 5228
 5229    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5230    fn invalidate_autoclose_regions(
 5231        &mut self,
 5232        mut selections: &[Selection<Anchor>],
 5233        buffer: &MultiBufferSnapshot,
 5234    ) {
 5235        self.autoclose_regions.retain(|state| {
 5236            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5237                return false;
 5238            }
 5239
 5240            let mut i = 0;
 5241            while let Some(selection) = selections.get(i) {
 5242                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5243                    selections = &selections[1..];
 5244                    continue;
 5245                }
 5246                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5247                    break;
 5248                }
 5249                if selection.id == state.selection_id {
 5250                    return true;
 5251                } else {
 5252                    i += 1;
 5253                }
 5254            }
 5255            false
 5256        });
 5257    }
 5258
 5259    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5260        let offset = position.to_offset(buffer);
 5261        let (word_range, kind) =
 5262            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5263        if offset > word_range.start && kind == Some(CharKind::Word) {
 5264            Some(
 5265                buffer
 5266                    .text_for_range(word_range.start..offset)
 5267                    .collect::<String>(),
 5268            )
 5269        } else {
 5270            None
 5271        }
 5272    }
 5273
 5274    pub fn visible_excerpts(
 5275        &self,
 5276        lsp_related_only: bool,
 5277        cx: &mut Context<Editor>,
 5278    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5279        let project = self.project().cloned();
 5280        let multi_buffer = self.buffer().read(cx);
 5281        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5282        let multi_buffer_visible_start = self
 5283            .scroll_manager
 5284            .anchor()
 5285            .anchor
 5286            .to_point(&multi_buffer_snapshot);
 5287        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5288            multi_buffer_visible_start
 5289                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5290            Bias::Left,
 5291        );
 5292        multi_buffer_snapshot
 5293            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5294            .into_iter()
 5295            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5296            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5297                if !lsp_related_only {
 5298                    return Some((
 5299                        excerpt_id,
 5300                        (
 5301                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5302                            buffer.version().clone(),
 5303                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5304                        ),
 5305                    ));
 5306                }
 5307
 5308                let project = project.as_ref()?.read(cx);
 5309                let buffer_file = project::File::from_dyn(buffer.file())?;
 5310                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5311                let worktree_entry = buffer_worktree
 5312                    .read(cx)
 5313                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5314                if worktree_entry.is_ignored {
 5315                    None
 5316                } else {
 5317                    Some((
 5318                        excerpt_id,
 5319                        (
 5320                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5321                            buffer.version().clone(),
 5322                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5323                        ),
 5324                    ))
 5325                }
 5326            })
 5327            .collect()
 5328    }
 5329
 5330    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5331        TextLayoutDetails {
 5332            text_system: window.text_system().clone(),
 5333            editor_style: self.style.clone().unwrap(),
 5334            rem_size: window.rem_size(),
 5335            scroll_anchor: self.scroll_manager.anchor(),
 5336            visible_rows: self.visible_line_count(),
 5337            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5338        }
 5339    }
 5340
 5341    fn trigger_on_type_formatting(
 5342        &self,
 5343        input: String,
 5344        window: &mut Window,
 5345        cx: &mut Context<Self>,
 5346    ) -> Option<Task<Result<()>>> {
 5347        if input.chars().count() != 1 {
 5348            return None;
 5349        }
 5350
 5351        let project = self.project()?;
 5352        let position = self.selections.newest_anchor().head();
 5353        let (buffer, buffer_position) = self
 5354            .buffer
 5355            .read(cx)
 5356            .text_anchor_for_position(position, cx)?;
 5357
 5358        let settings = language_settings::language_settings(
 5359            buffer
 5360                .read(cx)
 5361                .language_at(buffer_position)
 5362                .map(|l| l.name()),
 5363            buffer.read(cx).file(),
 5364            cx,
 5365        );
 5366        if !settings.use_on_type_format {
 5367            return None;
 5368        }
 5369
 5370        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5371        // hence we do LSP request & edit on host side only — add formats to host's history.
 5372        let push_to_lsp_host_history = true;
 5373        // If this is not the host, append its history with new edits.
 5374        let push_to_client_history = project.read(cx).is_via_collab();
 5375
 5376        let on_type_formatting = project.update(cx, |project, cx| {
 5377            project.on_type_format(
 5378                buffer.clone(),
 5379                buffer_position,
 5380                input,
 5381                push_to_lsp_host_history,
 5382                cx,
 5383            )
 5384        });
 5385        Some(cx.spawn_in(window, async move |editor, cx| {
 5386            if let Some(transaction) = on_type_formatting.await? {
 5387                if push_to_client_history {
 5388                    buffer
 5389                        .update(cx, |buffer, _| {
 5390                            buffer.push_transaction(transaction, Instant::now());
 5391                            buffer.finalize_last_transaction();
 5392                        })
 5393                        .ok();
 5394                }
 5395                editor.update(cx, |editor, cx| {
 5396                    editor.refresh_document_highlights(cx);
 5397                })?;
 5398            }
 5399            Ok(())
 5400        }))
 5401    }
 5402
 5403    pub fn show_word_completions(
 5404        &mut self,
 5405        _: &ShowWordCompletions,
 5406        window: &mut Window,
 5407        cx: &mut Context<Self>,
 5408    ) {
 5409        self.open_or_update_completions_menu(
 5410            Some(CompletionsMenuSource::Words {
 5411                ignore_threshold: true,
 5412            }),
 5413            None,
 5414            false,
 5415            window,
 5416            cx,
 5417        );
 5418    }
 5419
 5420    pub fn show_completions(
 5421        &mut self,
 5422        _: &ShowCompletions,
 5423        window: &mut Window,
 5424        cx: &mut Context<Self>,
 5425    ) {
 5426        self.open_or_update_completions_menu(None, None, false, window, cx);
 5427    }
 5428
 5429    fn open_or_update_completions_menu(
 5430        &mut self,
 5431        requested_source: Option<CompletionsMenuSource>,
 5432        trigger: Option<String>,
 5433        trigger_in_words: bool,
 5434        window: &mut Window,
 5435        cx: &mut Context<Self>,
 5436    ) {
 5437        if self.pending_rename.is_some() {
 5438            return;
 5439        }
 5440
 5441        let completions_source = self
 5442            .context_menu
 5443            .borrow()
 5444            .as_ref()
 5445            .and_then(|menu| match menu {
 5446                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5447                CodeContextMenu::CodeActions(_) => None,
 5448            });
 5449
 5450        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5451
 5452        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5453        // inserted and selected. To handle that case, the start of the selection is used so that
 5454        // the menu starts with all choices.
 5455        let position = self
 5456            .selections
 5457            .newest_anchor()
 5458            .start
 5459            .bias_right(&multibuffer_snapshot);
 5460        if position.diff_base_anchor.is_some() {
 5461            return;
 5462        }
 5463        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5464        let Some(buffer) = buffer_position
 5465            .text_anchor
 5466            .buffer_id
 5467            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5468        else {
 5469            return;
 5470        };
 5471        let buffer_snapshot = buffer.read(cx).snapshot();
 5472
 5473        let menu_is_open = matches!(
 5474            self.context_menu.borrow().as_ref(),
 5475            Some(CodeContextMenu::Completions(_))
 5476        );
 5477
 5478        let language = buffer_snapshot
 5479            .language_at(buffer_position.text_anchor)
 5480            .map(|language| language.name());
 5481
 5482        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5483        let completion_settings = language_settings.completions.clone();
 5484
 5485        let show_completions_on_input = self
 5486            .show_completions_on_input_override
 5487            .unwrap_or(language_settings.show_completions_on_input);
 5488        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5489            return;
 5490        }
 5491
 5492        let query: Option<Arc<String>> =
 5493            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5494                .map(|query| query.into());
 5495
 5496        drop(multibuffer_snapshot);
 5497
 5498        // Hide the current completions menu when query is empty. Without this, cached
 5499        // completions from before the trigger char may be reused (#32774).
 5500        if query.is_none() && menu_is_open {
 5501            self.hide_context_menu(window, cx);
 5502        }
 5503
 5504        let mut ignore_word_threshold = false;
 5505        let provider = match requested_source {
 5506            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5507            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5508                ignore_word_threshold = ignore_threshold;
 5509                None
 5510            }
 5511            Some(CompletionsMenuSource::SnippetChoices)
 5512            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5513                log::error!("bug: SnippetChoices requested_source is not handled");
 5514                None
 5515            }
 5516        };
 5517
 5518        let sort_completions = provider
 5519            .as_ref()
 5520            .is_some_and(|provider| provider.sort_completions());
 5521
 5522        let filter_completions = provider
 5523            .as_ref()
 5524            .is_none_or(|provider| provider.filter_completions());
 5525
 5526        let was_snippets_only = matches!(
 5527            completions_source,
 5528            Some(CompletionsMenuSource::SnippetsOnly)
 5529        );
 5530
 5531        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5532            if filter_completions {
 5533                menu.filter(
 5534                    query.clone().unwrap_or_default(),
 5535                    buffer_position.text_anchor,
 5536                    &buffer,
 5537                    provider.clone(),
 5538                    window,
 5539                    cx,
 5540                );
 5541            }
 5542            // When `is_incomplete` is false, no need to re-query completions when the current query
 5543            // is a suffix of the initial query.
 5544            let was_complete = !menu.is_incomplete;
 5545            if was_complete && !was_snippets_only {
 5546                // If the new query is a suffix of the old query (typing more characters) and
 5547                // the previous result was complete, the existing completions can be filtered.
 5548                //
 5549                // Note that snippet completions are always complete.
 5550                let query_matches = match (&menu.initial_query, &query) {
 5551                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5552                    (None, _) => true,
 5553                    _ => false,
 5554                };
 5555                if query_matches {
 5556                    let position_matches = if menu.initial_position == position {
 5557                        true
 5558                    } else {
 5559                        let snapshot = self.buffer.read(cx).read(cx);
 5560                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5561                    };
 5562                    if position_matches {
 5563                        return;
 5564                    }
 5565                }
 5566            }
 5567        };
 5568
 5569        let Anchor {
 5570            excerpt_id: buffer_excerpt_id,
 5571            text_anchor: buffer_position,
 5572            ..
 5573        } = buffer_position;
 5574
 5575        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5576            buffer_snapshot.surrounding_word(buffer_position, None)
 5577        {
 5578            let word_to_exclude = buffer_snapshot
 5579                .text_for_range(word_range.clone())
 5580                .collect::<String>();
 5581            (
 5582                buffer_snapshot.anchor_before(word_range.start)
 5583                    ..buffer_snapshot.anchor_after(buffer_position),
 5584                Some(word_to_exclude),
 5585            )
 5586        } else {
 5587            (buffer_position..buffer_position, None)
 5588        };
 5589
 5590        let show_completion_documentation = buffer_snapshot
 5591            .settings_at(buffer_position, cx)
 5592            .show_completion_documentation;
 5593
 5594        // The document can be large, so stay in reasonable bounds when searching for words,
 5595        // otherwise completion pop-up might be slow to appear.
 5596        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5597        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5598        let min_word_search = buffer_snapshot.clip_point(
 5599            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5600            Bias::Left,
 5601        );
 5602        let max_word_search = buffer_snapshot.clip_point(
 5603            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5604            Bias::Right,
 5605        );
 5606        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5607            ..buffer_snapshot.point_to_offset(max_word_search);
 5608
 5609        let skip_digits = query
 5610            .as_ref()
 5611            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5612
 5613        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5614            trigger.as_ref().is_none_or(|trigger| {
 5615                provider.is_completion_trigger(
 5616                    &buffer,
 5617                    position.text_anchor,
 5618                    trigger,
 5619                    trigger_in_words,
 5620                    cx,
 5621                )
 5622            })
 5623        });
 5624
 5625        let provider_responses = if let Some(provider) = &provider
 5626            && load_provider_completions
 5627        {
 5628            let trigger_character =
 5629                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5630            let completion_context = CompletionContext {
 5631                trigger_kind: match &trigger_character {
 5632                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5633                    None => CompletionTriggerKind::INVOKED,
 5634                },
 5635                trigger_character,
 5636            };
 5637
 5638            provider.completions(
 5639                buffer_excerpt_id,
 5640                &buffer,
 5641                buffer_position,
 5642                completion_context,
 5643                window,
 5644                cx,
 5645            )
 5646        } else {
 5647            Task::ready(Ok(Vec::new()))
 5648        };
 5649
 5650        let load_word_completions = if !self.word_completions_enabled {
 5651            false
 5652        } else if requested_source
 5653            == Some(CompletionsMenuSource::Words {
 5654                ignore_threshold: true,
 5655            })
 5656        {
 5657            true
 5658        } else {
 5659            load_provider_completions
 5660                && completion_settings.words != WordsCompletionMode::Disabled
 5661                && (ignore_word_threshold || {
 5662                    let words_min_length = completion_settings.words_min_length;
 5663                    // check whether word has at least `words_min_length` characters
 5664                    let query_chars = query.iter().flat_map(|q| q.chars());
 5665                    query_chars.take(words_min_length).count() == words_min_length
 5666                })
 5667        };
 5668
 5669        let mut words = if load_word_completions {
 5670            cx.background_spawn({
 5671                let buffer_snapshot = buffer_snapshot.clone();
 5672                async move {
 5673                    buffer_snapshot.words_in_range(WordsQuery {
 5674                        fuzzy_contents: None,
 5675                        range: word_search_range,
 5676                        skip_digits,
 5677                    })
 5678                }
 5679            })
 5680        } else {
 5681            Task::ready(BTreeMap::default())
 5682        };
 5683
 5684        let snippets = if let Some(provider) = &provider
 5685            && provider.show_snippets()
 5686            && let Some(project) = self.project()
 5687        {
 5688            let char_classifier = buffer_snapshot
 5689                .char_classifier_at(buffer_position)
 5690                .scope_context(Some(CharScopeContext::Completion));
 5691            project.update(cx, |project, cx| {
 5692                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5693            })
 5694        } else {
 5695            Task::ready(Ok(CompletionResponse {
 5696                completions: Vec::new(),
 5697                display_options: Default::default(),
 5698                is_incomplete: false,
 5699            }))
 5700        };
 5701
 5702        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5703
 5704        let id = post_inc(&mut self.next_completion_id);
 5705        let task = cx.spawn_in(window, async move |editor, cx| {
 5706            let Ok(()) = editor.update(cx, |this, _| {
 5707                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5708            }) else {
 5709                return;
 5710            };
 5711
 5712            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5713            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5714            let mut completions = Vec::new();
 5715            let mut is_incomplete = false;
 5716            let mut display_options: Option<CompletionDisplayOptions> = None;
 5717            if let Some(provider_responses) = provider_responses.await.log_err()
 5718                && !provider_responses.is_empty()
 5719            {
 5720                for response in provider_responses {
 5721                    completions.extend(response.completions);
 5722                    is_incomplete = is_incomplete || response.is_incomplete;
 5723                    match display_options.as_mut() {
 5724                        None => {
 5725                            display_options = Some(response.display_options);
 5726                        }
 5727                        Some(options) => options.merge(&response.display_options),
 5728                    }
 5729                }
 5730                if completion_settings.words == WordsCompletionMode::Fallback {
 5731                    words = Task::ready(BTreeMap::default());
 5732                }
 5733            }
 5734            let display_options = display_options.unwrap_or_default();
 5735
 5736            let mut words = words.await;
 5737            if let Some(word_to_exclude) = &word_to_exclude {
 5738                words.remove(word_to_exclude);
 5739            }
 5740            for lsp_completion in &completions {
 5741                words.remove(&lsp_completion.new_text);
 5742            }
 5743            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5744                replace_range: word_replace_range.clone(),
 5745                new_text: word.clone(),
 5746                label: CodeLabel::plain(word, None),
 5747                match_start: None,
 5748                snippet_deduplication_key: None,
 5749                icon_path: None,
 5750                documentation: None,
 5751                source: CompletionSource::BufferWord {
 5752                    word_range,
 5753                    resolved: false,
 5754                },
 5755                insert_text_mode: Some(InsertTextMode::AS_IS),
 5756                confirm: None,
 5757            }));
 5758
 5759            completions.extend(
 5760                snippets
 5761                    .await
 5762                    .into_iter()
 5763                    .flat_map(|response| response.completions),
 5764            );
 5765
 5766            let menu = if completions.is_empty() {
 5767                None
 5768            } else {
 5769                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5770                    let languages = editor
 5771                        .workspace
 5772                        .as_ref()
 5773                        .and_then(|(workspace, _)| workspace.upgrade())
 5774                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5775                    let menu = CompletionsMenu::new(
 5776                        id,
 5777                        requested_source.unwrap_or(if load_provider_completions {
 5778                            CompletionsMenuSource::Normal
 5779                        } else {
 5780                            CompletionsMenuSource::SnippetsOnly
 5781                        }),
 5782                        sort_completions,
 5783                        show_completion_documentation,
 5784                        position,
 5785                        query.clone(),
 5786                        is_incomplete,
 5787                        buffer.clone(),
 5788                        completions.into(),
 5789                        editor
 5790                            .context_menu()
 5791                            .borrow_mut()
 5792                            .as_ref()
 5793                            .map(|menu| menu.primary_scroll_handle()),
 5794                        display_options,
 5795                        snippet_sort_order,
 5796                        languages,
 5797                        language,
 5798                        cx,
 5799                    );
 5800
 5801                    let query = if filter_completions { query } else { None };
 5802                    let matches_task = menu.do_async_filtering(
 5803                        query.unwrap_or_default(),
 5804                        buffer_position,
 5805                        &buffer,
 5806                        cx,
 5807                    );
 5808                    (menu, matches_task)
 5809                }) else {
 5810                    return;
 5811                };
 5812
 5813                let matches = matches_task.await;
 5814
 5815                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5816                    // Newer menu already set, so exit.
 5817                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5818                        editor.context_menu.borrow().as_ref()
 5819                        && prev_menu.id > id
 5820                    {
 5821                        return;
 5822                    };
 5823
 5824                    // Only valid to take prev_menu because either the new menu is immediately set
 5825                    // below, or the menu is hidden.
 5826                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5827                        editor.context_menu.borrow_mut().take()
 5828                    {
 5829                        let position_matches =
 5830                            if prev_menu.initial_position == menu.initial_position {
 5831                                true
 5832                            } else {
 5833                                let snapshot = editor.buffer.read(cx).read(cx);
 5834                                prev_menu.initial_position.to_offset(&snapshot)
 5835                                    == menu.initial_position.to_offset(&snapshot)
 5836                            };
 5837                        if position_matches {
 5838                            // Preserve markdown cache before `set_filter_results` because it will
 5839                            // try to populate the documentation cache.
 5840                            menu.preserve_markdown_cache(prev_menu);
 5841                        }
 5842                    };
 5843
 5844                    menu.set_filter_results(matches, provider, window, cx);
 5845                }) else {
 5846                    return;
 5847                };
 5848
 5849                menu.visible().then_some(menu)
 5850            };
 5851
 5852            editor
 5853                .update_in(cx, |editor, window, cx| {
 5854                    if editor.focus_handle.is_focused(window)
 5855                        && let Some(menu) = menu
 5856                    {
 5857                        *editor.context_menu.borrow_mut() =
 5858                            Some(CodeContextMenu::Completions(menu));
 5859
 5860                        crate::hover_popover::hide_hover(editor, cx);
 5861                        if editor.show_edit_predictions_in_menu() {
 5862                            editor.update_visible_edit_prediction(window, cx);
 5863                        } else {
 5864                            editor.discard_edit_prediction(false, cx);
 5865                        }
 5866
 5867                        cx.notify();
 5868                        return;
 5869                    }
 5870
 5871                    if editor.completion_tasks.len() <= 1 {
 5872                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5873                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5874                        // If it was already hidden and we don't show edit predictions in the menu,
 5875                        // we should also show the edit prediction when available.
 5876                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5877                            editor.update_visible_edit_prediction(window, cx);
 5878                        }
 5879                    }
 5880                })
 5881                .ok();
 5882        });
 5883
 5884        self.completion_tasks.push((id, task));
 5885    }
 5886
 5887    #[cfg(feature = "test-support")]
 5888    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5889        let menu = self.context_menu.borrow();
 5890        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5891            let completions = menu.completions.borrow();
 5892            Some(completions.to_vec())
 5893        } else {
 5894            None
 5895        }
 5896    }
 5897
 5898    pub fn with_completions_menu_matching_id<R>(
 5899        &self,
 5900        id: CompletionId,
 5901        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5902    ) -> R {
 5903        let mut context_menu = self.context_menu.borrow_mut();
 5904        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5905            return f(None);
 5906        };
 5907        if completions_menu.id != id {
 5908            return f(None);
 5909        }
 5910        f(Some(completions_menu))
 5911    }
 5912
 5913    pub fn confirm_completion(
 5914        &mut self,
 5915        action: &ConfirmCompletion,
 5916        window: &mut Window,
 5917        cx: &mut Context<Self>,
 5918    ) -> Option<Task<Result<()>>> {
 5919        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5920        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5921    }
 5922
 5923    pub fn confirm_completion_insert(
 5924        &mut self,
 5925        _: &ConfirmCompletionInsert,
 5926        window: &mut Window,
 5927        cx: &mut Context<Self>,
 5928    ) -> Option<Task<Result<()>>> {
 5929        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5930        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5931    }
 5932
 5933    pub fn confirm_completion_replace(
 5934        &mut self,
 5935        _: &ConfirmCompletionReplace,
 5936        window: &mut Window,
 5937        cx: &mut Context<Self>,
 5938    ) -> Option<Task<Result<()>>> {
 5939        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5940        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5941    }
 5942
 5943    pub fn compose_completion(
 5944        &mut self,
 5945        action: &ComposeCompletion,
 5946        window: &mut Window,
 5947        cx: &mut Context<Self>,
 5948    ) -> Option<Task<Result<()>>> {
 5949        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5950        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5951    }
 5952
 5953    fn do_completion(
 5954        &mut self,
 5955        item_ix: Option<usize>,
 5956        intent: CompletionIntent,
 5957        window: &mut Window,
 5958        cx: &mut Context<Editor>,
 5959    ) -> Option<Task<Result<()>>> {
 5960        use language::ToOffset as _;
 5961
 5962        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5963        else {
 5964            return None;
 5965        };
 5966
 5967        let candidate_id = {
 5968            let entries = completions_menu.entries.borrow();
 5969            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5970            if self.show_edit_predictions_in_menu() {
 5971                self.discard_edit_prediction(true, cx);
 5972            }
 5973            mat.candidate_id
 5974        };
 5975
 5976        let completion = completions_menu
 5977            .completions
 5978            .borrow()
 5979            .get(candidate_id)?
 5980            .clone();
 5981        cx.stop_propagation();
 5982
 5983        let buffer_handle = completions_menu.buffer.clone();
 5984
 5985        let CompletionEdit {
 5986            new_text,
 5987            snippet,
 5988            replace_range,
 5989        } = process_completion_for_edit(
 5990            &completion,
 5991            intent,
 5992            &buffer_handle,
 5993            &completions_menu.initial_position.text_anchor,
 5994            cx,
 5995        );
 5996
 5997        let buffer = buffer_handle.read(cx);
 5998        let snapshot = self.buffer.read(cx).snapshot(cx);
 5999        let newest_anchor = self.selections.newest_anchor();
 6000        let replace_range_multibuffer = {
 6001            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6002            excerpt.map_range_from_buffer(replace_range.clone())
 6003        };
 6004        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6005            return None;
 6006        }
 6007
 6008        let old_text = buffer
 6009            .text_for_range(replace_range.clone())
 6010            .collect::<String>();
 6011        let lookbehind = newest_anchor
 6012            .start
 6013            .text_anchor
 6014            .to_offset(buffer)
 6015            .saturating_sub(replace_range.start.0);
 6016        let lookahead = replace_range
 6017            .end
 6018            .0
 6019            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6020        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6021        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6022
 6023        let selections = self
 6024            .selections
 6025            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6026        let mut ranges = Vec::new();
 6027        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6028
 6029        for selection in &selections {
 6030            let range = if selection.id == newest_anchor.id {
 6031                replace_range_multibuffer.clone()
 6032            } else {
 6033                let mut range = selection.range();
 6034
 6035                // if prefix is present, don't duplicate it
 6036                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6037                    range.start = range.start.saturating_sub_usize(lookbehind);
 6038
 6039                    // if suffix is also present, mimic the newest cursor and replace it
 6040                    if selection.id != newest_anchor.id
 6041                        && snapshot.contains_str_at(range.end, suffix)
 6042                    {
 6043                        range.end += lookahead;
 6044                    }
 6045                }
 6046                range
 6047            };
 6048
 6049            ranges.push(range.clone());
 6050
 6051            if !self.linked_edit_ranges.is_empty() {
 6052                let start_anchor = snapshot.anchor_before(range.start);
 6053                let end_anchor = snapshot.anchor_after(range.end);
 6054                if let Some(ranges) = self
 6055                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6056                {
 6057                    for (buffer, edits) in ranges {
 6058                        linked_edits
 6059                            .entry(buffer.clone())
 6060                            .or_default()
 6061                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6062                    }
 6063                }
 6064            }
 6065        }
 6066
 6067        let common_prefix_len = old_text
 6068            .chars()
 6069            .zip(new_text.chars())
 6070            .take_while(|(a, b)| a == b)
 6071            .map(|(a, _)| a.len_utf8())
 6072            .sum::<usize>();
 6073
 6074        cx.emit(EditorEvent::InputHandled {
 6075            utf16_range_to_replace: None,
 6076            text: new_text[common_prefix_len..].into(),
 6077        });
 6078
 6079        self.transact(window, cx, |editor, window, cx| {
 6080            if let Some(mut snippet) = snippet {
 6081                snippet.text = new_text.to_string();
 6082                editor
 6083                    .insert_snippet(&ranges, snippet, window, cx)
 6084                    .log_err();
 6085            } else {
 6086                editor.buffer.update(cx, |multi_buffer, cx| {
 6087                    let auto_indent = match completion.insert_text_mode {
 6088                        Some(InsertTextMode::AS_IS) => None,
 6089                        _ => editor.autoindent_mode.clone(),
 6090                    };
 6091                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6092                    multi_buffer.edit(edits, auto_indent, cx);
 6093                });
 6094            }
 6095            for (buffer, edits) in linked_edits {
 6096                buffer.update(cx, |buffer, cx| {
 6097                    let snapshot = buffer.snapshot();
 6098                    let edits = edits
 6099                        .into_iter()
 6100                        .map(|(range, text)| {
 6101                            use text::ToPoint as TP;
 6102                            let end_point = TP::to_point(&range.end, &snapshot);
 6103                            let start_point = TP::to_point(&range.start, &snapshot);
 6104                            (start_point..end_point, text)
 6105                        })
 6106                        .sorted_by_key(|(range, _)| range.start);
 6107                    buffer.edit(edits, None, cx);
 6108                })
 6109            }
 6110
 6111            editor.refresh_edit_prediction(true, false, window, cx);
 6112        });
 6113        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6114
 6115        let show_new_completions_on_confirm = completion
 6116            .confirm
 6117            .as_ref()
 6118            .is_some_and(|confirm| confirm(intent, window, cx));
 6119        if show_new_completions_on_confirm {
 6120            self.open_or_update_completions_menu(None, None, false, window, cx);
 6121        }
 6122
 6123        let provider = self.completion_provider.as_ref()?;
 6124
 6125        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6126        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6127            let CompletionSource::Lsp {
 6128                lsp_completion,
 6129                server_id,
 6130                ..
 6131            } = &completion.source
 6132            else {
 6133                return None;
 6134            };
 6135            let lsp_command = lsp_completion.command.as_ref()?;
 6136            let available_commands = lsp_store
 6137                .read(cx)
 6138                .lsp_server_capabilities
 6139                .get(server_id)
 6140                .and_then(|server_capabilities| {
 6141                    server_capabilities
 6142                        .execute_command_provider
 6143                        .as_ref()
 6144                        .map(|options| options.commands.as_slice())
 6145                })?;
 6146            if available_commands.contains(&lsp_command.command) {
 6147                Some(CodeAction {
 6148                    server_id: *server_id,
 6149                    range: language::Anchor::MIN..language::Anchor::MIN,
 6150                    lsp_action: LspAction::Command(lsp_command.clone()),
 6151                    resolved: false,
 6152                })
 6153            } else {
 6154                None
 6155            }
 6156        });
 6157
 6158        drop(completion);
 6159        let apply_edits = provider.apply_additional_edits_for_completion(
 6160            buffer_handle.clone(),
 6161            completions_menu.completions.clone(),
 6162            candidate_id,
 6163            true,
 6164            cx,
 6165        );
 6166
 6167        let editor_settings = EditorSettings::get_global(cx);
 6168        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6169            // After the code completion is finished, users often want to know what signatures are needed.
 6170            // so we should automatically call signature_help
 6171            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6172        }
 6173
 6174        Some(cx.spawn_in(window, async move |editor, cx| {
 6175            apply_edits.await?;
 6176
 6177            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6178                let title = command.lsp_action.title().to_owned();
 6179                let project_transaction = lsp_store
 6180                    .update(cx, |lsp_store, cx| {
 6181                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6182                    })?
 6183                    .await
 6184                    .context("applying post-completion command")?;
 6185                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6186                    Self::open_project_transaction(
 6187                        &editor,
 6188                        workspace.downgrade(),
 6189                        project_transaction,
 6190                        title,
 6191                        cx,
 6192                    )
 6193                    .await?;
 6194                }
 6195            }
 6196
 6197            Ok(())
 6198        }))
 6199    }
 6200
 6201    pub fn toggle_code_actions(
 6202        &mut self,
 6203        action: &ToggleCodeActions,
 6204        window: &mut Window,
 6205        cx: &mut Context<Self>,
 6206    ) {
 6207        let quick_launch = action.quick_launch;
 6208        let mut context_menu = self.context_menu.borrow_mut();
 6209        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6210            if code_actions.deployed_from == action.deployed_from {
 6211                // Toggle if we're selecting the same one
 6212                *context_menu = None;
 6213                cx.notify();
 6214                return;
 6215            } else {
 6216                // Otherwise, clear it and start a new one
 6217                *context_menu = None;
 6218                cx.notify();
 6219            }
 6220        }
 6221        drop(context_menu);
 6222        let snapshot = self.snapshot(window, cx);
 6223        let deployed_from = action.deployed_from.clone();
 6224        let action = action.clone();
 6225        self.completion_tasks.clear();
 6226        self.discard_edit_prediction(false, cx);
 6227
 6228        let multibuffer_point = match &action.deployed_from {
 6229            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6230                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6231            }
 6232            _ => self
 6233                .selections
 6234                .newest::<Point>(&snapshot.display_snapshot)
 6235                .head(),
 6236        };
 6237        let Some((buffer, buffer_row)) = snapshot
 6238            .buffer_snapshot()
 6239            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6240            .and_then(|(buffer_snapshot, range)| {
 6241                self.buffer()
 6242                    .read(cx)
 6243                    .buffer(buffer_snapshot.remote_id())
 6244                    .map(|buffer| (buffer, range.start.row))
 6245            })
 6246        else {
 6247            return;
 6248        };
 6249        let buffer_id = buffer.read(cx).remote_id();
 6250        let tasks = self
 6251            .tasks
 6252            .get(&(buffer_id, buffer_row))
 6253            .map(|t| Arc::new(t.to_owned()));
 6254
 6255        if !self.focus_handle.is_focused(window) {
 6256            return;
 6257        }
 6258        let project = self.project.clone();
 6259
 6260        let code_actions_task = match deployed_from {
 6261            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6262            _ => self.code_actions(buffer_row, window, cx),
 6263        };
 6264
 6265        let runnable_task = match deployed_from {
 6266            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6267            _ => {
 6268                let mut task_context_task = Task::ready(None);
 6269                if let Some(tasks) = &tasks
 6270                    && let Some(project) = project
 6271                {
 6272                    task_context_task =
 6273                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6274                }
 6275
 6276                cx.spawn_in(window, {
 6277                    let buffer = buffer.clone();
 6278                    async move |editor, cx| {
 6279                        let task_context = task_context_task.await;
 6280
 6281                        let resolved_tasks =
 6282                            tasks
 6283                                .zip(task_context.clone())
 6284                                .map(|(tasks, task_context)| ResolvedTasks {
 6285                                    templates: tasks.resolve(&task_context).collect(),
 6286                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6287                                        multibuffer_point.row,
 6288                                        tasks.column,
 6289                                    )),
 6290                                });
 6291                        let debug_scenarios = editor
 6292                            .update(cx, |editor, cx| {
 6293                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6294                            })?
 6295                            .await;
 6296                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6297                    }
 6298                })
 6299            }
 6300        };
 6301
 6302        cx.spawn_in(window, async move |editor, cx| {
 6303            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6304            let code_actions = code_actions_task.await;
 6305            let spawn_straight_away = quick_launch
 6306                && resolved_tasks
 6307                    .as_ref()
 6308                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6309                && code_actions
 6310                    .as_ref()
 6311                    .is_none_or(|actions| actions.is_empty())
 6312                && debug_scenarios.is_empty();
 6313
 6314            editor.update_in(cx, |editor, window, cx| {
 6315                crate::hover_popover::hide_hover(editor, cx);
 6316                let actions = CodeActionContents::new(
 6317                    resolved_tasks,
 6318                    code_actions,
 6319                    debug_scenarios,
 6320                    task_context.unwrap_or_default(),
 6321                );
 6322
 6323                // Don't show the menu if there are no actions available
 6324                if actions.is_empty() {
 6325                    cx.notify();
 6326                    return Task::ready(Ok(()));
 6327                }
 6328
 6329                *editor.context_menu.borrow_mut() =
 6330                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6331                        buffer,
 6332                        actions,
 6333                        selected_item: Default::default(),
 6334                        scroll_handle: UniformListScrollHandle::default(),
 6335                        deployed_from,
 6336                    }));
 6337                cx.notify();
 6338                if spawn_straight_away
 6339                    && let Some(task) = editor.confirm_code_action(
 6340                        &ConfirmCodeAction { item_ix: Some(0) },
 6341                        window,
 6342                        cx,
 6343                    )
 6344                {
 6345                    return task;
 6346                }
 6347
 6348                Task::ready(Ok(()))
 6349            })
 6350        })
 6351        .detach_and_log_err(cx);
 6352    }
 6353
 6354    fn debug_scenarios(
 6355        &mut self,
 6356        resolved_tasks: &Option<ResolvedTasks>,
 6357        buffer: &Entity<Buffer>,
 6358        cx: &mut App,
 6359    ) -> Task<Vec<task::DebugScenario>> {
 6360        maybe!({
 6361            let project = self.project()?;
 6362            let dap_store = project.read(cx).dap_store();
 6363            let mut scenarios = vec![];
 6364            let resolved_tasks = resolved_tasks.as_ref()?;
 6365            let buffer = buffer.read(cx);
 6366            let language = buffer.language()?;
 6367            let file = buffer.file();
 6368            let debug_adapter = language_settings(language.name().into(), file, cx)
 6369                .debuggers
 6370                .first()
 6371                .map(SharedString::from)
 6372                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6373
 6374            dap_store.update(cx, |dap_store, cx| {
 6375                for (_, task) in &resolved_tasks.templates {
 6376                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6377                        task.original_task().clone(),
 6378                        debug_adapter.clone().into(),
 6379                        task.display_label().to_owned().into(),
 6380                        cx,
 6381                    );
 6382                    scenarios.push(maybe_scenario);
 6383                }
 6384            });
 6385            Some(cx.background_spawn(async move {
 6386                futures::future::join_all(scenarios)
 6387                    .await
 6388                    .into_iter()
 6389                    .flatten()
 6390                    .collect::<Vec<_>>()
 6391            }))
 6392        })
 6393        .unwrap_or_else(|| Task::ready(vec![]))
 6394    }
 6395
 6396    fn code_actions(
 6397        &mut self,
 6398        buffer_row: u32,
 6399        window: &mut Window,
 6400        cx: &mut Context<Self>,
 6401    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6402        let mut task = self.code_actions_task.take();
 6403        cx.spawn_in(window, async move |editor, cx| {
 6404            while let Some(prev_task) = task {
 6405                prev_task.await.log_err();
 6406                task = editor
 6407                    .update(cx, |this, _| this.code_actions_task.take())
 6408                    .ok()?;
 6409            }
 6410
 6411            editor
 6412                .update(cx, |editor, cx| {
 6413                    editor
 6414                        .available_code_actions
 6415                        .clone()
 6416                        .and_then(|(location, code_actions)| {
 6417                            let snapshot = location.buffer.read(cx).snapshot();
 6418                            let point_range = location.range.to_point(&snapshot);
 6419                            let point_range = point_range.start.row..=point_range.end.row;
 6420                            if point_range.contains(&buffer_row) {
 6421                                Some(code_actions)
 6422                            } else {
 6423                                None
 6424                            }
 6425                        })
 6426                })
 6427                .ok()
 6428                .flatten()
 6429        })
 6430    }
 6431
 6432    pub fn confirm_code_action(
 6433        &mut self,
 6434        action: &ConfirmCodeAction,
 6435        window: &mut Window,
 6436        cx: &mut Context<Self>,
 6437    ) -> Option<Task<Result<()>>> {
 6438        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6439
 6440        let actions_menu =
 6441            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6442                menu
 6443            } else {
 6444                return None;
 6445            };
 6446
 6447        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6448        let action = actions_menu.actions.get(action_ix)?;
 6449        let title = action.label();
 6450        let buffer = actions_menu.buffer;
 6451        let workspace = self.workspace()?;
 6452
 6453        match action {
 6454            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6455                workspace.update(cx, |workspace, cx| {
 6456                    workspace.schedule_resolved_task(
 6457                        task_source_kind,
 6458                        resolved_task,
 6459                        false,
 6460                        window,
 6461                        cx,
 6462                    );
 6463
 6464                    Some(Task::ready(Ok(())))
 6465                })
 6466            }
 6467            CodeActionsItem::CodeAction {
 6468                excerpt_id,
 6469                action,
 6470                provider,
 6471            } => {
 6472                let apply_code_action =
 6473                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6474                let workspace = workspace.downgrade();
 6475                Some(cx.spawn_in(window, async move |editor, cx| {
 6476                    let project_transaction = apply_code_action.await?;
 6477                    Self::open_project_transaction(
 6478                        &editor,
 6479                        workspace,
 6480                        project_transaction,
 6481                        title,
 6482                        cx,
 6483                    )
 6484                    .await
 6485                }))
 6486            }
 6487            CodeActionsItem::DebugScenario(scenario) => {
 6488                let context = actions_menu.actions.context;
 6489
 6490                workspace.update(cx, |workspace, cx| {
 6491                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6492                    workspace.start_debug_session(
 6493                        scenario,
 6494                        context,
 6495                        Some(buffer),
 6496                        None,
 6497                        window,
 6498                        cx,
 6499                    );
 6500                });
 6501                Some(Task::ready(Ok(())))
 6502            }
 6503        }
 6504    }
 6505
 6506    fn open_transaction_for_hidden_buffers(
 6507        workspace: Entity<Workspace>,
 6508        transaction: ProjectTransaction,
 6509        title: String,
 6510        window: &mut Window,
 6511        cx: &mut Context<Self>,
 6512    ) {
 6513        if transaction.0.is_empty() {
 6514            return;
 6515        }
 6516
 6517        let edited_buffers_already_open = {
 6518            let other_editors: Vec<Entity<Editor>> = workspace
 6519                .read(cx)
 6520                .panes()
 6521                .iter()
 6522                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 6523                .filter(|editor| editor.entity_id() != cx.entity_id())
 6524                .collect();
 6525
 6526            transaction.0.keys().all(|buffer| {
 6527                other_editors.iter().any(|editor| {
 6528                    let multi_buffer = editor.read(cx).buffer();
 6529                    multi_buffer.read(cx).is_singleton()
 6530                        && multi_buffer
 6531                            .read(cx)
 6532                            .as_singleton()
 6533                            .map_or(false, |singleton| {
 6534                                singleton.entity_id() == buffer.entity_id()
 6535                            })
 6536                })
 6537            })
 6538        };
 6539        if !edited_buffers_already_open {
 6540            let workspace = workspace.downgrade();
 6541            cx.defer_in(window, move |_, window, cx| {
 6542                cx.spawn_in(window, async move |editor, cx| {
 6543                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 6544                        .await
 6545                        .ok()
 6546                })
 6547                .detach();
 6548            });
 6549        }
 6550    }
 6551
 6552    pub async fn open_project_transaction(
 6553        editor: &WeakEntity<Editor>,
 6554        workspace: WeakEntity<Workspace>,
 6555        transaction: ProjectTransaction,
 6556        title: String,
 6557        cx: &mut AsyncWindowContext,
 6558    ) -> Result<()> {
 6559        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6560        cx.update(|_, cx| {
 6561            entries.sort_unstable_by_key(|(buffer, _)| {
 6562                buffer.read(cx).file().map(|f| f.path().clone())
 6563            });
 6564        })?;
 6565        if entries.is_empty() {
 6566            return Ok(());
 6567        }
 6568
 6569        // If the project transaction's edits are all contained within this editor, then
 6570        // avoid opening a new editor to display them.
 6571
 6572        if let [(buffer, transaction)] = &*entries {
 6573            let excerpt = editor.update(cx, |editor, cx| {
 6574                editor
 6575                    .buffer()
 6576                    .read(cx)
 6577                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6578            })?;
 6579            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6580                && excerpted_buffer == *buffer
 6581            {
 6582                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6583                    let excerpt_range = excerpt_range.to_offset(buffer);
 6584                    buffer
 6585                        .edited_ranges_for_transaction::<usize>(transaction)
 6586                        .all(|range| {
 6587                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6588                        })
 6589                })?;
 6590
 6591                if all_edits_within_excerpt {
 6592                    return Ok(());
 6593                }
 6594            }
 6595        }
 6596
 6597        let mut ranges_to_highlight = Vec::new();
 6598        let excerpt_buffer = cx.new(|cx| {
 6599            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6600            for (buffer_handle, transaction) in &entries {
 6601                let edited_ranges = buffer_handle
 6602                    .read(cx)
 6603                    .edited_ranges_for_transaction::<Point>(transaction)
 6604                    .collect::<Vec<_>>();
 6605                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6606                    PathKey::for_buffer(buffer_handle, cx),
 6607                    buffer_handle.clone(),
 6608                    edited_ranges,
 6609                    multibuffer_context_lines(cx),
 6610                    cx,
 6611                );
 6612
 6613                ranges_to_highlight.extend(ranges);
 6614            }
 6615            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6616            multibuffer
 6617        })?;
 6618
 6619        workspace.update_in(cx, |workspace, window, cx| {
 6620            let project = workspace.project().clone();
 6621            let editor =
 6622                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6623            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6624            editor.update(cx, |editor, cx| {
 6625                editor.highlight_background::<Self>(
 6626                    &ranges_to_highlight,
 6627                    |_, theme| theme.colors().editor_highlighted_line_background,
 6628                    cx,
 6629                );
 6630            });
 6631        })?;
 6632
 6633        Ok(())
 6634    }
 6635
 6636    pub fn clear_code_action_providers(&mut self) {
 6637        self.code_action_providers.clear();
 6638        self.available_code_actions.take();
 6639    }
 6640
 6641    pub fn add_code_action_provider(
 6642        &mut self,
 6643        provider: Rc<dyn CodeActionProvider>,
 6644        window: &mut Window,
 6645        cx: &mut Context<Self>,
 6646    ) {
 6647        if self
 6648            .code_action_providers
 6649            .iter()
 6650            .any(|existing_provider| existing_provider.id() == provider.id())
 6651        {
 6652            return;
 6653        }
 6654
 6655        self.code_action_providers.push(provider);
 6656        self.refresh_code_actions(window, cx);
 6657    }
 6658
 6659    pub fn remove_code_action_provider(
 6660        &mut self,
 6661        id: Arc<str>,
 6662        window: &mut Window,
 6663        cx: &mut Context<Self>,
 6664    ) {
 6665        self.code_action_providers
 6666            .retain(|provider| provider.id() != id);
 6667        self.refresh_code_actions(window, cx);
 6668    }
 6669
 6670    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6671        !self.code_action_providers.is_empty()
 6672            && EditorSettings::get_global(cx).toolbar.code_actions
 6673    }
 6674
 6675    pub fn has_available_code_actions(&self) -> bool {
 6676        self.available_code_actions
 6677            .as_ref()
 6678            .is_some_and(|(_, actions)| !actions.is_empty())
 6679    }
 6680
 6681    fn render_inline_code_actions(
 6682        &self,
 6683        icon_size: ui::IconSize,
 6684        display_row: DisplayRow,
 6685        is_active: bool,
 6686        cx: &mut Context<Self>,
 6687    ) -> AnyElement {
 6688        let show_tooltip = !self.context_menu_visible();
 6689        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6690            .icon_size(icon_size)
 6691            .shape(ui::IconButtonShape::Square)
 6692            .icon_color(ui::Color::Hidden)
 6693            .toggle_state(is_active)
 6694            .when(show_tooltip, |this| {
 6695                this.tooltip({
 6696                    let focus_handle = self.focus_handle.clone();
 6697                    move |_window, cx| {
 6698                        Tooltip::for_action_in(
 6699                            "Toggle Code Actions",
 6700                            &ToggleCodeActions {
 6701                                deployed_from: None,
 6702                                quick_launch: false,
 6703                            },
 6704                            &focus_handle,
 6705                            cx,
 6706                        )
 6707                    }
 6708                })
 6709            })
 6710            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6711                window.focus(&editor.focus_handle(cx), cx);
 6712                editor.toggle_code_actions(
 6713                    &crate::actions::ToggleCodeActions {
 6714                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6715                            display_row,
 6716                        )),
 6717                        quick_launch: false,
 6718                    },
 6719                    window,
 6720                    cx,
 6721                );
 6722            }))
 6723            .into_any_element()
 6724    }
 6725
 6726    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6727        &self.context_menu
 6728    }
 6729
 6730    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6731        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6732            cx.background_executor()
 6733                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6734                .await;
 6735
 6736            let (start_buffer, start, _, end, newest_selection) = this
 6737                .update(cx, |this, cx| {
 6738                    let newest_selection = this.selections.newest_anchor().clone();
 6739                    if newest_selection.head().diff_base_anchor.is_some() {
 6740                        return None;
 6741                    }
 6742                    let display_snapshot = this.display_snapshot(cx);
 6743                    let newest_selection_adjusted =
 6744                        this.selections.newest_adjusted(&display_snapshot);
 6745                    let buffer = this.buffer.read(cx);
 6746
 6747                    let (start_buffer, start) =
 6748                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6749                    let (end_buffer, end) =
 6750                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6751
 6752                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6753                })?
 6754                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6755                .context(
 6756                    "Expected selection to lie in a single buffer when refreshing code actions",
 6757                )?;
 6758            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6759                let providers = this.code_action_providers.clone();
 6760                let tasks = this
 6761                    .code_action_providers
 6762                    .iter()
 6763                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6764                    .collect::<Vec<_>>();
 6765                (providers, tasks)
 6766            })?;
 6767
 6768            let mut actions = Vec::new();
 6769            for (provider, provider_actions) in
 6770                providers.into_iter().zip(future::join_all(tasks).await)
 6771            {
 6772                if let Some(provider_actions) = provider_actions.log_err() {
 6773                    actions.extend(provider_actions.into_iter().map(|action| {
 6774                        AvailableCodeAction {
 6775                            excerpt_id: newest_selection.start.excerpt_id,
 6776                            action,
 6777                            provider: provider.clone(),
 6778                        }
 6779                    }));
 6780                }
 6781            }
 6782
 6783            this.update(cx, |this, cx| {
 6784                this.available_code_actions = if actions.is_empty() {
 6785                    None
 6786                } else {
 6787                    Some((
 6788                        Location {
 6789                            buffer: start_buffer,
 6790                            range: start..end,
 6791                        },
 6792                        actions.into(),
 6793                    ))
 6794                };
 6795                cx.notify();
 6796            })
 6797        }));
 6798    }
 6799
 6800    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6801        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6802            self.show_git_blame_inline = false;
 6803
 6804            self.show_git_blame_inline_delay_task =
 6805                Some(cx.spawn_in(window, async move |this, cx| {
 6806                    cx.background_executor().timer(delay).await;
 6807
 6808                    this.update(cx, |this, cx| {
 6809                        this.show_git_blame_inline = true;
 6810                        cx.notify();
 6811                    })
 6812                    .log_err();
 6813                }));
 6814        }
 6815    }
 6816
 6817    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6818        let snapshot = self.snapshot(window, cx);
 6819        let cursor = self
 6820            .selections
 6821            .newest::<Point>(&snapshot.display_snapshot)
 6822            .head();
 6823        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6824        else {
 6825            return;
 6826        };
 6827
 6828        if self.blame.is_none() {
 6829            self.start_git_blame(true, window, cx);
 6830        }
 6831        let Some(blame) = self.blame.as_ref() else {
 6832            return;
 6833        };
 6834
 6835        let row_info = RowInfo {
 6836            buffer_id: Some(buffer.remote_id()),
 6837            buffer_row: Some(point.row),
 6838            ..Default::default()
 6839        };
 6840        let Some((buffer, blame_entry)) = blame
 6841            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6842            .flatten()
 6843        else {
 6844            return;
 6845        };
 6846
 6847        let anchor = self.selections.newest_anchor().head();
 6848        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 6849        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6850            self.show_blame_popover(
 6851                buffer,
 6852                &blame_entry,
 6853                position + last_bounds.origin,
 6854                true,
 6855                cx,
 6856            );
 6857        };
 6858    }
 6859
 6860    fn show_blame_popover(
 6861        &mut self,
 6862        buffer: BufferId,
 6863        blame_entry: &BlameEntry,
 6864        position: gpui::Point<Pixels>,
 6865        ignore_timeout: bool,
 6866        cx: &mut Context<Self>,
 6867    ) {
 6868        if let Some(state) = &mut self.inline_blame_popover {
 6869            state.hide_task.take();
 6870        } else {
 6871            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6872            let blame_entry = blame_entry.clone();
 6873            let show_task = cx.spawn(async move |editor, cx| {
 6874                if !ignore_timeout {
 6875                    cx.background_executor()
 6876                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6877                        .await;
 6878                }
 6879                editor
 6880                    .update(cx, |editor, cx| {
 6881                        editor.inline_blame_popover_show_task.take();
 6882                        let Some(blame) = editor.blame.as_ref() else {
 6883                            return;
 6884                        };
 6885                        let blame = blame.read(cx);
 6886                        let details = blame.details_for_entry(buffer, &blame_entry);
 6887                        let markdown = cx.new(|cx| {
 6888                            Markdown::new(
 6889                                details
 6890                                    .as_ref()
 6891                                    .map(|message| message.message.clone())
 6892                                    .unwrap_or_default(),
 6893                                None,
 6894                                None,
 6895                                cx,
 6896                            )
 6897                        });
 6898                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6899                            position,
 6900                            hide_task: None,
 6901                            popover_bounds: None,
 6902                            popover_state: InlineBlamePopoverState {
 6903                                scroll_handle: ScrollHandle::new(),
 6904                                commit_message: details,
 6905                                markdown,
 6906                            },
 6907                            keyboard_grace: ignore_timeout,
 6908                        });
 6909                        cx.notify();
 6910                    })
 6911                    .ok();
 6912            });
 6913            self.inline_blame_popover_show_task = Some(show_task);
 6914        }
 6915    }
 6916
 6917    pub fn has_mouse_context_menu(&self) -> bool {
 6918        self.mouse_context_menu.is_some()
 6919    }
 6920
 6921    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6922        self.inline_blame_popover_show_task.take();
 6923        if let Some(state) = &mut self.inline_blame_popover {
 6924            let hide_task = cx.spawn(async move |editor, cx| {
 6925                if !ignore_timeout {
 6926                    cx.background_executor()
 6927                        .timer(std::time::Duration::from_millis(100))
 6928                        .await;
 6929                }
 6930                editor
 6931                    .update(cx, |editor, cx| {
 6932                        editor.inline_blame_popover.take();
 6933                        cx.notify();
 6934                    })
 6935                    .ok();
 6936            });
 6937            state.hide_task = Some(hide_task);
 6938            true
 6939        } else {
 6940            false
 6941        }
 6942    }
 6943
 6944    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6945        if self.pending_rename.is_some() {
 6946            return None;
 6947        }
 6948
 6949        let provider = self.semantics_provider.clone()?;
 6950        let buffer = self.buffer.read(cx);
 6951        let newest_selection = self.selections.newest_anchor().clone();
 6952        let cursor_position = newest_selection.head();
 6953        let (cursor_buffer, cursor_buffer_position) =
 6954            buffer.text_anchor_for_position(cursor_position, cx)?;
 6955        let (tail_buffer, tail_buffer_position) =
 6956            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6957        if cursor_buffer != tail_buffer {
 6958            return None;
 6959        }
 6960
 6961        let snapshot = cursor_buffer.read(cx).snapshot();
 6962        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6963        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6964        if start_word_range != end_word_range {
 6965            self.document_highlights_task.take();
 6966            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6967            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6968            return None;
 6969        }
 6970
 6971        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6972        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6973            cx.background_executor()
 6974                .timer(Duration::from_millis(debounce))
 6975                .await;
 6976
 6977            let highlights = if let Some(highlights) = cx
 6978                .update(|cx| {
 6979                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6980                })
 6981                .ok()
 6982                .flatten()
 6983            {
 6984                highlights.await.log_err()
 6985            } else {
 6986                None
 6987            };
 6988
 6989            if let Some(highlights) = highlights {
 6990                this.update(cx, |this, cx| {
 6991                    if this.pending_rename.is_some() {
 6992                        return;
 6993                    }
 6994
 6995                    let buffer = this.buffer.read(cx);
 6996                    if buffer
 6997                        .text_anchor_for_position(cursor_position, cx)
 6998                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6999                    {
 7000                        return;
 7001                    }
 7002
 7003                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7004                    let mut write_ranges = Vec::new();
 7005                    let mut read_ranges = Vec::new();
 7006                    for highlight in highlights {
 7007                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7008                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7009                        {
 7010                            let start = highlight
 7011                                .range
 7012                                .start
 7013                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7014                            let end = highlight
 7015                                .range
 7016                                .end
 7017                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7018                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7019                                continue;
 7020                            }
 7021
 7022                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7023                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7024                                write_ranges.push(range);
 7025                            } else {
 7026                                read_ranges.push(range);
 7027                            }
 7028                        }
 7029                    }
 7030
 7031                    this.highlight_background::<DocumentHighlightRead>(
 7032                        &read_ranges,
 7033                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7034                        cx,
 7035                    );
 7036                    this.highlight_background::<DocumentHighlightWrite>(
 7037                        &write_ranges,
 7038                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7039                        cx,
 7040                    );
 7041                    cx.notify();
 7042                })
 7043                .log_err();
 7044            }
 7045        }));
 7046        None
 7047    }
 7048
 7049    fn prepare_highlight_query_from_selection(
 7050        &mut self,
 7051        window: &Window,
 7052        cx: &mut Context<Editor>,
 7053    ) -> Option<(String, Range<Anchor>)> {
 7054        if matches!(self.mode, EditorMode::SingleLine) {
 7055            return None;
 7056        }
 7057        if !EditorSettings::get_global(cx).selection_highlight {
 7058            return None;
 7059        }
 7060        if self.selections.count() != 1 || self.selections.line_mode() {
 7061            return None;
 7062        }
 7063        let snapshot = self.snapshot(window, cx);
 7064        let selection = self.selections.newest::<Point>(&snapshot);
 7065        // If the selection spans multiple rows OR it is empty
 7066        if selection.start.row != selection.end.row
 7067            || selection.start.column == selection.end.column
 7068        {
 7069            return None;
 7070        }
 7071        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7072        let query = snapshot
 7073            .buffer_snapshot()
 7074            .text_for_range(selection_anchor_range.clone())
 7075            .collect::<String>();
 7076        if query.trim().is_empty() {
 7077            return None;
 7078        }
 7079        Some((query, selection_anchor_range))
 7080    }
 7081
 7082    #[ztracing::instrument(skip_all)]
 7083    fn update_selection_occurrence_highlights(
 7084        &mut self,
 7085        query_text: String,
 7086        query_range: Range<Anchor>,
 7087        multi_buffer_range_to_query: Range<Point>,
 7088        use_debounce: bool,
 7089        window: &mut Window,
 7090        cx: &mut Context<Editor>,
 7091    ) -> Task<()> {
 7092        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7093        cx.spawn_in(window, async move |editor, cx| {
 7094            if use_debounce {
 7095                cx.background_executor()
 7096                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7097                    .await;
 7098            }
 7099            let match_task = cx.background_spawn(async move {
 7100                let buffer_ranges = multi_buffer_snapshot
 7101                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7102                    .into_iter()
 7103                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7104                let mut match_ranges = Vec::new();
 7105                let Ok(regex) = project::search::SearchQuery::text(
 7106                    query_text.clone(),
 7107                    false,
 7108                    false,
 7109                    false,
 7110                    Default::default(),
 7111                    Default::default(),
 7112                    false,
 7113                    None,
 7114                ) else {
 7115                    return Vec::default();
 7116                };
 7117                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7118                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7119                    match_ranges.extend(
 7120                        regex
 7121                            .search(
 7122                                buffer_snapshot,
 7123                                Some(search_range.start.0..search_range.end.0),
 7124                            )
 7125                            .await
 7126                            .into_iter()
 7127                            .filter_map(|match_range| {
 7128                                let match_start = buffer_snapshot
 7129                                    .anchor_after(search_range.start + match_range.start);
 7130                                let match_end = buffer_snapshot
 7131                                    .anchor_before(search_range.start + match_range.end);
 7132                                let match_anchor_range =
 7133                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7134                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7135                            }),
 7136                    );
 7137                }
 7138                match_ranges
 7139            });
 7140            let match_ranges = match_task.await;
 7141            editor
 7142                .update_in(cx, |editor, _, cx| {
 7143                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7144                    if !match_ranges.is_empty() {
 7145                        editor.highlight_background::<SelectedTextHighlight>(
 7146                            &match_ranges,
 7147                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7148                            cx,
 7149                        )
 7150                    }
 7151                })
 7152                .log_err();
 7153        })
 7154    }
 7155
 7156    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7157        struct NewlineFold;
 7158        let type_id = std::any::TypeId::of::<NewlineFold>();
 7159        if !self.mode.is_single_line() {
 7160            return;
 7161        }
 7162        let snapshot = self.snapshot(window, cx);
 7163        if snapshot.buffer_snapshot().max_point().row == 0 {
 7164            return;
 7165        }
 7166        let task = cx.background_spawn(async move {
 7167            let new_newlines = snapshot
 7168                .buffer_chars_at(MultiBufferOffset(0))
 7169                .filter_map(|(c, i)| {
 7170                    if c == '\n' {
 7171                        Some(
 7172                            snapshot.buffer_snapshot().anchor_after(i)
 7173                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7174                        )
 7175                    } else {
 7176                        None
 7177                    }
 7178                })
 7179                .collect::<Vec<_>>();
 7180            let existing_newlines = snapshot
 7181                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7182                .filter_map(|fold| {
 7183                    if fold.placeholder.type_tag == Some(type_id) {
 7184                        Some(fold.range.start..fold.range.end)
 7185                    } else {
 7186                        None
 7187                    }
 7188                })
 7189                .collect::<Vec<_>>();
 7190
 7191            (new_newlines, existing_newlines)
 7192        });
 7193        self.folding_newlines = cx.spawn(async move |this, cx| {
 7194            let (new_newlines, existing_newlines) = task.await;
 7195            if new_newlines == existing_newlines {
 7196                return;
 7197            }
 7198            let placeholder = FoldPlaceholder {
 7199                render: Arc::new(move |_, _, cx| {
 7200                    div()
 7201                        .bg(cx.theme().status().hint_background)
 7202                        .border_b_1()
 7203                        .size_full()
 7204                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7205                        .border_color(cx.theme().status().hint)
 7206                        .child("\\n")
 7207                        .into_any()
 7208                }),
 7209                constrain_width: false,
 7210                merge_adjacent: false,
 7211                type_tag: Some(type_id),
 7212            };
 7213            let creases = new_newlines
 7214                .into_iter()
 7215                .map(|range| Crease::simple(range, placeholder.clone()))
 7216                .collect();
 7217            this.update(cx, |this, cx| {
 7218                this.display_map.update(cx, |display_map, cx| {
 7219                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7220                    display_map.fold(creases, cx);
 7221                });
 7222            })
 7223            .ok();
 7224        });
 7225    }
 7226
 7227    #[ztracing::instrument(skip_all)]
 7228    fn refresh_selected_text_highlights(
 7229        &mut self,
 7230        on_buffer_edit: bool,
 7231        window: &mut Window,
 7232        cx: &mut Context<Editor>,
 7233    ) {
 7234        let Some((query_text, query_range)) =
 7235            self.prepare_highlight_query_from_selection(window, cx)
 7236        else {
 7237            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7238            self.quick_selection_highlight_task.take();
 7239            self.debounced_selection_highlight_task.take();
 7240            return;
 7241        };
 7242        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7243        if on_buffer_edit
 7244            || self
 7245                .quick_selection_highlight_task
 7246                .as_ref()
 7247                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7248        {
 7249            let multi_buffer_visible_start = self
 7250                .scroll_manager
 7251                .anchor()
 7252                .anchor
 7253                .to_point(&multi_buffer_snapshot);
 7254            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7255                multi_buffer_visible_start
 7256                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7257                Bias::Left,
 7258            );
 7259            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7260            self.quick_selection_highlight_task = Some((
 7261                query_range.clone(),
 7262                self.update_selection_occurrence_highlights(
 7263                    query_text.clone(),
 7264                    query_range.clone(),
 7265                    multi_buffer_visible_range,
 7266                    false,
 7267                    window,
 7268                    cx,
 7269                ),
 7270            ));
 7271        }
 7272        if on_buffer_edit
 7273            || self
 7274                .debounced_selection_highlight_task
 7275                .as_ref()
 7276                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7277        {
 7278            let multi_buffer_start = multi_buffer_snapshot
 7279                .anchor_before(MultiBufferOffset(0))
 7280                .to_point(&multi_buffer_snapshot);
 7281            let multi_buffer_end = multi_buffer_snapshot
 7282                .anchor_after(multi_buffer_snapshot.len())
 7283                .to_point(&multi_buffer_snapshot);
 7284            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7285            self.debounced_selection_highlight_task = Some((
 7286                query_range.clone(),
 7287                self.update_selection_occurrence_highlights(
 7288                    query_text,
 7289                    query_range,
 7290                    multi_buffer_full_range,
 7291                    true,
 7292                    window,
 7293                    cx,
 7294                ),
 7295            ));
 7296        }
 7297    }
 7298
 7299    pub fn refresh_edit_prediction(
 7300        &mut self,
 7301        debounce: bool,
 7302        user_requested: bool,
 7303        window: &mut Window,
 7304        cx: &mut Context<Self>,
 7305    ) -> Option<()> {
 7306        if DisableAiSettings::get_global(cx).disable_ai {
 7307            return None;
 7308        }
 7309
 7310        let provider = self.edit_prediction_provider()?;
 7311        let cursor = self.selections.newest_anchor().head();
 7312        let (buffer, cursor_buffer_position) =
 7313            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7314
 7315        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7316            self.discard_edit_prediction(false, cx);
 7317            return None;
 7318        }
 7319
 7320        self.update_visible_edit_prediction(window, cx);
 7321
 7322        if !user_requested
 7323            && (!self.should_show_edit_predictions()
 7324                || !self.is_focused(window)
 7325                || buffer.read(cx).is_empty())
 7326        {
 7327            self.discard_edit_prediction(false, cx);
 7328            return None;
 7329        }
 7330
 7331        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7332        Some(())
 7333    }
 7334
 7335    fn show_edit_predictions_in_menu(&self) -> bool {
 7336        match self.edit_prediction_settings {
 7337            EditPredictionSettings::Disabled => false,
 7338            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7339        }
 7340    }
 7341
 7342    pub fn edit_predictions_enabled(&self) -> bool {
 7343        match self.edit_prediction_settings {
 7344            EditPredictionSettings::Disabled => false,
 7345            EditPredictionSettings::Enabled { .. } => true,
 7346        }
 7347    }
 7348
 7349    fn edit_prediction_requires_modifier(&self) -> bool {
 7350        match self.edit_prediction_settings {
 7351            EditPredictionSettings::Disabled => false,
 7352            EditPredictionSettings::Enabled {
 7353                preview_requires_modifier,
 7354                ..
 7355            } => preview_requires_modifier,
 7356        }
 7357    }
 7358
 7359    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7360        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7361            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7362            self.discard_edit_prediction(false, cx);
 7363        } else {
 7364            let selection = self.selections.newest_anchor();
 7365            let cursor = selection.head();
 7366
 7367            if let Some((buffer, cursor_buffer_position)) =
 7368                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7369            {
 7370                self.edit_prediction_settings =
 7371                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7372            }
 7373        }
 7374    }
 7375
 7376    fn edit_prediction_settings_at_position(
 7377        &self,
 7378        buffer: &Entity<Buffer>,
 7379        buffer_position: language::Anchor,
 7380        cx: &App,
 7381    ) -> EditPredictionSettings {
 7382        if !self.mode.is_full()
 7383            || !self.show_edit_predictions_override.unwrap_or(true)
 7384            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7385        {
 7386            return EditPredictionSettings::Disabled;
 7387        }
 7388
 7389        let buffer = buffer.read(cx);
 7390
 7391        let file = buffer.file();
 7392
 7393        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7394            return EditPredictionSettings::Disabled;
 7395        };
 7396
 7397        let by_provider = matches!(
 7398            self.menu_edit_predictions_policy,
 7399            MenuEditPredictionsPolicy::ByProvider
 7400        );
 7401
 7402        let show_in_menu = by_provider
 7403            && self
 7404                .edit_prediction_provider
 7405                .as_ref()
 7406                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7407
 7408        let preview_requires_modifier =
 7409            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7410
 7411        EditPredictionSettings::Enabled {
 7412            show_in_menu,
 7413            preview_requires_modifier,
 7414        }
 7415    }
 7416
 7417    fn should_show_edit_predictions(&self) -> bool {
 7418        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7419    }
 7420
 7421    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7422        matches!(
 7423            self.edit_prediction_preview,
 7424            EditPredictionPreview::Active { .. }
 7425        )
 7426    }
 7427
 7428    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7429        let cursor = self.selections.newest_anchor().head();
 7430        if let Some((buffer, cursor_position)) =
 7431            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7432        {
 7433            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7434        } else {
 7435            false
 7436        }
 7437    }
 7438
 7439    pub fn supports_minimap(&self, cx: &App) -> bool {
 7440        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7441    }
 7442
 7443    fn edit_predictions_enabled_in_buffer(
 7444        &self,
 7445        buffer: &Entity<Buffer>,
 7446        buffer_position: language::Anchor,
 7447        cx: &App,
 7448    ) -> bool {
 7449        maybe!({
 7450            if self.read_only(cx) {
 7451                return Some(false);
 7452            }
 7453            let provider = self.edit_prediction_provider()?;
 7454            if !provider.is_enabled(buffer, buffer_position, cx) {
 7455                return Some(false);
 7456            }
 7457            let buffer = buffer.read(cx);
 7458            let Some(file) = buffer.file() else {
 7459                return Some(true);
 7460            };
 7461            let settings = all_language_settings(Some(file), cx);
 7462            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7463        })
 7464        .unwrap_or(false)
 7465    }
 7466
 7467    pub fn show_edit_prediction(
 7468        &mut self,
 7469        _: &ShowEditPrediction,
 7470        window: &mut Window,
 7471        cx: &mut Context<Self>,
 7472    ) {
 7473        if !self.has_active_edit_prediction() {
 7474            self.refresh_edit_prediction(false, true, window, cx);
 7475            return;
 7476        }
 7477
 7478        self.update_visible_edit_prediction(window, cx);
 7479    }
 7480
 7481    pub fn display_cursor_names(
 7482        &mut self,
 7483        _: &DisplayCursorNames,
 7484        window: &mut Window,
 7485        cx: &mut Context<Self>,
 7486    ) {
 7487        self.show_cursor_names(window, cx);
 7488    }
 7489
 7490    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7491        self.show_cursor_names = true;
 7492        cx.notify();
 7493        cx.spawn_in(window, async move |this, cx| {
 7494            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7495            this.update(cx, |this, cx| {
 7496                this.show_cursor_names = false;
 7497                cx.notify()
 7498            })
 7499            .ok()
 7500        })
 7501        .detach();
 7502    }
 7503
 7504    pub fn accept_partial_edit_prediction(
 7505        &mut self,
 7506        granularity: EditPredictionGranularity,
 7507        window: &mut Window,
 7508        cx: &mut Context<Self>,
 7509    ) {
 7510        if self.show_edit_predictions_in_menu() {
 7511            self.hide_context_menu(window, cx);
 7512        }
 7513
 7514        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7515            return;
 7516        };
 7517
 7518        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 7519            return;
 7520        }
 7521
 7522        match &active_edit_prediction.completion {
 7523            EditPrediction::MoveWithin { target, .. } => {
 7524                let target = *target;
 7525
 7526                if matches!(granularity, EditPredictionGranularity::Full) {
 7527                    if let Some(position_map) = &self.last_position_map {
 7528                        let target_row = target.to_display_point(&position_map.snapshot).row();
 7529                        let is_visible = position_map.visible_row_range.contains(&target_row);
 7530
 7531                        if is_visible || !self.edit_prediction_requires_modifier() {
 7532                            self.unfold_ranges(&[target..target], true, false, cx);
 7533                            self.change_selections(
 7534                                SelectionEffects::scroll(Autoscroll::newest()),
 7535                                window,
 7536                                cx,
 7537                                |selections| {
 7538                                    selections.select_anchor_ranges([target..target]);
 7539                                },
 7540                            );
 7541                            self.clear_row_highlights::<EditPredictionPreview>();
 7542                            self.edit_prediction_preview
 7543                                .set_previous_scroll_position(None);
 7544                        } else {
 7545                            // Highlight and request scroll
 7546                            self.edit_prediction_preview
 7547                                .set_previous_scroll_position(Some(
 7548                                    position_map.snapshot.scroll_anchor,
 7549                                ));
 7550                            self.highlight_rows::<EditPredictionPreview>(
 7551                                target..target,
 7552                                cx.theme().colors().editor_highlighted_line_background,
 7553                                RowHighlightOptions {
 7554                                    autoscroll: true,
 7555                                    ..Default::default()
 7556                                },
 7557                                cx,
 7558                            );
 7559                            self.request_autoscroll(Autoscroll::fit(), cx);
 7560                        }
 7561                    }
 7562                } else {
 7563                    self.change_selections(
 7564                        SelectionEffects::scroll(Autoscroll::newest()),
 7565                        window,
 7566                        cx,
 7567                        |selections| {
 7568                            selections.select_anchor_ranges([target..target]);
 7569                        },
 7570                    );
 7571                }
 7572            }
 7573            EditPrediction::MoveOutside { snapshot, target } => {
 7574                if let Some(workspace) = self.workspace() {
 7575                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7576                        .detach_and_log_err(cx);
 7577                }
 7578            }
 7579            EditPrediction::Edit { edits, .. } => {
 7580                self.report_edit_prediction_event(
 7581                    active_edit_prediction.completion_id.clone(),
 7582                    true,
 7583                    cx,
 7584                );
 7585
 7586                match granularity {
 7587                    EditPredictionGranularity::Full => {
 7588                        if let Some(provider) = self.edit_prediction_provider() {
 7589                            provider.accept(cx);
 7590                        }
 7591
 7592                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7593                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7594                        let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7595
 7596                        self.buffer.update(cx, |buffer, cx| {
 7597                            buffer.edit(edits.iter().cloned(), None, cx)
 7598                        });
 7599
 7600                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7601                            s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7602                        });
 7603
 7604                        let selections = self.selections.disjoint_anchors_arc();
 7605                        if let Some(transaction_id_now) =
 7606                            self.buffer.read(cx).last_transaction_id(cx)
 7607                        {
 7608                            if transaction_id_prev != Some(transaction_id_now) {
 7609                                self.selection_history
 7610                                    .insert_transaction(transaction_id_now, selections);
 7611                            }
 7612                        }
 7613
 7614                        self.update_visible_edit_prediction(window, cx);
 7615                        if self.active_edit_prediction.is_none() {
 7616                            self.refresh_edit_prediction(true, true, window, cx);
 7617                        }
 7618                        cx.notify();
 7619                    }
 7620                    _ => {
 7621                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7622                        let cursor_offset = self
 7623                            .selections
 7624                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7625                            .head();
 7626
 7627                        let insertion = edits.iter().find_map(|(range, text)| {
 7628                            let range = range.to_offset(&snapshot);
 7629                            if range.is_empty() && range.start == cursor_offset {
 7630                                Some(text)
 7631                            } else {
 7632                                None
 7633                            }
 7634                        });
 7635
 7636                        if let Some(text) = insertion {
 7637                            let text_to_insert = match granularity {
 7638                                EditPredictionGranularity::Word => {
 7639                                    let mut partial = text
 7640                                        .chars()
 7641                                        .by_ref()
 7642                                        .take_while(|c| c.is_alphabetic())
 7643                                        .collect::<String>();
 7644                                    if partial.is_empty() {
 7645                                        partial = text
 7646                                            .chars()
 7647                                            .by_ref()
 7648                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7649                                            .collect::<String>();
 7650                                    }
 7651                                    partial
 7652                                }
 7653                                EditPredictionGranularity::Line => {
 7654                                    if let Some(line) = text.split_inclusive('\n').next() {
 7655                                        line.to_string()
 7656                                    } else {
 7657                                        text.to_string()
 7658                                    }
 7659                                }
 7660                                EditPredictionGranularity::Full => unreachable!(),
 7661                            };
 7662
 7663                            cx.emit(EditorEvent::InputHandled {
 7664                                utf16_range_to_replace: None,
 7665                                text: text_to_insert.clone().into(),
 7666                            });
 7667
 7668                            self.insert_with_autoindent_mode(&text_to_insert, None, window, cx);
 7669                            self.refresh_edit_prediction(true, true, window, cx);
 7670                            cx.notify();
 7671                        } else {
 7672                            self.accept_partial_edit_prediction(
 7673                                EditPredictionGranularity::Full,
 7674                                window,
 7675                                cx,
 7676                            );
 7677                        }
 7678                    }
 7679                }
 7680            }
 7681        }
 7682
 7683        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7684    }
 7685
 7686    pub fn accept_next_word_edit_prediction(
 7687        &mut self,
 7688        _: &AcceptNextWordEditPrediction,
 7689        window: &mut Window,
 7690        cx: &mut Context<Self>,
 7691    ) {
 7692        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 7693    }
 7694
 7695    pub fn accept_next_line_edit_prediction(
 7696        &mut self,
 7697        _: &AcceptNextLineEditPrediction,
 7698        window: &mut Window,
 7699        cx: &mut Context<Self>,
 7700    ) {
 7701        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 7702    }
 7703
 7704    pub fn accept_edit_prediction(
 7705        &mut self,
 7706        _: &AcceptEditPrediction,
 7707        window: &mut Window,
 7708        cx: &mut Context<Self>,
 7709    ) {
 7710        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 7711    }
 7712
 7713    fn discard_edit_prediction(
 7714        &mut self,
 7715        should_report_edit_prediction_event: bool,
 7716        cx: &mut Context<Self>,
 7717    ) -> bool {
 7718        if should_report_edit_prediction_event {
 7719            let completion_id = self
 7720                .active_edit_prediction
 7721                .as_ref()
 7722                .and_then(|active_completion| active_completion.completion_id.clone());
 7723
 7724            self.report_edit_prediction_event(completion_id, false, cx);
 7725        }
 7726
 7727        if let Some(provider) = self.edit_prediction_provider() {
 7728            provider.discard(cx);
 7729        }
 7730
 7731        self.take_active_edit_prediction(cx)
 7732    }
 7733
 7734    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7735        let Some(provider) = self.edit_prediction_provider() else {
 7736            return;
 7737        };
 7738
 7739        let Some((_, buffer, _)) = self
 7740            .buffer
 7741            .read(cx)
 7742            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7743        else {
 7744            return;
 7745        };
 7746
 7747        let extension = buffer
 7748            .read(cx)
 7749            .file()
 7750            .and_then(|file| Some(file.path().extension()?.to_string()));
 7751
 7752        let event_type = match accepted {
 7753            true => "Edit Prediction Accepted",
 7754            false => "Edit Prediction Discarded",
 7755        };
 7756        telemetry::event!(
 7757            event_type,
 7758            provider = provider.name(),
 7759            prediction_id = id,
 7760            suggestion_accepted = accepted,
 7761            file_extension = extension,
 7762        );
 7763    }
 7764
 7765    fn open_editor_at_anchor(
 7766        snapshot: &language::BufferSnapshot,
 7767        target: language::Anchor,
 7768        workspace: &Entity<Workspace>,
 7769        window: &mut Window,
 7770        cx: &mut App,
 7771    ) -> Task<Result<()>> {
 7772        workspace.update(cx, |workspace, cx| {
 7773            let path = snapshot.file().map(|file| file.full_path(cx));
 7774            let Some(path) =
 7775                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7776            else {
 7777                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7778            };
 7779            let target = text::ToPoint::to_point(&target, snapshot);
 7780            let item = workspace.open_path(path, None, true, window, cx);
 7781            window.spawn(cx, async move |cx| {
 7782                let Some(editor) = item.await?.downcast::<Editor>() else {
 7783                    return Ok(());
 7784                };
 7785                editor
 7786                    .update_in(cx, |editor, window, cx| {
 7787                        editor.go_to_singleton_buffer_point(target, window, cx);
 7788                    })
 7789                    .ok();
 7790                anyhow::Ok(())
 7791            })
 7792        })
 7793    }
 7794
 7795    pub fn has_active_edit_prediction(&self) -> bool {
 7796        self.active_edit_prediction.is_some()
 7797    }
 7798
 7799    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7800        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7801            return false;
 7802        };
 7803
 7804        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7805        self.clear_highlights::<EditPredictionHighlight>(cx);
 7806        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7807        true
 7808    }
 7809
 7810    /// Returns true when we're displaying the edit prediction popover below the cursor
 7811    /// like we are not previewing and the LSP autocomplete menu is visible
 7812    /// or we are in `when_holding_modifier` mode.
 7813    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7814        if self.edit_prediction_preview_is_active()
 7815            || !self.show_edit_predictions_in_menu()
 7816            || !self.edit_predictions_enabled()
 7817        {
 7818            return false;
 7819        }
 7820
 7821        if self.has_visible_completions_menu() {
 7822            return true;
 7823        }
 7824
 7825        has_completion && self.edit_prediction_requires_modifier()
 7826    }
 7827
 7828    fn handle_modifiers_changed(
 7829        &mut self,
 7830        modifiers: Modifiers,
 7831        position_map: &PositionMap,
 7832        window: &mut Window,
 7833        cx: &mut Context<Self>,
 7834    ) {
 7835        // Ensure that the edit prediction preview is updated, even when not
 7836        // enabled, if there's an active edit prediction preview.
 7837        if self.show_edit_predictions_in_menu()
 7838            || matches!(
 7839                self.edit_prediction_preview,
 7840                EditPredictionPreview::Active { .. }
 7841            )
 7842        {
 7843            self.update_edit_prediction_preview(&modifiers, window, cx);
 7844        }
 7845
 7846        self.update_selection_mode(&modifiers, position_map, window, cx);
 7847
 7848        let mouse_position = window.mouse_position();
 7849        if !position_map.text_hitbox.is_hovered(window) {
 7850            return;
 7851        }
 7852
 7853        self.update_hovered_link(
 7854            position_map.point_for_position(mouse_position),
 7855            &position_map.snapshot,
 7856            modifiers,
 7857            window,
 7858            cx,
 7859        )
 7860    }
 7861
 7862    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7863        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7864            MultiCursorModifier::Alt => modifiers.secondary(),
 7865            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7866        }
 7867    }
 7868
 7869    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7870        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7871            MultiCursorModifier::Alt => modifiers.alt,
 7872            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7873        }
 7874    }
 7875
 7876    fn columnar_selection_mode(
 7877        modifiers: &Modifiers,
 7878        cx: &mut Context<Self>,
 7879    ) -> Option<ColumnarMode> {
 7880        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7881            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7882                Some(ColumnarMode::FromMouse)
 7883            } else if Self::is_alt_pressed(modifiers, cx) {
 7884                Some(ColumnarMode::FromSelection)
 7885            } else {
 7886                None
 7887            }
 7888        } else {
 7889            None
 7890        }
 7891    }
 7892
 7893    fn update_selection_mode(
 7894        &mut self,
 7895        modifiers: &Modifiers,
 7896        position_map: &PositionMap,
 7897        window: &mut Window,
 7898        cx: &mut Context<Self>,
 7899    ) {
 7900        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7901            return;
 7902        };
 7903        if self.selections.pending_anchor().is_none() {
 7904            return;
 7905        }
 7906
 7907        let mouse_position = window.mouse_position();
 7908        let point_for_position = position_map.point_for_position(mouse_position);
 7909        let position = point_for_position.previous_valid;
 7910
 7911        self.select(
 7912            SelectPhase::BeginColumnar {
 7913                position,
 7914                reset: false,
 7915                mode,
 7916                goal_column: point_for_position.exact_unclipped.column(),
 7917            },
 7918            window,
 7919            cx,
 7920        );
 7921    }
 7922
 7923    fn update_edit_prediction_preview(
 7924        &mut self,
 7925        modifiers: &Modifiers,
 7926        window: &mut Window,
 7927        cx: &mut Context<Self>,
 7928    ) {
 7929        let mut modifiers_held = false;
 7930
 7931        // Check bindings for all granularities.
 7932        // If the user holds the key for Word, Line, or Full, we want to show the preview.
 7933        let granularities = [
 7934            EditPredictionGranularity::Full,
 7935            EditPredictionGranularity::Line,
 7936            EditPredictionGranularity::Word,
 7937        ];
 7938
 7939        for granularity in granularities {
 7940            if let Some(keystroke) = self
 7941                .accept_edit_prediction_keybind(granularity, window, cx)
 7942                .keystroke()
 7943            {
 7944                modifiers_held = modifiers_held
 7945                    || (keystroke.modifiers() == modifiers && keystroke.modifiers().modified());
 7946            }
 7947        }
 7948
 7949        if modifiers_held {
 7950            if matches!(
 7951                self.edit_prediction_preview,
 7952                EditPredictionPreview::Inactive { .. }
 7953            ) {
 7954                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 7955                    provider.provider.did_show(cx)
 7956                }
 7957
 7958                self.edit_prediction_preview = EditPredictionPreview::Active {
 7959                    previous_scroll_position: None,
 7960                    since: Instant::now(),
 7961                };
 7962
 7963                self.update_visible_edit_prediction(window, cx);
 7964                cx.notify();
 7965            }
 7966        } else if let EditPredictionPreview::Active {
 7967            previous_scroll_position,
 7968            since,
 7969        } = self.edit_prediction_preview
 7970        {
 7971            if let (Some(previous_scroll_position), Some(position_map)) =
 7972                (previous_scroll_position, self.last_position_map.as_ref())
 7973            {
 7974                self.set_scroll_position(
 7975                    previous_scroll_position
 7976                        .scroll_position(&position_map.snapshot.display_snapshot),
 7977                    window,
 7978                    cx,
 7979                );
 7980            }
 7981
 7982            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7983                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7984            };
 7985            self.clear_row_highlights::<EditPredictionPreview>();
 7986            self.update_visible_edit_prediction(window, cx);
 7987            cx.notify();
 7988        }
 7989    }
 7990
 7991    fn update_visible_edit_prediction(
 7992        &mut self,
 7993        _window: &mut Window,
 7994        cx: &mut Context<Self>,
 7995    ) -> Option<()> {
 7996        if DisableAiSettings::get_global(cx).disable_ai {
 7997            return None;
 7998        }
 7999
 8000        if self.ime_transaction.is_some() {
 8001            self.discard_edit_prediction(false, cx);
 8002            return None;
 8003        }
 8004
 8005        let selection = self.selections.newest_anchor();
 8006        let cursor = selection.head();
 8007        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8008        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8009        let excerpt_id = cursor.excerpt_id;
 8010
 8011        let show_in_menu = self.show_edit_predictions_in_menu();
 8012        let completions_menu_has_precedence = !show_in_menu
 8013            && (self.context_menu.borrow().is_some()
 8014                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8015
 8016        if completions_menu_has_precedence
 8017            || !offset_selection.is_empty()
 8018            || self
 8019                .active_edit_prediction
 8020                .as_ref()
 8021                .is_some_and(|completion| {
 8022                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8023                        return false;
 8024                    };
 8025                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8026                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8027                    !invalidation_range.contains(&offset_selection.head())
 8028                })
 8029        {
 8030            self.discard_edit_prediction(false, cx);
 8031            return None;
 8032        }
 8033
 8034        self.take_active_edit_prediction(cx);
 8035        let Some(provider) = self.edit_prediction_provider() else {
 8036            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8037            return None;
 8038        };
 8039
 8040        let (buffer, cursor_buffer_position) =
 8041            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8042
 8043        self.edit_prediction_settings =
 8044            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8045
 8046        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8047
 8048        if self.edit_prediction_indent_conflict {
 8049            let cursor_point = cursor.to_point(&multibuffer);
 8050            let mut suggested_indent = None;
 8051            multibuffer.suggested_indents_callback(
 8052                cursor_point.row..cursor_point.row + 1,
 8053                |_, indent| {
 8054                    suggested_indent = Some(indent);
 8055                    ControlFlow::Break(())
 8056                },
 8057                cx,
 8058            );
 8059
 8060            if let Some(indent) = suggested_indent
 8061                && indent.len == cursor_point.column
 8062            {
 8063                self.edit_prediction_indent_conflict = false;
 8064            }
 8065        }
 8066
 8067        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8068
 8069        let (completion_id, edits, edit_preview) = match edit_prediction {
 8070            edit_prediction_types::EditPrediction::Local {
 8071                id,
 8072                edits,
 8073                edit_preview,
 8074            } => (id, edits, edit_preview),
 8075            edit_prediction_types::EditPrediction::Jump {
 8076                id,
 8077                snapshot,
 8078                target,
 8079            } => {
 8080                self.stale_edit_prediction_in_menu = None;
 8081                self.active_edit_prediction = Some(EditPredictionState {
 8082                    inlay_ids: vec![],
 8083                    completion: EditPrediction::MoveOutside { snapshot, target },
 8084                    completion_id: id,
 8085                    invalidation_range: None,
 8086                });
 8087                cx.notify();
 8088                return Some(());
 8089            }
 8090        };
 8091
 8092        let edits = edits
 8093            .into_iter()
 8094            .flat_map(|(range, new_text)| {
 8095                Some((
 8096                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8097                    new_text,
 8098                ))
 8099            })
 8100            .collect::<Vec<_>>();
 8101        if edits.is_empty() {
 8102            return None;
 8103        }
 8104
 8105        let first_edit_start = edits.first().unwrap().0.start;
 8106        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8107        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8108
 8109        let last_edit_end = edits.last().unwrap().0.end;
 8110        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8111        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8112
 8113        let cursor_row = cursor.to_point(&multibuffer).row;
 8114
 8115        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8116
 8117        let mut inlay_ids = Vec::new();
 8118        let invalidation_row_range;
 8119        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8120            Some(cursor_row..edit_end_row)
 8121        } else if cursor_row > edit_end_row {
 8122            Some(edit_start_row..cursor_row)
 8123        } else {
 8124            None
 8125        };
 8126        let supports_jump = self
 8127            .edit_prediction_provider
 8128            .as_ref()
 8129            .map(|provider| provider.provider.supports_jump_to_edit())
 8130            .unwrap_or(true);
 8131
 8132        let is_move = supports_jump
 8133            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8134        let completion = if is_move {
 8135            invalidation_row_range =
 8136                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8137            let target = first_edit_start;
 8138            EditPrediction::MoveWithin { target, snapshot }
 8139        } else {
 8140            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8141                && !self.edit_predictions_hidden_for_vim_mode;
 8142
 8143            if show_completions_in_buffer {
 8144                if let Some(provider) = &self.edit_prediction_provider {
 8145                    provider.provider.did_show(cx);
 8146                }
 8147                if edits
 8148                    .iter()
 8149                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8150                {
 8151                    let mut inlays = Vec::new();
 8152                    for (range, new_text) in &edits {
 8153                        let inlay = Inlay::edit_prediction(
 8154                            post_inc(&mut self.next_inlay_id),
 8155                            range.start,
 8156                            new_text.as_ref(),
 8157                        );
 8158                        inlay_ids.push(inlay.id);
 8159                        inlays.push(inlay);
 8160                    }
 8161
 8162                    self.splice_inlays(&[], inlays, cx);
 8163                } else {
 8164                    let background_color = cx.theme().status().deleted_background;
 8165                    self.highlight_text::<EditPredictionHighlight>(
 8166                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8167                        HighlightStyle {
 8168                            background_color: Some(background_color),
 8169                            ..Default::default()
 8170                        },
 8171                        cx,
 8172                    );
 8173                }
 8174            }
 8175
 8176            invalidation_row_range = edit_start_row..edit_end_row;
 8177
 8178            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8179                if provider.show_tab_accept_marker() {
 8180                    EditDisplayMode::TabAccept
 8181                } else {
 8182                    EditDisplayMode::Inline
 8183                }
 8184            } else {
 8185                EditDisplayMode::DiffPopover
 8186            };
 8187
 8188            EditPrediction::Edit {
 8189                edits,
 8190                edit_preview,
 8191                display_mode,
 8192                snapshot,
 8193            }
 8194        };
 8195
 8196        let invalidation_range = multibuffer
 8197            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8198            ..multibuffer.anchor_after(Point::new(
 8199                invalidation_row_range.end,
 8200                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8201            ));
 8202
 8203        self.stale_edit_prediction_in_menu = None;
 8204        self.active_edit_prediction = Some(EditPredictionState {
 8205            inlay_ids,
 8206            completion,
 8207            completion_id,
 8208            invalidation_range: Some(invalidation_range),
 8209        });
 8210
 8211        cx.notify();
 8212
 8213        Some(())
 8214    }
 8215
 8216    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8217        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8218    }
 8219
 8220    fn clear_tasks(&mut self) {
 8221        self.tasks.clear()
 8222    }
 8223
 8224    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8225        if self.tasks.insert(key, value).is_some() {
 8226            // This case should hopefully be rare, but just in case...
 8227            log::error!(
 8228                "multiple different run targets found on a single line, only the last target will be rendered"
 8229            )
 8230        }
 8231    }
 8232
 8233    /// Get all display points of breakpoints that will be rendered within editor
 8234    ///
 8235    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8236    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8237    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8238    fn active_breakpoints(
 8239        &self,
 8240        range: Range<DisplayRow>,
 8241        window: &mut Window,
 8242        cx: &mut Context<Self>,
 8243    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8244        let mut breakpoint_display_points = HashMap::default();
 8245
 8246        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8247            return breakpoint_display_points;
 8248        };
 8249
 8250        let snapshot = self.snapshot(window, cx);
 8251
 8252        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8253        let Some(project) = self.project() else {
 8254            return breakpoint_display_points;
 8255        };
 8256
 8257        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8258            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8259
 8260        for (buffer_snapshot, range, excerpt_id) in
 8261            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8262        {
 8263            let Some(buffer) = project
 8264                .read(cx)
 8265                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8266            else {
 8267                continue;
 8268            };
 8269            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8270                &buffer,
 8271                Some(
 8272                    buffer_snapshot.anchor_before(range.start)
 8273                        ..buffer_snapshot.anchor_after(range.end),
 8274                ),
 8275                buffer_snapshot,
 8276                cx,
 8277            );
 8278            for (breakpoint, state) in breakpoints {
 8279                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8280                let position = multi_buffer_anchor
 8281                    .to_point(&multi_buffer_snapshot)
 8282                    .to_display_point(&snapshot);
 8283
 8284                breakpoint_display_points.insert(
 8285                    position.row(),
 8286                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8287                );
 8288            }
 8289        }
 8290
 8291        breakpoint_display_points
 8292    }
 8293
 8294    fn breakpoint_context_menu(
 8295        &self,
 8296        anchor: Anchor,
 8297        window: &mut Window,
 8298        cx: &mut Context<Self>,
 8299    ) -> Entity<ui::ContextMenu> {
 8300        let weak_editor = cx.weak_entity();
 8301        let focus_handle = self.focus_handle(cx);
 8302
 8303        let row = self
 8304            .buffer
 8305            .read(cx)
 8306            .snapshot(cx)
 8307            .summary_for_anchor::<Point>(&anchor)
 8308            .row;
 8309
 8310        let breakpoint = self
 8311            .breakpoint_at_row(row, window, cx)
 8312            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8313
 8314        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8315            "Edit Log Breakpoint"
 8316        } else {
 8317            "Set Log Breakpoint"
 8318        };
 8319
 8320        let condition_breakpoint_msg = if breakpoint
 8321            .as_ref()
 8322            .is_some_and(|bp| bp.1.condition.is_some())
 8323        {
 8324            "Edit Condition Breakpoint"
 8325        } else {
 8326            "Set Condition Breakpoint"
 8327        };
 8328
 8329        let hit_condition_breakpoint_msg = if breakpoint
 8330            .as_ref()
 8331            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8332        {
 8333            "Edit Hit Condition Breakpoint"
 8334        } else {
 8335            "Set Hit Condition Breakpoint"
 8336        };
 8337
 8338        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8339            "Unset Breakpoint"
 8340        } else {
 8341            "Set Breakpoint"
 8342        };
 8343
 8344        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8345
 8346        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8347            BreakpointState::Enabled => Some("Disable"),
 8348            BreakpointState::Disabled => Some("Enable"),
 8349        });
 8350
 8351        let (anchor, breakpoint) =
 8352            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8353
 8354        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8355            menu.on_blur_subscription(Subscription::new(|| {}))
 8356                .context(focus_handle)
 8357                .when(run_to_cursor, |this| {
 8358                    let weak_editor = weak_editor.clone();
 8359                    this.entry("Run to cursor", None, move |window, cx| {
 8360                        weak_editor
 8361                            .update(cx, |editor, cx| {
 8362                                editor.change_selections(
 8363                                    SelectionEffects::no_scroll(),
 8364                                    window,
 8365                                    cx,
 8366                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8367                                );
 8368                            })
 8369                            .ok();
 8370
 8371                        window.dispatch_action(Box::new(RunToCursor), cx);
 8372                    })
 8373                    .separator()
 8374                })
 8375                .when_some(toggle_state_msg, |this, msg| {
 8376                    this.entry(msg, None, {
 8377                        let weak_editor = weak_editor.clone();
 8378                        let breakpoint = breakpoint.clone();
 8379                        move |_window, cx| {
 8380                            weak_editor
 8381                                .update(cx, |this, cx| {
 8382                                    this.edit_breakpoint_at_anchor(
 8383                                        anchor,
 8384                                        breakpoint.as_ref().clone(),
 8385                                        BreakpointEditAction::InvertState,
 8386                                        cx,
 8387                                    );
 8388                                })
 8389                                .log_err();
 8390                        }
 8391                    })
 8392                })
 8393                .entry(set_breakpoint_msg, None, {
 8394                    let weak_editor = weak_editor.clone();
 8395                    let breakpoint = breakpoint.clone();
 8396                    move |_window, cx| {
 8397                        weak_editor
 8398                            .update(cx, |this, cx| {
 8399                                this.edit_breakpoint_at_anchor(
 8400                                    anchor,
 8401                                    breakpoint.as_ref().clone(),
 8402                                    BreakpointEditAction::Toggle,
 8403                                    cx,
 8404                                );
 8405                            })
 8406                            .log_err();
 8407                    }
 8408                })
 8409                .entry(log_breakpoint_msg, None, {
 8410                    let breakpoint = breakpoint.clone();
 8411                    let weak_editor = weak_editor.clone();
 8412                    move |window, cx| {
 8413                        weak_editor
 8414                            .update(cx, |this, cx| {
 8415                                this.add_edit_breakpoint_block(
 8416                                    anchor,
 8417                                    breakpoint.as_ref(),
 8418                                    BreakpointPromptEditAction::Log,
 8419                                    window,
 8420                                    cx,
 8421                                );
 8422                            })
 8423                            .log_err();
 8424                    }
 8425                })
 8426                .entry(condition_breakpoint_msg, None, {
 8427                    let breakpoint = breakpoint.clone();
 8428                    let weak_editor = weak_editor.clone();
 8429                    move |window, cx| {
 8430                        weak_editor
 8431                            .update(cx, |this, cx| {
 8432                                this.add_edit_breakpoint_block(
 8433                                    anchor,
 8434                                    breakpoint.as_ref(),
 8435                                    BreakpointPromptEditAction::Condition,
 8436                                    window,
 8437                                    cx,
 8438                                );
 8439                            })
 8440                            .log_err();
 8441                    }
 8442                })
 8443                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8444                    weak_editor
 8445                        .update(cx, |this, cx| {
 8446                            this.add_edit_breakpoint_block(
 8447                                anchor,
 8448                                breakpoint.as_ref(),
 8449                                BreakpointPromptEditAction::HitCondition,
 8450                                window,
 8451                                cx,
 8452                            );
 8453                        })
 8454                        .log_err();
 8455                })
 8456        })
 8457    }
 8458
 8459    fn render_breakpoint(
 8460        &self,
 8461        position: Anchor,
 8462        row: DisplayRow,
 8463        breakpoint: &Breakpoint,
 8464        state: Option<BreakpointSessionState>,
 8465        cx: &mut Context<Self>,
 8466    ) -> IconButton {
 8467        let is_rejected = state.is_some_and(|s| !s.verified);
 8468        // Is it a breakpoint that shows up when hovering over gutter?
 8469        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8470            (false, false),
 8471            |PhantomBreakpointIndicator {
 8472                 is_active,
 8473                 display_row,
 8474                 collides_with_existing_breakpoint,
 8475             }| {
 8476                (
 8477                    is_active && display_row == row,
 8478                    collides_with_existing_breakpoint,
 8479                )
 8480            },
 8481        );
 8482
 8483        let (color, icon) = {
 8484            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8485                (false, false) => ui::IconName::DebugBreakpoint,
 8486                (true, false) => ui::IconName::DebugLogBreakpoint,
 8487                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8488                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8489            };
 8490
 8491            let color = cx.theme().colors();
 8492
 8493            let color = if is_phantom {
 8494                if collides_with_existing {
 8495                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8496                } else {
 8497                    Color::Hint
 8498                }
 8499            } else if is_rejected {
 8500                Color::Disabled
 8501            } else {
 8502                Color::Debugger
 8503            };
 8504
 8505            (color, icon)
 8506        };
 8507
 8508        let breakpoint = Arc::from(breakpoint.clone());
 8509
 8510        let alt_as_text = gpui::Keystroke {
 8511            modifiers: Modifiers::secondary_key(),
 8512            ..Default::default()
 8513        };
 8514        let primary_action_text = if breakpoint.is_disabled() {
 8515            "Enable breakpoint"
 8516        } else if is_phantom && !collides_with_existing {
 8517            "Set breakpoint"
 8518        } else {
 8519            "Unset breakpoint"
 8520        };
 8521        let focus_handle = self.focus_handle.clone();
 8522
 8523        let meta = if is_rejected {
 8524            SharedString::from("No executable code is associated with this line.")
 8525        } else if collides_with_existing && !breakpoint.is_disabled() {
 8526            SharedString::from(format!(
 8527                "{alt_as_text}-click to disable,\nright-click for more options."
 8528            ))
 8529        } else {
 8530            SharedString::from("Right-click for more options.")
 8531        };
 8532        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8533            .icon_size(IconSize::XSmall)
 8534            .size(ui::ButtonSize::None)
 8535            .when(is_rejected, |this| {
 8536                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8537            })
 8538            .icon_color(color)
 8539            .style(ButtonStyle::Transparent)
 8540            .on_click(cx.listener({
 8541                move |editor, event: &ClickEvent, window, cx| {
 8542                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8543                        BreakpointEditAction::InvertState
 8544                    } else {
 8545                        BreakpointEditAction::Toggle
 8546                    };
 8547
 8548                    window.focus(&editor.focus_handle(cx), cx);
 8549                    editor.edit_breakpoint_at_anchor(
 8550                        position,
 8551                        breakpoint.as_ref().clone(),
 8552                        edit_action,
 8553                        cx,
 8554                    );
 8555                }
 8556            }))
 8557            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8558                editor.set_breakpoint_context_menu(
 8559                    row,
 8560                    Some(position),
 8561                    event.position(),
 8562                    window,
 8563                    cx,
 8564                );
 8565            }))
 8566            .tooltip(move |_window, cx| {
 8567                Tooltip::with_meta_in(
 8568                    primary_action_text,
 8569                    Some(&ToggleBreakpoint),
 8570                    meta.clone(),
 8571                    &focus_handle,
 8572                    cx,
 8573                )
 8574            })
 8575    }
 8576
 8577    fn build_tasks_context(
 8578        project: &Entity<Project>,
 8579        buffer: &Entity<Buffer>,
 8580        buffer_row: u32,
 8581        tasks: &Arc<RunnableTasks>,
 8582        cx: &mut Context<Self>,
 8583    ) -> Task<Option<task::TaskContext>> {
 8584        let position = Point::new(buffer_row, tasks.column);
 8585        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8586        let location = Location {
 8587            buffer: buffer.clone(),
 8588            range: range_start..range_start,
 8589        };
 8590        // Fill in the environmental variables from the tree-sitter captures
 8591        let mut captured_task_variables = TaskVariables::default();
 8592        for (capture_name, value) in tasks.extra_variables.clone() {
 8593            captured_task_variables.insert(
 8594                task::VariableName::Custom(capture_name.into()),
 8595                value.clone(),
 8596            );
 8597        }
 8598        project.update(cx, |project, cx| {
 8599            project.task_store().update(cx, |task_store, cx| {
 8600                task_store.task_context_for_location(captured_task_variables, location, cx)
 8601            })
 8602        })
 8603    }
 8604
 8605    pub fn spawn_nearest_task(
 8606        &mut self,
 8607        action: &SpawnNearestTask,
 8608        window: &mut Window,
 8609        cx: &mut Context<Self>,
 8610    ) {
 8611        let Some((workspace, _)) = self.workspace.clone() else {
 8612            return;
 8613        };
 8614        let Some(project) = self.project.clone() else {
 8615            return;
 8616        };
 8617
 8618        // Try to find a closest, enclosing node using tree-sitter that has a task
 8619        let Some((buffer, buffer_row, tasks)) = self
 8620            .find_enclosing_node_task(cx)
 8621            // Or find the task that's closest in row-distance.
 8622            .or_else(|| self.find_closest_task(cx))
 8623        else {
 8624            return;
 8625        };
 8626
 8627        let reveal_strategy = action.reveal;
 8628        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8629        cx.spawn_in(window, async move |_, cx| {
 8630            let context = task_context.await?;
 8631            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8632
 8633            let resolved = &mut resolved_task.resolved;
 8634            resolved.reveal = reveal_strategy;
 8635
 8636            workspace
 8637                .update_in(cx, |workspace, window, cx| {
 8638                    workspace.schedule_resolved_task(
 8639                        task_source_kind,
 8640                        resolved_task,
 8641                        false,
 8642                        window,
 8643                        cx,
 8644                    );
 8645                })
 8646                .ok()
 8647        })
 8648        .detach();
 8649    }
 8650
 8651    fn find_closest_task(
 8652        &mut self,
 8653        cx: &mut Context<Self>,
 8654    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8655        let cursor_row = self
 8656            .selections
 8657            .newest_adjusted(&self.display_snapshot(cx))
 8658            .head()
 8659            .row;
 8660
 8661        let ((buffer_id, row), tasks) = self
 8662            .tasks
 8663            .iter()
 8664            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8665
 8666        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8667        let tasks = Arc::new(tasks.to_owned());
 8668        Some((buffer, *row, tasks))
 8669    }
 8670
 8671    fn find_enclosing_node_task(
 8672        &mut self,
 8673        cx: &mut Context<Self>,
 8674    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8675        let snapshot = self.buffer.read(cx).snapshot(cx);
 8676        let offset = self
 8677            .selections
 8678            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8679            .head();
 8680        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8681        let offset = excerpt.map_offset_to_buffer(offset);
 8682        let buffer_id = excerpt.buffer().remote_id();
 8683
 8684        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8685        let mut cursor = layer.node().walk();
 8686
 8687        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8688            if cursor.node().end_byte() == offset.0 {
 8689                cursor.goto_next_sibling();
 8690            }
 8691        }
 8692
 8693        // Ascend to the smallest ancestor that contains the range and has a task.
 8694        loop {
 8695            let node = cursor.node();
 8696            let node_range = node.byte_range();
 8697            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8698
 8699            // Check if this node contains our offset
 8700            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8701                // If it contains offset, check for task
 8702                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8703                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8704                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8705                }
 8706            }
 8707
 8708            if !cursor.goto_parent() {
 8709                break;
 8710            }
 8711        }
 8712        None
 8713    }
 8714
 8715    fn render_run_indicator(
 8716        &self,
 8717        _style: &EditorStyle,
 8718        is_active: bool,
 8719        row: DisplayRow,
 8720        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8721        cx: &mut Context<Self>,
 8722    ) -> IconButton {
 8723        let color = Color::Muted;
 8724        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8725
 8726        IconButton::new(
 8727            ("run_indicator", row.0 as usize),
 8728            ui::IconName::PlayOutlined,
 8729        )
 8730        .shape(ui::IconButtonShape::Square)
 8731        .icon_size(IconSize::XSmall)
 8732        .icon_color(color)
 8733        .toggle_state(is_active)
 8734        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8735            let quick_launch = match e {
 8736                ClickEvent::Keyboard(_) => true,
 8737                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8738            };
 8739
 8740            window.focus(&editor.focus_handle(cx), cx);
 8741            editor.toggle_code_actions(
 8742                &ToggleCodeActions {
 8743                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8744                    quick_launch,
 8745                },
 8746                window,
 8747                cx,
 8748            );
 8749        }))
 8750        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8751            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8752        }))
 8753    }
 8754
 8755    pub fn context_menu_visible(&self) -> bool {
 8756        !self.edit_prediction_preview_is_active()
 8757            && self
 8758                .context_menu
 8759                .borrow()
 8760                .as_ref()
 8761                .is_some_and(|menu| menu.visible())
 8762    }
 8763
 8764    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8765        self.context_menu
 8766            .borrow()
 8767            .as_ref()
 8768            .map(|menu| menu.origin())
 8769    }
 8770
 8771    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8772        self.context_menu_options = Some(options);
 8773    }
 8774
 8775    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8776    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8777
 8778    fn render_edit_prediction_popover(
 8779        &mut self,
 8780        text_bounds: &Bounds<Pixels>,
 8781        content_origin: gpui::Point<Pixels>,
 8782        right_margin: Pixels,
 8783        editor_snapshot: &EditorSnapshot,
 8784        visible_row_range: Range<DisplayRow>,
 8785        scroll_top: ScrollOffset,
 8786        scroll_bottom: ScrollOffset,
 8787        line_layouts: &[LineWithInvisibles],
 8788        line_height: Pixels,
 8789        scroll_position: gpui::Point<ScrollOffset>,
 8790        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8791        newest_selection_head: Option<DisplayPoint>,
 8792        editor_width: Pixels,
 8793        style: &EditorStyle,
 8794        window: &mut Window,
 8795        cx: &mut App,
 8796    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8797        if self.mode().is_minimap() {
 8798            return None;
 8799        }
 8800        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8801
 8802        if self.edit_prediction_visible_in_cursor_popover(true) {
 8803            return None;
 8804        }
 8805
 8806        match &active_edit_prediction.completion {
 8807            EditPrediction::MoveWithin { target, .. } => {
 8808                let target_display_point = target.to_display_point(editor_snapshot);
 8809
 8810                if self.edit_prediction_requires_modifier() {
 8811                    if !self.edit_prediction_preview_is_active() {
 8812                        return None;
 8813                    }
 8814
 8815                    self.render_edit_prediction_modifier_jump_popover(
 8816                        text_bounds,
 8817                        content_origin,
 8818                        visible_row_range,
 8819                        line_layouts,
 8820                        line_height,
 8821                        scroll_pixel_position,
 8822                        newest_selection_head,
 8823                        target_display_point,
 8824                        window,
 8825                        cx,
 8826                    )
 8827                } else {
 8828                    self.render_edit_prediction_eager_jump_popover(
 8829                        text_bounds,
 8830                        content_origin,
 8831                        editor_snapshot,
 8832                        visible_row_range,
 8833                        scroll_top,
 8834                        scroll_bottom,
 8835                        line_height,
 8836                        scroll_pixel_position,
 8837                        target_display_point,
 8838                        editor_width,
 8839                        window,
 8840                        cx,
 8841                    )
 8842                }
 8843            }
 8844            EditPrediction::Edit {
 8845                display_mode: EditDisplayMode::Inline,
 8846                ..
 8847            } => None,
 8848            EditPrediction::Edit {
 8849                display_mode: EditDisplayMode::TabAccept,
 8850                edits,
 8851                ..
 8852            } => {
 8853                let range = &edits.first()?.0;
 8854                let target_display_point = range.end.to_display_point(editor_snapshot);
 8855
 8856                self.render_edit_prediction_end_of_line_popover(
 8857                    "Accept",
 8858                    editor_snapshot,
 8859                    visible_row_range,
 8860                    target_display_point,
 8861                    line_height,
 8862                    scroll_pixel_position,
 8863                    content_origin,
 8864                    editor_width,
 8865                    window,
 8866                    cx,
 8867                )
 8868            }
 8869            EditPrediction::Edit {
 8870                edits,
 8871                edit_preview,
 8872                display_mode: EditDisplayMode::DiffPopover,
 8873                snapshot,
 8874            } => self.render_edit_prediction_diff_popover(
 8875                text_bounds,
 8876                content_origin,
 8877                right_margin,
 8878                editor_snapshot,
 8879                visible_row_range,
 8880                line_layouts,
 8881                line_height,
 8882                scroll_position,
 8883                scroll_pixel_position,
 8884                newest_selection_head,
 8885                editor_width,
 8886                style,
 8887                edits,
 8888                edit_preview,
 8889                snapshot,
 8890                window,
 8891                cx,
 8892            ),
 8893            EditPrediction::MoveOutside { snapshot, .. } => {
 8894                let mut element = self
 8895                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 8896                    .into_any();
 8897
 8898                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8899                let origin_x = text_bounds.size.width - size.width - px(30.);
 8900                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 8901                element.prepaint_at(origin, window, cx);
 8902
 8903                Some((element, origin))
 8904            }
 8905        }
 8906    }
 8907
 8908    fn render_edit_prediction_modifier_jump_popover(
 8909        &mut self,
 8910        text_bounds: &Bounds<Pixels>,
 8911        content_origin: gpui::Point<Pixels>,
 8912        visible_row_range: Range<DisplayRow>,
 8913        line_layouts: &[LineWithInvisibles],
 8914        line_height: Pixels,
 8915        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8916        newest_selection_head: Option<DisplayPoint>,
 8917        target_display_point: DisplayPoint,
 8918        window: &mut Window,
 8919        cx: &mut App,
 8920    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8921        let scrolled_content_origin =
 8922            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8923
 8924        const SCROLL_PADDING_Y: Pixels = px(12.);
 8925
 8926        if target_display_point.row() < visible_row_range.start {
 8927            return self.render_edit_prediction_scroll_popover(
 8928                |_| SCROLL_PADDING_Y,
 8929                IconName::ArrowUp,
 8930                visible_row_range,
 8931                line_layouts,
 8932                newest_selection_head,
 8933                scrolled_content_origin,
 8934                window,
 8935                cx,
 8936            );
 8937        } else if target_display_point.row() >= visible_row_range.end {
 8938            return self.render_edit_prediction_scroll_popover(
 8939                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8940                IconName::ArrowDown,
 8941                visible_row_range,
 8942                line_layouts,
 8943                newest_selection_head,
 8944                scrolled_content_origin,
 8945                window,
 8946                cx,
 8947            );
 8948        }
 8949
 8950        const POLE_WIDTH: Pixels = px(2.);
 8951
 8952        let line_layout =
 8953            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8954        let target_column = target_display_point.column() as usize;
 8955
 8956        let target_x = line_layout.x_for_index(target_column);
 8957        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8958            - scroll_pixel_position.y;
 8959
 8960        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8961
 8962        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8963        border_color.l += 0.001;
 8964
 8965        let mut element = v_flex()
 8966            .items_end()
 8967            .when(flag_on_right, |el| el.items_start())
 8968            .child(if flag_on_right {
 8969                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8970                    .rounded_bl(px(0.))
 8971                    .rounded_tl(px(0.))
 8972                    .border_l_2()
 8973                    .border_color(border_color)
 8974            } else {
 8975                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8976                    .rounded_br(px(0.))
 8977                    .rounded_tr(px(0.))
 8978                    .border_r_2()
 8979                    .border_color(border_color)
 8980            })
 8981            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8982            .into_any();
 8983
 8984        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8985
 8986        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8987            - point(
 8988                if flag_on_right {
 8989                    POLE_WIDTH
 8990                } else {
 8991                    size.width - POLE_WIDTH
 8992                },
 8993                size.height - line_height,
 8994            );
 8995
 8996        origin.x = origin.x.max(content_origin.x);
 8997
 8998        element.prepaint_at(origin, window, cx);
 8999
 9000        Some((element, origin))
 9001    }
 9002
 9003    fn render_edit_prediction_scroll_popover(
 9004        &mut self,
 9005        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9006        scroll_icon: IconName,
 9007        visible_row_range: Range<DisplayRow>,
 9008        line_layouts: &[LineWithInvisibles],
 9009        newest_selection_head: Option<DisplayPoint>,
 9010        scrolled_content_origin: gpui::Point<Pixels>,
 9011        window: &mut Window,
 9012        cx: &mut App,
 9013    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9014        let mut element = self
 9015            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9016            .into_any();
 9017
 9018        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9019
 9020        let cursor = newest_selection_head?;
 9021        let cursor_row_layout =
 9022            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9023        let cursor_column = cursor.column() as usize;
 9024
 9025        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9026
 9027        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9028
 9029        element.prepaint_at(origin, window, cx);
 9030        Some((element, origin))
 9031    }
 9032
 9033    fn render_edit_prediction_eager_jump_popover(
 9034        &mut self,
 9035        text_bounds: &Bounds<Pixels>,
 9036        content_origin: gpui::Point<Pixels>,
 9037        editor_snapshot: &EditorSnapshot,
 9038        visible_row_range: Range<DisplayRow>,
 9039        scroll_top: ScrollOffset,
 9040        scroll_bottom: ScrollOffset,
 9041        line_height: Pixels,
 9042        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9043        target_display_point: DisplayPoint,
 9044        editor_width: Pixels,
 9045        window: &mut Window,
 9046        cx: &mut App,
 9047    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9048        if target_display_point.row().as_f64() < scroll_top {
 9049            let mut element = self
 9050                .render_edit_prediction_line_popover(
 9051                    "Jump to Edit",
 9052                    Some(IconName::ArrowUp),
 9053                    window,
 9054                    cx,
 9055                )
 9056                .into_any();
 9057
 9058            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9059            let offset = point(
 9060                (text_bounds.size.width - size.width) / 2.,
 9061                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9062            );
 9063
 9064            let origin = text_bounds.origin + offset;
 9065            element.prepaint_at(origin, window, cx);
 9066            Some((element, origin))
 9067        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9068            let mut element = self
 9069                .render_edit_prediction_line_popover(
 9070                    "Jump to Edit",
 9071                    Some(IconName::ArrowDown),
 9072                    window,
 9073                    cx,
 9074                )
 9075                .into_any();
 9076
 9077            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9078            let offset = point(
 9079                (text_bounds.size.width - size.width) / 2.,
 9080                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9081            );
 9082
 9083            let origin = text_bounds.origin + offset;
 9084            element.prepaint_at(origin, window, cx);
 9085            Some((element, origin))
 9086        } else {
 9087            self.render_edit_prediction_end_of_line_popover(
 9088                "Jump to Edit",
 9089                editor_snapshot,
 9090                visible_row_range,
 9091                target_display_point,
 9092                line_height,
 9093                scroll_pixel_position,
 9094                content_origin,
 9095                editor_width,
 9096                window,
 9097                cx,
 9098            )
 9099        }
 9100    }
 9101
 9102    fn render_edit_prediction_end_of_line_popover(
 9103        self: &mut Editor,
 9104        label: &'static str,
 9105        editor_snapshot: &EditorSnapshot,
 9106        visible_row_range: Range<DisplayRow>,
 9107        target_display_point: DisplayPoint,
 9108        line_height: Pixels,
 9109        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9110        content_origin: gpui::Point<Pixels>,
 9111        editor_width: Pixels,
 9112        window: &mut Window,
 9113        cx: &mut App,
 9114    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9115        let target_line_end = DisplayPoint::new(
 9116            target_display_point.row(),
 9117            editor_snapshot.line_len(target_display_point.row()),
 9118        );
 9119
 9120        let mut element = self
 9121            .render_edit_prediction_line_popover(label, None, window, cx)
 9122            .into_any();
 9123
 9124        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9125
 9126        let line_origin =
 9127            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9128
 9129        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9130        let mut origin = start_point
 9131            + line_origin
 9132            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9133        origin.x = origin.x.max(content_origin.x);
 9134
 9135        let max_x = content_origin.x + editor_width - size.width;
 9136
 9137        if origin.x > max_x {
 9138            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9139
 9140            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9141                origin.y += offset;
 9142                IconName::ArrowUp
 9143            } else {
 9144                origin.y -= offset;
 9145                IconName::ArrowDown
 9146            };
 9147
 9148            element = self
 9149                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9150                .into_any();
 9151
 9152            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9153
 9154            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9155        }
 9156
 9157        element.prepaint_at(origin, window, cx);
 9158        Some((element, origin))
 9159    }
 9160
 9161    fn render_edit_prediction_diff_popover(
 9162        self: &Editor,
 9163        text_bounds: &Bounds<Pixels>,
 9164        content_origin: gpui::Point<Pixels>,
 9165        right_margin: Pixels,
 9166        editor_snapshot: &EditorSnapshot,
 9167        visible_row_range: Range<DisplayRow>,
 9168        line_layouts: &[LineWithInvisibles],
 9169        line_height: Pixels,
 9170        scroll_position: gpui::Point<ScrollOffset>,
 9171        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9172        newest_selection_head: Option<DisplayPoint>,
 9173        editor_width: Pixels,
 9174        style: &EditorStyle,
 9175        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9176        edit_preview: &Option<language::EditPreview>,
 9177        snapshot: &language::BufferSnapshot,
 9178        window: &mut Window,
 9179        cx: &mut App,
 9180    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9181        let edit_start = edits
 9182            .first()
 9183            .unwrap()
 9184            .0
 9185            .start
 9186            .to_display_point(editor_snapshot);
 9187        let edit_end = edits
 9188            .last()
 9189            .unwrap()
 9190            .0
 9191            .end
 9192            .to_display_point(editor_snapshot);
 9193
 9194        let is_visible = visible_row_range.contains(&edit_start.row())
 9195            || visible_row_range.contains(&edit_end.row());
 9196        if !is_visible {
 9197            return None;
 9198        }
 9199
 9200        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9201            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9202        } else {
 9203            // Fallback for providers without edit_preview
 9204            crate::edit_prediction_fallback_text(edits, cx)
 9205        };
 9206
 9207        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9208        let line_count = highlighted_edits.text.lines().count();
 9209
 9210        const BORDER_WIDTH: Pixels = px(1.);
 9211
 9212        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9213        let has_keybind = keybind.is_some();
 9214
 9215        let mut element = h_flex()
 9216            .items_start()
 9217            .child(
 9218                h_flex()
 9219                    .bg(cx.theme().colors().editor_background)
 9220                    .border(BORDER_WIDTH)
 9221                    .shadow_xs()
 9222                    .border_color(cx.theme().colors().border)
 9223                    .rounded_l_lg()
 9224                    .when(line_count > 1, |el| el.rounded_br_lg())
 9225                    .pr_1()
 9226                    .child(styled_text),
 9227            )
 9228            .child(
 9229                h_flex()
 9230                    .h(line_height + BORDER_WIDTH * 2.)
 9231                    .px_1p5()
 9232                    .gap_1()
 9233                    // Workaround: For some reason, there's a gap if we don't do this
 9234                    .ml(-BORDER_WIDTH)
 9235                    .shadow(vec![gpui::BoxShadow {
 9236                        color: gpui::black().opacity(0.05),
 9237                        offset: point(px(1.), px(1.)),
 9238                        blur_radius: px(2.),
 9239                        spread_radius: px(0.),
 9240                    }])
 9241                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9242                    .border(BORDER_WIDTH)
 9243                    .border_color(cx.theme().colors().border)
 9244                    .rounded_r_lg()
 9245                    .id("edit_prediction_diff_popover_keybind")
 9246                    .when(!has_keybind, |el| {
 9247                        let status_colors = cx.theme().status();
 9248
 9249                        el.bg(status_colors.error_background)
 9250                            .border_color(status_colors.error.opacity(0.6))
 9251                            .child(Icon::new(IconName::Info).color(Color::Error))
 9252                            .cursor_default()
 9253                            .hoverable_tooltip(move |_window, cx| {
 9254                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9255                            })
 9256                    })
 9257                    .children(keybind),
 9258            )
 9259            .into_any();
 9260
 9261        let longest_row =
 9262            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9263        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9264            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9265        } else {
 9266            layout_line(
 9267                longest_row,
 9268                editor_snapshot,
 9269                style,
 9270                editor_width,
 9271                |_| false,
 9272                window,
 9273                cx,
 9274            )
 9275            .width
 9276        };
 9277
 9278        let viewport_bounds =
 9279            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9280                right: -right_margin,
 9281                ..Default::default()
 9282            });
 9283
 9284        let x_after_longest = Pixels::from(
 9285            ScrollPixelOffset::from(
 9286                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9287            ) - scroll_pixel_position.x,
 9288        );
 9289
 9290        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9291
 9292        // Fully visible if it can be displayed within the window (allow overlapping other
 9293        // panes). However, this is only allowed if the popover starts within text_bounds.
 9294        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9295            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9296
 9297        let mut origin = if can_position_to_the_right {
 9298            point(
 9299                x_after_longest,
 9300                text_bounds.origin.y
 9301                    + Pixels::from(
 9302                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9303                            - scroll_pixel_position.y,
 9304                    ),
 9305            )
 9306        } else {
 9307            let cursor_row = newest_selection_head.map(|head| head.row());
 9308            let above_edit = edit_start
 9309                .row()
 9310                .0
 9311                .checked_sub(line_count as u32)
 9312                .map(DisplayRow);
 9313            let below_edit = Some(edit_end.row() + 1);
 9314            let above_cursor =
 9315                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9316            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9317
 9318            // Place the edit popover adjacent to the edit if there is a location
 9319            // available that is onscreen and does not obscure the cursor. Otherwise,
 9320            // place it adjacent to the cursor.
 9321            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9322                .into_iter()
 9323                .flatten()
 9324                .find(|&start_row| {
 9325                    let end_row = start_row + line_count as u32;
 9326                    visible_row_range.contains(&start_row)
 9327                        && visible_row_range.contains(&end_row)
 9328                        && cursor_row
 9329                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9330                })?;
 9331
 9332            content_origin
 9333                + point(
 9334                    Pixels::from(-scroll_pixel_position.x),
 9335                    Pixels::from(
 9336                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9337                    ),
 9338                )
 9339        };
 9340
 9341        origin.x -= BORDER_WIDTH;
 9342
 9343        window.defer_draw(element, origin, 1);
 9344
 9345        // Do not return an element, since it will already be drawn due to defer_draw.
 9346        None
 9347    }
 9348
 9349    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9350        px(30.)
 9351    }
 9352
 9353    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9354        if self.read_only(cx) {
 9355            cx.theme().players().read_only()
 9356        } else {
 9357            self.style.as_ref().unwrap().local_player
 9358        }
 9359    }
 9360
 9361    fn render_edit_prediction_accept_keybind(
 9362        &self,
 9363        window: &mut Window,
 9364        cx: &mut App,
 9365    ) -> Option<AnyElement> {
 9366        let accept_binding =
 9367            self.accept_edit_prediction_keybind(EditPredictionGranularity::Full, window, cx);
 9368        let accept_keystroke = accept_binding.keystroke()?;
 9369
 9370        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9371
 9372        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9373            Color::Accent
 9374        } else {
 9375            Color::Muted
 9376        };
 9377
 9378        h_flex()
 9379            .px_0p5()
 9380            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9381            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9382            .text_size(TextSize::XSmall.rems(cx))
 9383            .child(h_flex().children(ui::render_modifiers(
 9384                accept_keystroke.modifiers(),
 9385                PlatformStyle::platform(),
 9386                Some(modifiers_color),
 9387                Some(IconSize::XSmall.rems().into()),
 9388                true,
 9389            )))
 9390            .when(is_platform_style_mac, |parent| {
 9391                parent.child(accept_keystroke.key().to_string())
 9392            })
 9393            .when(!is_platform_style_mac, |parent| {
 9394                parent.child(
 9395                    Key::new(
 9396                        util::capitalize(accept_keystroke.key()),
 9397                        Some(Color::Default),
 9398                    )
 9399                    .size(Some(IconSize::XSmall.rems().into())),
 9400                )
 9401            })
 9402            .into_any()
 9403            .into()
 9404    }
 9405
 9406    fn render_edit_prediction_line_popover(
 9407        &self,
 9408        label: impl Into<SharedString>,
 9409        icon: Option<IconName>,
 9410        window: &mut Window,
 9411        cx: &mut App,
 9412    ) -> Stateful<Div> {
 9413        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9414
 9415        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9416        let has_keybind = keybind.is_some();
 9417
 9418        h_flex()
 9419            .id("ep-line-popover")
 9420            .py_0p5()
 9421            .pl_1()
 9422            .pr(padding_right)
 9423            .gap_1()
 9424            .rounded_md()
 9425            .border_1()
 9426            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9427            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9428            .shadow_xs()
 9429            .when(!has_keybind, |el| {
 9430                let status_colors = cx.theme().status();
 9431
 9432                el.bg(status_colors.error_background)
 9433                    .border_color(status_colors.error.opacity(0.6))
 9434                    .pl_2()
 9435                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9436                    .cursor_default()
 9437                    .hoverable_tooltip(move |_window, cx| {
 9438                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9439                    })
 9440            })
 9441            .children(keybind)
 9442            .child(
 9443                Label::new(label)
 9444                    .size(LabelSize::Small)
 9445                    .when(!has_keybind, |el| {
 9446                        el.color(cx.theme().status().error.into()).strikethrough()
 9447                    }),
 9448            )
 9449            .when(!has_keybind, |el| {
 9450                el.child(
 9451                    h_flex().ml_1().child(
 9452                        Icon::new(IconName::Info)
 9453                            .size(IconSize::Small)
 9454                            .color(cx.theme().status().error.into()),
 9455                    ),
 9456                )
 9457            })
 9458            .when_some(icon, |element, icon| {
 9459                element.child(
 9460                    div()
 9461                        .mt(px(1.5))
 9462                        .child(Icon::new(icon).size(IconSize::Small)),
 9463                )
 9464            })
 9465    }
 9466
 9467    fn render_edit_prediction_jump_outside_popover(
 9468        &self,
 9469        snapshot: &BufferSnapshot,
 9470        window: &mut Window,
 9471        cx: &mut App,
 9472    ) -> Stateful<Div> {
 9473        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9474        let has_keybind = keybind.is_some();
 9475
 9476        let file_name = snapshot
 9477            .file()
 9478            .map(|file| SharedString::new(file.file_name(cx)))
 9479            .unwrap_or(SharedString::new_static("untitled"));
 9480
 9481        h_flex()
 9482            .id("ep-jump-outside-popover")
 9483            .py_1()
 9484            .px_2()
 9485            .gap_1()
 9486            .rounded_md()
 9487            .border_1()
 9488            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9489            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9490            .shadow_xs()
 9491            .when(!has_keybind, |el| {
 9492                let status_colors = cx.theme().status();
 9493
 9494                el.bg(status_colors.error_background)
 9495                    .border_color(status_colors.error.opacity(0.6))
 9496                    .pl_2()
 9497                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9498                    .cursor_default()
 9499                    .hoverable_tooltip(move |_window, cx| {
 9500                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9501                    })
 9502            })
 9503            .children(keybind)
 9504            .child(
 9505                Label::new(file_name)
 9506                    .size(LabelSize::Small)
 9507                    .buffer_font(cx)
 9508                    .when(!has_keybind, |el| {
 9509                        el.color(cx.theme().status().error.into()).strikethrough()
 9510                    }),
 9511            )
 9512            .when(!has_keybind, |el| {
 9513                el.child(
 9514                    h_flex().ml_1().child(
 9515                        Icon::new(IconName::Info)
 9516                            .size(IconSize::Small)
 9517                            .color(cx.theme().status().error.into()),
 9518                    ),
 9519                )
 9520            })
 9521            .child(
 9522                div()
 9523                    .mt(px(1.5))
 9524                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9525            )
 9526    }
 9527
 9528    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9529        let accent_color = cx.theme().colors().text_accent;
 9530        let editor_bg_color = cx.theme().colors().editor_background;
 9531        editor_bg_color.blend(accent_color.opacity(0.1))
 9532    }
 9533
 9534    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9535        let accent_color = cx.theme().colors().text_accent;
 9536        let editor_bg_color = cx.theme().colors().editor_background;
 9537        editor_bg_color.blend(accent_color.opacity(0.6))
 9538    }
 9539    fn get_prediction_provider_icon_name(
 9540        provider: &Option<RegisteredEditPredictionDelegate>,
 9541    ) -> IconName {
 9542        match provider {
 9543            Some(provider) => match provider.provider.name() {
 9544                "copilot" => IconName::Copilot,
 9545                "supermaven" => IconName::Supermaven,
 9546                _ => IconName::ZedPredict,
 9547            },
 9548            None => IconName::ZedPredict,
 9549        }
 9550    }
 9551
 9552    fn render_edit_prediction_cursor_popover(
 9553        &self,
 9554        min_width: Pixels,
 9555        max_width: Pixels,
 9556        cursor_point: Point,
 9557        style: &EditorStyle,
 9558        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9559        _window: &Window,
 9560        cx: &mut Context<Editor>,
 9561    ) -> Option<AnyElement> {
 9562        let provider = self.edit_prediction_provider.as_ref()?;
 9563        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9564
 9565        let is_refreshing = provider.provider.is_refreshing(cx);
 9566
 9567        fn pending_completion_container(icon: IconName) -> Div {
 9568            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9569        }
 9570
 9571        let completion = match &self.active_edit_prediction {
 9572            Some(prediction) => {
 9573                if !self.has_visible_completions_menu() {
 9574                    const RADIUS: Pixels = px(6.);
 9575                    const BORDER_WIDTH: Pixels = px(1.);
 9576
 9577                    return Some(
 9578                        h_flex()
 9579                            .elevation_2(cx)
 9580                            .border(BORDER_WIDTH)
 9581                            .border_color(cx.theme().colors().border)
 9582                            .when(accept_keystroke.is_none(), |el| {
 9583                                el.border_color(cx.theme().status().error)
 9584                            })
 9585                            .rounded(RADIUS)
 9586                            .rounded_tl(px(0.))
 9587                            .overflow_hidden()
 9588                            .child(div().px_1p5().child(match &prediction.completion {
 9589                                EditPrediction::MoveWithin { target, snapshot } => {
 9590                                    use text::ToPoint as _;
 9591                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9592                                    {
 9593                                        Icon::new(IconName::ZedPredictDown)
 9594                                    } else {
 9595                                        Icon::new(IconName::ZedPredictUp)
 9596                                    }
 9597                                }
 9598                                EditPrediction::MoveOutside { .. } => {
 9599                                    // TODO [zeta2] custom icon for external jump?
 9600                                    Icon::new(provider_icon)
 9601                                }
 9602                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9603                            }))
 9604                            .child(
 9605                                h_flex()
 9606                                    .gap_1()
 9607                                    .py_1()
 9608                                    .px_2()
 9609                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9610                                    .border_l_1()
 9611                                    .border_color(cx.theme().colors().border)
 9612                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9613                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9614                                        el.child(
 9615                                            Label::new("Hold")
 9616                                                .size(LabelSize::Small)
 9617                                                .when(accept_keystroke.is_none(), |el| {
 9618                                                    el.strikethrough()
 9619                                                })
 9620                                                .line_height_style(LineHeightStyle::UiLabel),
 9621                                        )
 9622                                    })
 9623                                    .id("edit_prediction_cursor_popover_keybind")
 9624                                    .when(accept_keystroke.is_none(), |el| {
 9625                                        let status_colors = cx.theme().status();
 9626
 9627                                        el.bg(status_colors.error_background)
 9628                                            .border_color(status_colors.error.opacity(0.6))
 9629                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9630                                            .cursor_default()
 9631                                            .hoverable_tooltip(move |_window, cx| {
 9632                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9633                                                    .into()
 9634                                            })
 9635                                    })
 9636                                    .when_some(
 9637                                        accept_keystroke.as_ref(),
 9638                                        |el, accept_keystroke| {
 9639                                            el.child(h_flex().children(ui::render_modifiers(
 9640                                                accept_keystroke.modifiers(),
 9641                                                PlatformStyle::platform(),
 9642                                                Some(Color::Default),
 9643                                                Some(IconSize::XSmall.rems().into()),
 9644                                                false,
 9645                                            )))
 9646                                        },
 9647                                    ),
 9648                            )
 9649                            .into_any(),
 9650                    );
 9651                }
 9652
 9653                self.render_edit_prediction_cursor_popover_preview(
 9654                    prediction,
 9655                    cursor_point,
 9656                    style,
 9657                    cx,
 9658                )?
 9659            }
 9660
 9661            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9662                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9663                    stale_completion,
 9664                    cursor_point,
 9665                    style,
 9666                    cx,
 9667                )?,
 9668
 9669                None => pending_completion_container(provider_icon)
 9670                    .child(Label::new("...").size(LabelSize::Small)),
 9671            },
 9672
 9673            None => pending_completion_container(provider_icon)
 9674                .child(Label::new("...").size(LabelSize::Small)),
 9675        };
 9676
 9677        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9678            completion
 9679                .with_animation(
 9680                    "loading-completion",
 9681                    Animation::new(Duration::from_secs(2))
 9682                        .repeat()
 9683                        .with_easing(pulsating_between(0.4, 0.8)),
 9684                    |label, delta| label.opacity(delta),
 9685                )
 9686                .into_any_element()
 9687        } else {
 9688            completion.into_any_element()
 9689        };
 9690
 9691        let has_completion = self.active_edit_prediction.is_some();
 9692
 9693        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9694        Some(
 9695            h_flex()
 9696                .min_w(min_width)
 9697                .max_w(max_width)
 9698                .flex_1()
 9699                .elevation_2(cx)
 9700                .border_color(cx.theme().colors().border)
 9701                .child(
 9702                    div()
 9703                        .flex_1()
 9704                        .py_1()
 9705                        .px_2()
 9706                        .overflow_hidden()
 9707                        .child(completion),
 9708                )
 9709                .when_some(accept_keystroke, |el, accept_keystroke| {
 9710                    if !accept_keystroke.modifiers().modified() {
 9711                        return el;
 9712                    }
 9713
 9714                    el.child(
 9715                        h_flex()
 9716                            .h_full()
 9717                            .border_l_1()
 9718                            .rounded_r_lg()
 9719                            .border_color(cx.theme().colors().border)
 9720                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9721                            .gap_1()
 9722                            .py_1()
 9723                            .px_2()
 9724                            .child(
 9725                                h_flex()
 9726                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9727                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9728                                    .child(h_flex().children(ui::render_modifiers(
 9729                                        accept_keystroke.modifiers(),
 9730                                        PlatformStyle::platform(),
 9731                                        Some(if !has_completion {
 9732                                            Color::Muted
 9733                                        } else {
 9734                                            Color::Default
 9735                                        }),
 9736                                        None,
 9737                                        false,
 9738                                    ))),
 9739                            )
 9740                            .child(Label::new("Preview").into_any_element())
 9741                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9742                    )
 9743                })
 9744                .into_any(),
 9745        )
 9746    }
 9747
 9748    fn render_edit_prediction_cursor_popover_preview(
 9749        &self,
 9750        completion: &EditPredictionState,
 9751        cursor_point: Point,
 9752        style: &EditorStyle,
 9753        cx: &mut Context<Editor>,
 9754    ) -> Option<Div> {
 9755        use text::ToPoint as _;
 9756
 9757        fn render_relative_row_jump(
 9758            prefix: impl Into<String>,
 9759            current_row: u32,
 9760            target_row: u32,
 9761        ) -> Div {
 9762            let (row_diff, arrow) = if target_row < current_row {
 9763                (current_row - target_row, IconName::ArrowUp)
 9764            } else {
 9765                (target_row - current_row, IconName::ArrowDown)
 9766            };
 9767
 9768            h_flex()
 9769                .child(
 9770                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9771                        .color(Color::Muted)
 9772                        .size(LabelSize::Small),
 9773                )
 9774                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9775        }
 9776
 9777        let supports_jump = self
 9778            .edit_prediction_provider
 9779            .as_ref()
 9780            .map(|provider| provider.provider.supports_jump_to_edit())
 9781            .unwrap_or(true);
 9782
 9783        match &completion.completion {
 9784            EditPrediction::MoveWithin {
 9785                target, snapshot, ..
 9786            } => {
 9787                if !supports_jump {
 9788                    return None;
 9789                }
 9790
 9791                Some(
 9792                    h_flex()
 9793                        .px_2()
 9794                        .gap_2()
 9795                        .flex_1()
 9796                        .child(
 9797                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9798                                Icon::new(IconName::ZedPredictDown)
 9799                            } else {
 9800                                Icon::new(IconName::ZedPredictUp)
 9801                            },
 9802                        )
 9803                        .child(Label::new("Jump to Edit")),
 9804                )
 9805            }
 9806            EditPrediction::MoveOutside { snapshot, .. } => {
 9807                let file_name = snapshot
 9808                    .file()
 9809                    .map(|file| file.file_name(cx))
 9810                    .unwrap_or("untitled");
 9811                Some(
 9812                    h_flex()
 9813                        .px_2()
 9814                        .gap_2()
 9815                        .flex_1()
 9816                        .child(Icon::new(IconName::ZedPredict))
 9817                        .child(Label::new(format!("Jump to {file_name}"))),
 9818                )
 9819            }
 9820            EditPrediction::Edit {
 9821                edits,
 9822                edit_preview,
 9823                snapshot,
 9824                display_mode: _,
 9825            } => {
 9826                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9827
 9828                let (highlighted_edits, has_more_lines) =
 9829                    if let Some(edit_preview) = edit_preview.as_ref() {
 9830                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9831                            .first_line_preview()
 9832                    } else {
 9833                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9834                    };
 9835
 9836                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9837                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9838
 9839                let preview = h_flex()
 9840                    .gap_1()
 9841                    .min_w_16()
 9842                    .child(styled_text)
 9843                    .when(has_more_lines, |parent| parent.child(""));
 9844
 9845                let left = if supports_jump && first_edit_row != cursor_point.row {
 9846                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9847                        .into_any_element()
 9848                } else {
 9849                    let icon_name =
 9850                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9851                    Icon::new(icon_name).into_any_element()
 9852                };
 9853
 9854                Some(
 9855                    h_flex()
 9856                        .h_full()
 9857                        .flex_1()
 9858                        .gap_2()
 9859                        .pr_1()
 9860                        .overflow_x_hidden()
 9861                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9862                        .child(left)
 9863                        .child(preview),
 9864                )
 9865            }
 9866        }
 9867    }
 9868
 9869    pub fn render_context_menu(
 9870        &mut self,
 9871        max_height_in_lines: u32,
 9872        window: &mut Window,
 9873        cx: &mut Context<Editor>,
 9874    ) -> Option<AnyElement> {
 9875        let menu = self.context_menu.borrow();
 9876        let menu = menu.as_ref()?;
 9877        if !menu.visible() {
 9878            return None;
 9879        };
 9880        self.style
 9881            .as_ref()
 9882            .map(|style| menu.render(style, max_height_in_lines, window, cx))
 9883    }
 9884
 9885    fn render_context_menu_aside(
 9886        &mut self,
 9887        max_size: Size<Pixels>,
 9888        window: &mut Window,
 9889        cx: &mut Context<Editor>,
 9890    ) -> Option<AnyElement> {
 9891        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9892            if menu.visible() {
 9893                menu.render_aside(max_size, window, cx)
 9894            } else {
 9895                None
 9896            }
 9897        })
 9898    }
 9899
 9900    fn hide_context_menu(
 9901        &mut self,
 9902        window: &mut Window,
 9903        cx: &mut Context<Self>,
 9904    ) -> Option<CodeContextMenu> {
 9905        cx.notify();
 9906        self.completion_tasks.clear();
 9907        let context_menu = self.context_menu.borrow_mut().take();
 9908        self.stale_edit_prediction_in_menu.take();
 9909        self.update_visible_edit_prediction(window, cx);
 9910        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9911            && let Some(completion_provider) = &self.completion_provider
 9912        {
 9913            completion_provider.selection_changed(None, window, cx);
 9914        }
 9915        context_menu
 9916    }
 9917
 9918    fn show_snippet_choices(
 9919        &mut self,
 9920        choices: &Vec<String>,
 9921        selection: Range<Anchor>,
 9922        cx: &mut Context<Self>,
 9923    ) {
 9924        let Some((_, buffer, _)) = self
 9925            .buffer()
 9926            .read(cx)
 9927            .excerpt_containing(selection.start, cx)
 9928        else {
 9929            return;
 9930        };
 9931        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9932        else {
 9933            return;
 9934        };
 9935        if buffer != end_buffer {
 9936            log::error!("expected anchor range to have matching buffer IDs");
 9937            return;
 9938        }
 9939
 9940        let id = post_inc(&mut self.next_completion_id);
 9941        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9942        let mut context_menu = self.context_menu.borrow_mut();
 9943        let old_menu = context_menu.take();
 9944        *context_menu = Some(CodeContextMenu::Completions(
 9945            CompletionsMenu::new_snippet_choices(
 9946                id,
 9947                true,
 9948                choices,
 9949                selection,
 9950                buffer,
 9951                old_menu.map(|menu| menu.primary_scroll_handle()),
 9952                snippet_sort_order,
 9953            ),
 9954        ));
 9955    }
 9956
 9957    pub fn insert_snippet(
 9958        &mut self,
 9959        insertion_ranges: &[Range<MultiBufferOffset>],
 9960        snippet: Snippet,
 9961        window: &mut Window,
 9962        cx: &mut Context<Self>,
 9963    ) -> Result<()> {
 9964        struct Tabstop<T> {
 9965            is_end_tabstop: bool,
 9966            ranges: Vec<Range<T>>,
 9967            choices: Option<Vec<String>>,
 9968        }
 9969
 9970        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9971            let snippet_text: Arc<str> = snippet.text.clone().into();
 9972            let edits = insertion_ranges
 9973                .iter()
 9974                .cloned()
 9975                .map(|range| (range, snippet_text.clone()));
 9976            let autoindent_mode = AutoindentMode::Block {
 9977                original_indent_columns: Vec::new(),
 9978            };
 9979            buffer.edit(edits, Some(autoindent_mode), cx);
 9980
 9981            let snapshot = &*buffer.read(cx);
 9982            let snippet = &snippet;
 9983            snippet
 9984                .tabstops
 9985                .iter()
 9986                .map(|tabstop| {
 9987                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9988                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9989                    });
 9990                    let mut tabstop_ranges = tabstop
 9991                        .ranges
 9992                        .iter()
 9993                        .flat_map(|tabstop_range| {
 9994                            let mut delta = 0_isize;
 9995                            insertion_ranges.iter().map(move |insertion_range| {
 9996                                let insertion_start = insertion_range.start + delta;
 9997                                delta += snippet.text.len() as isize
 9998                                    - (insertion_range.end - insertion_range.start) as isize;
 9999
10000                                let start =
10001                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10002                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10003                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10004                            })
10005                        })
10006                        .collect::<Vec<_>>();
10007                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10008
10009                    Tabstop {
10010                        is_end_tabstop,
10011                        ranges: tabstop_ranges,
10012                        choices: tabstop.choices.clone(),
10013                    }
10014                })
10015                .collect::<Vec<_>>()
10016        });
10017        if let Some(tabstop) = tabstops.first() {
10018            self.change_selections(Default::default(), window, cx, |s| {
10019                // Reverse order so that the first range is the newest created selection.
10020                // Completions will use it and autoscroll will prioritize it.
10021                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10022            });
10023
10024            if let Some(choices) = &tabstop.choices
10025                && let Some(selection) = tabstop.ranges.first()
10026            {
10027                self.show_snippet_choices(choices, selection.clone(), cx)
10028            }
10029
10030            // If we're already at the last tabstop and it's at the end of the snippet,
10031            // we're done, we don't need to keep the state around.
10032            if !tabstop.is_end_tabstop {
10033                let choices = tabstops
10034                    .iter()
10035                    .map(|tabstop| tabstop.choices.clone())
10036                    .collect();
10037
10038                let ranges = tabstops
10039                    .into_iter()
10040                    .map(|tabstop| tabstop.ranges)
10041                    .collect::<Vec<_>>();
10042
10043                self.snippet_stack.push(SnippetState {
10044                    active_index: 0,
10045                    ranges,
10046                    choices,
10047                });
10048            }
10049
10050            // Check whether the just-entered snippet ends with an auto-closable bracket.
10051            if self.autoclose_regions.is_empty() {
10052                let snapshot = self.buffer.read(cx).snapshot(cx);
10053                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10054                    let selection_head = selection.head();
10055                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10056                        continue;
10057                    };
10058
10059                    let mut bracket_pair = None;
10060                    let max_lookup_length = scope
10061                        .brackets()
10062                        .map(|(pair, _)| {
10063                            pair.start
10064                                .as_str()
10065                                .chars()
10066                                .count()
10067                                .max(pair.end.as_str().chars().count())
10068                        })
10069                        .max();
10070                    if let Some(max_lookup_length) = max_lookup_length {
10071                        let next_text = snapshot
10072                            .chars_at(selection_head)
10073                            .take(max_lookup_length)
10074                            .collect::<String>();
10075                        let prev_text = snapshot
10076                            .reversed_chars_at(selection_head)
10077                            .take(max_lookup_length)
10078                            .collect::<String>();
10079
10080                        for (pair, enabled) in scope.brackets() {
10081                            if enabled
10082                                && pair.close
10083                                && prev_text.starts_with(pair.start.as_str())
10084                                && next_text.starts_with(pair.end.as_str())
10085                            {
10086                                bracket_pair = Some(pair.clone());
10087                                break;
10088                            }
10089                        }
10090                    }
10091
10092                    if let Some(pair) = bracket_pair {
10093                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10094                        let autoclose_enabled =
10095                            self.use_autoclose && snapshot_settings.use_autoclose;
10096                        if autoclose_enabled {
10097                            let start = snapshot.anchor_after(selection_head);
10098                            let end = snapshot.anchor_after(selection_head);
10099                            self.autoclose_regions.push(AutocloseRegion {
10100                                selection_id: selection.id,
10101                                range: start..end,
10102                                pair,
10103                            });
10104                        }
10105                    }
10106                }
10107            }
10108        }
10109        Ok(())
10110    }
10111
10112    pub fn move_to_next_snippet_tabstop(
10113        &mut self,
10114        window: &mut Window,
10115        cx: &mut Context<Self>,
10116    ) -> bool {
10117        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10118    }
10119
10120    pub fn move_to_prev_snippet_tabstop(
10121        &mut self,
10122        window: &mut Window,
10123        cx: &mut Context<Self>,
10124    ) -> bool {
10125        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10126    }
10127
10128    pub fn move_to_snippet_tabstop(
10129        &mut self,
10130        bias: Bias,
10131        window: &mut Window,
10132        cx: &mut Context<Self>,
10133    ) -> bool {
10134        if let Some(mut snippet) = self.snippet_stack.pop() {
10135            match bias {
10136                Bias::Left => {
10137                    if snippet.active_index > 0 {
10138                        snippet.active_index -= 1;
10139                    } else {
10140                        self.snippet_stack.push(snippet);
10141                        return false;
10142                    }
10143                }
10144                Bias::Right => {
10145                    if snippet.active_index + 1 < snippet.ranges.len() {
10146                        snippet.active_index += 1;
10147                    } else {
10148                        self.snippet_stack.push(snippet);
10149                        return false;
10150                    }
10151                }
10152            }
10153            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10154                self.change_selections(Default::default(), window, cx, |s| {
10155                    // Reverse order so that the first range is the newest created selection.
10156                    // Completions will use it and autoscroll will prioritize it.
10157                    s.select_ranges(current_ranges.iter().rev().cloned())
10158                });
10159
10160                if let Some(choices) = &snippet.choices[snippet.active_index]
10161                    && let Some(selection) = current_ranges.first()
10162                {
10163                    self.show_snippet_choices(choices, selection.clone(), cx);
10164                }
10165
10166                // If snippet state is not at the last tabstop, push it back on the stack
10167                if snippet.active_index + 1 < snippet.ranges.len() {
10168                    self.snippet_stack.push(snippet);
10169                }
10170                return true;
10171            }
10172        }
10173
10174        false
10175    }
10176
10177    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10178        self.transact(window, cx, |this, window, cx| {
10179            this.select_all(&SelectAll, window, cx);
10180            this.insert("", window, cx);
10181        });
10182    }
10183
10184    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10185        if self.read_only(cx) {
10186            return;
10187        }
10188        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10189        self.transact(window, cx, |this, window, cx| {
10190            this.select_autoclose_pair(window, cx);
10191
10192            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10193
10194            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10195            if !this.linked_edit_ranges.is_empty() {
10196                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10197                let snapshot = this.buffer.read(cx).snapshot(cx);
10198
10199                for selection in selections.iter() {
10200                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10201                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10202                    if selection_start.buffer_id != selection_end.buffer_id {
10203                        continue;
10204                    }
10205                    if let Some(ranges) =
10206                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10207                    {
10208                        for (buffer, entries) in ranges {
10209                            linked_ranges.entry(buffer).or_default().extend(entries);
10210                        }
10211                    }
10212                }
10213            }
10214
10215            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10216            for selection in &mut selections {
10217                if selection.is_empty() {
10218                    let old_head = selection.head();
10219                    let mut new_head =
10220                        movement::left(&display_map, old_head.to_display_point(&display_map))
10221                            .to_point(&display_map);
10222                    if let Some((buffer, line_buffer_range)) = display_map
10223                        .buffer_snapshot()
10224                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10225                    {
10226                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10227                        let indent_len = match indent_size.kind {
10228                            IndentKind::Space => {
10229                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10230                            }
10231                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10232                        };
10233                        if old_head.column <= indent_size.len && old_head.column > 0 {
10234                            let indent_len = indent_len.get();
10235                            new_head = cmp::min(
10236                                new_head,
10237                                MultiBufferPoint::new(
10238                                    old_head.row,
10239                                    ((old_head.column - 1) / indent_len) * indent_len,
10240                                ),
10241                            );
10242                        }
10243                    }
10244
10245                    selection.set_head(new_head, SelectionGoal::None);
10246                }
10247            }
10248
10249            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10250            this.insert("", window, cx);
10251            let empty_str: Arc<str> = Arc::from("");
10252            for (buffer, edits) in linked_ranges {
10253                let snapshot = buffer.read(cx).snapshot();
10254                use text::ToPoint as TP;
10255
10256                let edits = edits
10257                    .into_iter()
10258                    .map(|range| {
10259                        let end_point = TP::to_point(&range.end, &snapshot);
10260                        let mut start_point = TP::to_point(&range.start, &snapshot);
10261
10262                        if end_point == start_point {
10263                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10264                                .saturating_sub(1);
10265                            start_point =
10266                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10267                        };
10268
10269                        (start_point..end_point, empty_str.clone())
10270                    })
10271                    .sorted_by_key(|(range, _)| range.start)
10272                    .collect::<Vec<_>>();
10273                buffer.update(cx, |this, cx| {
10274                    this.edit(edits, None, cx);
10275                })
10276            }
10277            this.refresh_edit_prediction(true, false, window, cx);
10278            refresh_linked_ranges(this, window, cx);
10279        });
10280    }
10281
10282    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10283        if self.read_only(cx) {
10284            return;
10285        }
10286        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10287        self.transact(window, cx, |this, window, cx| {
10288            this.change_selections(Default::default(), window, cx, |s| {
10289                s.move_with(|map, selection| {
10290                    if selection.is_empty() {
10291                        let cursor = movement::right(map, selection.head());
10292                        selection.end = cursor;
10293                        selection.reversed = true;
10294                        selection.goal = SelectionGoal::None;
10295                    }
10296                })
10297            });
10298            this.insert("", window, cx);
10299            this.refresh_edit_prediction(true, false, window, cx);
10300        });
10301    }
10302
10303    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10304        if self.mode.is_single_line() {
10305            cx.propagate();
10306            return;
10307        }
10308
10309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10310        if self.move_to_prev_snippet_tabstop(window, cx) {
10311            return;
10312        }
10313        self.outdent(&Outdent, window, cx);
10314    }
10315
10316    pub fn next_snippet_tabstop(
10317        &mut self,
10318        _: &NextSnippetTabstop,
10319        window: &mut Window,
10320        cx: &mut Context<Self>,
10321    ) {
10322        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10323            cx.propagate();
10324            return;
10325        }
10326
10327        if self.move_to_next_snippet_tabstop(window, cx) {
10328            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10329            return;
10330        }
10331        cx.propagate();
10332    }
10333
10334    pub fn previous_snippet_tabstop(
10335        &mut self,
10336        _: &PreviousSnippetTabstop,
10337        window: &mut Window,
10338        cx: &mut Context<Self>,
10339    ) {
10340        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10341            cx.propagate();
10342            return;
10343        }
10344
10345        if self.move_to_prev_snippet_tabstop(window, cx) {
10346            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10347            return;
10348        }
10349        cx.propagate();
10350    }
10351
10352    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10353        if self.mode.is_single_line() {
10354            cx.propagate();
10355            return;
10356        }
10357
10358        if self.move_to_next_snippet_tabstop(window, cx) {
10359            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10360            return;
10361        }
10362        if self.read_only(cx) {
10363            return;
10364        }
10365        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10366        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10367        let buffer = self.buffer.read(cx);
10368        let snapshot = buffer.snapshot(cx);
10369        let rows_iter = selections.iter().map(|s| s.head().row);
10370        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10371
10372        let has_some_cursor_in_whitespace = selections
10373            .iter()
10374            .filter(|selection| selection.is_empty())
10375            .any(|selection| {
10376                let cursor = selection.head();
10377                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10378                cursor.column < current_indent.len
10379            });
10380
10381        let mut edits = Vec::new();
10382        let mut prev_edited_row = 0;
10383        let mut row_delta = 0;
10384        for selection in &mut selections {
10385            if selection.start.row != prev_edited_row {
10386                row_delta = 0;
10387            }
10388            prev_edited_row = selection.end.row;
10389
10390            // If the selection is non-empty, then increase the indentation of the selected lines.
10391            if !selection.is_empty() {
10392                row_delta =
10393                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10394                continue;
10395            }
10396
10397            let cursor = selection.head();
10398            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10399            if let Some(suggested_indent) =
10400                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10401            {
10402                // Don't do anything if already at suggested indent
10403                // and there is any other cursor which is not
10404                if has_some_cursor_in_whitespace
10405                    && cursor.column == current_indent.len
10406                    && current_indent.len == suggested_indent.len
10407                {
10408                    continue;
10409                }
10410
10411                // Adjust line and move cursor to suggested indent
10412                // if cursor is not at suggested indent
10413                if cursor.column < suggested_indent.len
10414                    && cursor.column <= current_indent.len
10415                    && current_indent.len <= suggested_indent.len
10416                {
10417                    selection.start = Point::new(cursor.row, suggested_indent.len);
10418                    selection.end = selection.start;
10419                    if row_delta == 0 {
10420                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10421                            cursor.row,
10422                            current_indent,
10423                            suggested_indent,
10424                        ));
10425                        row_delta = suggested_indent.len - current_indent.len;
10426                    }
10427                    continue;
10428                }
10429
10430                // If current indent is more than suggested indent
10431                // only move cursor to current indent and skip indent
10432                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10433                    selection.start = Point::new(cursor.row, current_indent.len);
10434                    selection.end = selection.start;
10435                    continue;
10436                }
10437            }
10438
10439            // Otherwise, insert a hard or soft tab.
10440            let settings = buffer.language_settings_at(cursor, cx);
10441            let tab_size = if settings.hard_tabs {
10442                IndentSize::tab()
10443            } else {
10444                let tab_size = settings.tab_size.get();
10445                let indent_remainder = snapshot
10446                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10447                    .flat_map(str::chars)
10448                    .fold(row_delta % tab_size, |counter: u32, c| {
10449                        if c == '\t' {
10450                            0
10451                        } else {
10452                            (counter + 1) % tab_size
10453                        }
10454                    });
10455
10456                let chars_to_next_tab_stop = tab_size - indent_remainder;
10457                IndentSize::spaces(chars_to_next_tab_stop)
10458            };
10459            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10460            selection.end = selection.start;
10461            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10462            row_delta += tab_size.len;
10463        }
10464
10465        self.transact(window, cx, |this, window, cx| {
10466            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10467            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10468            this.refresh_edit_prediction(true, false, window, cx);
10469        });
10470    }
10471
10472    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10473        if self.read_only(cx) {
10474            return;
10475        }
10476        if self.mode.is_single_line() {
10477            cx.propagate();
10478            return;
10479        }
10480
10481        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10482        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10483        let mut prev_edited_row = 0;
10484        let mut row_delta = 0;
10485        let mut edits = Vec::new();
10486        let buffer = self.buffer.read(cx);
10487        let snapshot = buffer.snapshot(cx);
10488        for selection in &mut selections {
10489            if selection.start.row != prev_edited_row {
10490                row_delta = 0;
10491            }
10492            prev_edited_row = selection.end.row;
10493
10494            row_delta =
10495                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10496        }
10497
10498        self.transact(window, cx, |this, window, cx| {
10499            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10500            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10501        });
10502    }
10503
10504    fn indent_selection(
10505        buffer: &MultiBuffer,
10506        snapshot: &MultiBufferSnapshot,
10507        selection: &mut Selection<Point>,
10508        edits: &mut Vec<(Range<Point>, String)>,
10509        delta_for_start_row: u32,
10510        cx: &App,
10511    ) -> u32 {
10512        let settings = buffer.language_settings_at(selection.start, cx);
10513        let tab_size = settings.tab_size.get();
10514        let indent_kind = if settings.hard_tabs {
10515            IndentKind::Tab
10516        } else {
10517            IndentKind::Space
10518        };
10519        let mut start_row = selection.start.row;
10520        let mut end_row = selection.end.row + 1;
10521
10522        // If a selection ends at the beginning of a line, don't indent
10523        // that last line.
10524        if selection.end.column == 0 && selection.end.row > selection.start.row {
10525            end_row -= 1;
10526        }
10527
10528        // Avoid re-indenting a row that has already been indented by a
10529        // previous selection, but still update this selection's column
10530        // to reflect that indentation.
10531        if delta_for_start_row > 0 {
10532            start_row += 1;
10533            selection.start.column += delta_for_start_row;
10534            if selection.end.row == selection.start.row {
10535                selection.end.column += delta_for_start_row;
10536            }
10537        }
10538
10539        let mut delta_for_end_row = 0;
10540        let has_multiple_rows = start_row + 1 != end_row;
10541        for row in start_row..end_row {
10542            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10543            let indent_delta = match (current_indent.kind, indent_kind) {
10544                (IndentKind::Space, IndentKind::Space) => {
10545                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10546                    IndentSize::spaces(columns_to_next_tab_stop)
10547                }
10548                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10549                (_, IndentKind::Tab) => IndentSize::tab(),
10550            };
10551
10552            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10553                0
10554            } else {
10555                selection.start.column
10556            };
10557            let row_start = Point::new(row, start);
10558            edits.push((
10559                row_start..row_start,
10560                indent_delta.chars().collect::<String>(),
10561            ));
10562
10563            // Update this selection's endpoints to reflect the indentation.
10564            if row == selection.start.row {
10565                selection.start.column += indent_delta.len;
10566            }
10567            if row == selection.end.row {
10568                selection.end.column += indent_delta.len;
10569                delta_for_end_row = indent_delta.len;
10570            }
10571        }
10572
10573        if selection.start.row == selection.end.row {
10574            delta_for_start_row + delta_for_end_row
10575        } else {
10576            delta_for_end_row
10577        }
10578    }
10579
10580    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10581        if self.read_only(cx) {
10582            return;
10583        }
10584        if self.mode.is_single_line() {
10585            cx.propagate();
10586            return;
10587        }
10588
10589        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10590        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10591        let selections = self.selections.all::<Point>(&display_map);
10592        let mut deletion_ranges = Vec::new();
10593        let mut last_outdent = None;
10594        {
10595            let buffer = self.buffer.read(cx);
10596            let snapshot = buffer.snapshot(cx);
10597            for selection in &selections {
10598                let settings = buffer.language_settings_at(selection.start, cx);
10599                let tab_size = settings.tab_size.get();
10600                let mut rows = selection.spanned_rows(false, &display_map);
10601
10602                // Avoid re-outdenting a row that has already been outdented by a
10603                // previous selection.
10604                if let Some(last_row) = last_outdent
10605                    && last_row == rows.start
10606                {
10607                    rows.start = rows.start.next_row();
10608                }
10609                let has_multiple_rows = rows.len() > 1;
10610                for row in rows.iter_rows() {
10611                    let indent_size = snapshot.indent_size_for_line(row);
10612                    if indent_size.len > 0 {
10613                        let deletion_len = match indent_size.kind {
10614                            IndentKind::Space => {
10615                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10616                                if columns_to_prev_tab_stop == 0 {
10617                                    tab_size
10618                                } else {
10619                                    columns_to_prev_tab_stop
10620                                }
10621                            }
10622                            IndentKind::Tab => 1,
10623                        };
10624                        let start = if has_multiple_rows
10625                            || deletion_len > selection.start.column
10626                            || indent_size.len < selection.start.column
10627                        {
10628                            0
10629                        } else {
10630                            selection.start.column - deletion_len
10631                        };
10632                        deletion_ranges.push(
10633                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10634                        );
10635                        last_outdent = Some(row);
10636                    }
10637                }
10638            }
10639        }
10640
10641        self.transact(window, cx, |this, window, cx| {
10642            this.buffer.update(cx, |buffer, cx| {
10643                let empty_str: Arc<str> = Arc::default();
10644                buffer.edit(
10645                    deletion_ranges
10646                        .into_iter()
10647                        .map(|range| (range, empty_str.clone())),
10648                    None,
10649                    cx,
10650                );
10651            });
10652            let selections = this
10653                .selections
10654                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10655            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10656        });
10657    }
10658
10659    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10660        if self.read_only(cx) {
10661            return;
10662        }
10663        if self.mode.is_single_line() {
10664            cx.propagate();
10665            return;
10666        }
10667
10668        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10669        let selections = self
10670            .selections
10671            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10672            .into_iter()
10673            .map(|s| s.range());
10674
10675        self.transact(window, cx, |this, window, cx| {
10676            this.buffer.update(cx, |buffer, cx| {
10677                buffer.autoindent_ranges(selections, cx);
10678            });
10679            let selections = this
10680                .selections
10681                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10682            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10683        });
10684    }
10685
10686    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10687        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10688        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10689        let selections = self.selections.all::<Point>(&display_map);
10690
10691        let mut new_cursors = Vec::new();
10692        let mut edit_ranges = Vec::new();
10693        let mut selections = selections.iter().peekable();
10694        while let Some(selection) = selections.next() {
10695            let mut rows = selection.spanned_rows(false, &display_map);
10696
10697            // Accumulate contiguous regions of rows that we want to delete.
10698            while let Some(next_selection) = selections.peek() {
10699                let next_rows = next_selection.spanned_rows(false, &display_map);
10700                if next_rows.start <= rows.end {
10701                    rows.end = next_rows.end;
10702                    selections.next().unwrap();
10703                } else {
10704                    break;
10705                }
10706            }
10707
10708            let buffer = display_map.buffer_snapshot();
10709            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10710            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10711                // If there's a line after the range, delete the \n from the end of the row range
10712                (
10713                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10714                    rows.end,
10715                )
10716            } else {
10717                // If there isn't a line after the range, delete the \n from the line before the
10718                // start of the row range
10719                edit_start = edit_start.saturating_sub_usize(1);
10720                (buffer.len(), rows.start.previous_row())
10721            };
10722
10723            let text_layout_details = self.text_layout_details(window);
10724            let x = display_map.x_for_display_point(
10725                selection.head().to_display_point(&display_map),
10726                &text_layout_details,
10727            );
10728            let row = Point::new(target_row.0, 0)
10729                .to_display_point(&display_map)
10730                .row();
10731            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10732
10733            new_cursors.push((
10734                selection.id,
10735                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10736                SelectionGoal::None,
10737            ));
10738            edit_ranges.push(edit_start..edit_end);
10739        }
10740
10741        self.transact(window, cx, |this, window, cx| {
10742            let buffer = this.buffer.update(cx, |buffer, cx| {
10743                let empty_str: Arc<str> = Arc::default();
10744                buffer.edit(
10745                    edit_ranges
10746                        .into_iter()
10747                        .map(|range| (range, empty_str.clone())),
10748                    None,
10749                    cx,
10750                );
10751                buffer.snapshot(cx)
10752            });
10753            let new_selections = new_cursors
10754                .into_iter()
10755                .map(|(id, cursor, goal)| {
10756                    let cursor = cursor.to_point(&buffer);
10757                    Selection {
10758                        id,
10759                        start: cursor,
10760                        end: cursor,
10761                        reversed: false,
10762                        goal,
10763                    }
10764                })
10765                .collect();
10766
10767            this.change_selections(Default::default(), window, cx, |s| {
10768                s.select(new_selections);
10769            });
10770        });
10771    }
10772
10773    pub fn join_lines_impl(
10774        &mut self,
10775        insert_whitespace: bool,
10776        window: &mut Window,
10777        cx: &mut Context<Self>,
10778    ) {
10779        if self.read_only(cx) {
10780            return;
10781        }
10782        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10783        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10784            let start = MultiBufferRow(selection.start.row);
10785            // Treat single line selections as if they include the next line. Otherwise this action
10786            // would do nothing for single line selections individual cursors.
10787            let end = if selection.start.row == selection.end.row {
10788                MultiBufferRow(selection.start.row + 1)
10789            } else {
10790                MultiBufferRow(selection.end.row)
10791            };
10792
10793            if let Some(last_row_range) = row_ranges.last_mut()
10794                && start <= last_row_range.end
10795            {
10796                last_row_range.end = end;
10797                continue;
10798            }
10799            row_ranges.push(start..end);
10800        }
10801
10802        let snapshot = self.buffer.read(cx).snapshot(cx);
10803        let mut cursor_positions = Vec::new();
10804        for row_range in &row_ranges {
10805            let anchor = snapshot.anchor_before(Point::new(
10806                row_range.end.previous_row().0,
10807                snapshot.line_len(row_range.end.previous_row()),
10808            ));
10809            cursor_positions.push(anchor..anchor);
10810        }
10811
10812        self.transact(window, cx, |this, window, cx| {
10813            for row_range in row_ranges.into_iter().rev() {
10814                for row in row_range.iter_rows().rev() {
10815                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10816                    let next_line_row = row.next_row();
10817                    let indent = snapshot.indent_size_for_line(next_line_row);
10818                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10819
10820                    let replace =
10821                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10822                            " "
10823                        } else {
10824                            ""
10825                        };
10826
10827                    this.buffer.update(cx, |buffer, cx| {
10828                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10829                    });
10830                }
10831            }
10832
10833            this.change_selections(Default::default(), window, cx, |s| {
10834                s.select_anchor_ranges(cursor_positions)
10835            });
10836        });
10837    }
10838
10839    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10840        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10841        self.join_lines_impl(true, window, cx);
10842    }
10843
10844    pub fn sort_lines_case_sensitive(
10845        &mut self,
10846        _: &SortLinesCaseSensitive,
10847        window: &mut Window,
10848        cx: &mut Context<Self>,
10849    ) {
10850        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10851    }
10852
10853    pub fn sort_lines_by_length(
10854        &mut self,
10855        _: &SortLinesByLength,
10856        window: &mut Window,
10857        cx: &mut Context<Self>,
10858    ) {
10859        self.manipulate_immutable_lines(window, cx, |lines| {
10860            lines.sort_by_key(|&line| line.chars().count())
10861        })
10862    }
10863
10864    pub fn sort_lines_case_insensitive(
10865        &mut self,
10866        _: &SortLinesCaseInsensitive,
10867        window: &mut Window,
10868        cx: &mut Context<Self>,
10869    ) {
10870        self.manipulate_immutable_lines(window, cx, |lines| {
10871            lines.sort_by_key(|line| line.to_lowercase())
10872        })
10873    }
10874
10875    pub fn unique_lines_case_insensitive(
10876        &mut self,
10877        _: &UniqueLinesCaseInsensitive,
10878        window: &mut Window,
10879        cx: &mut Context<Self>,
10880    ) {
10881        self.manipulate_immutable_lines(window, cx, |lines| {
10882            let mut seen = HashSet::default();
10883            lines.retain(|line| seen.insert(line.to_lowercase()));
10884        })
10885    }
10886
10887    pub fn unique_lines_case_sensitive(
10888        &mut self,
10889        _: &UniqueLinesCaseSensitive,
10890        window: &mut Window,
10891        cx: &mut Context<Self>,
10892    ) {
10893        self.manipulate_immutable_lines(window, cx, |lines| {
10894            let mut seen = HashSet::default();
10895            lines.retain(|line| seen.insert(*line));
10896        })
10897    }
10898
10899    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10900        let snapshot = self.buffer.read(cx).snapshot(cx);
10901        for selection in self.selections.disjoint_anchors_arc().iter() {
10902            if snapshot
10903                .language_at(selection.start)
10904                .and_then(|lang| lang.config().wrap_characters.as_ref())
10905                .is_some()
10906            {
10907                return true;
10908            }
10909        }
10910        false
10911    }
10912
10913    fn wrap_selections_in_tag(
10914        &mut self,
10915        _: &WrapSelectionsInTag,
10916        window: &mut Window,
10917        cx: &mut Context<Self>,
10918    ) {
10919        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10920
10921        let snapshot = self.buffer.read(cx).snapshot(cx);
10922
10923        let mut edits = Vec::new();
10924        let mut boundaries = Vec::new();
10925
10926        for selection in self
10927            .selections
10928            .all_adjusted(&self.display_snapshot(cx))
10929            .iter()
10930        {
10931            let Some(wrap_config) = snapshot
10932                .language_at(selection.start)
10933                .and_then(|lang| lang.config().wrap_characters.clone())
10934            else {
10935                continue;
10936            };
10937
10938            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10939            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10940
10941            let start_before = snapshot.anchor_before(selection.start);
10942            let end_after = snapshot.anchor_after(selection.end);
10943
10944            edits.push((start_before..start_before, open_tag));
10945            edits.push((end_after..end_after, close_tag));
10946
10947            boundaries.push((
10948                start_before,
10949                end_after,
10950                wrap_config.start_prefix.len(),
10951                wrap_config.end_suffix.len(),
10952            ));
10953        }
10954
10955        if edits.is_empty() {
10956            return;
10957        }
10958
10959        self.transact(window, cx, |this, window, cx| {
10960            let buffer = this.buffer.update(cx, |buffer, cx| {
10961                buffer.edit(edits, None, cx);
10962                buffer.snapshot(cx)
10963            });
10964
10965            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10966            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10967                boundaries.into_iter()
10968            {
10969                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10970                let close_offset = end_after
10971                    .to_offset(&buffer)
10972                    .saturating_sub_usize(end_suffix_len);
10973                new_selections.push(open_offset..open_offset);
10974                new_selections.push(close_offset..close_offset);
10975            }
10976
10977            this.change_selections(Default::default(), window, cx, |s| {
10978                s.select_ranges(new_selections);
10979            });
10980
10981            this.request_autoscroll(Autoscroll::fit(), cx);
10982        });
10983    }
10984
10985    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10986        let Some(project) = self.project.clone() else {
10987            return;
10988        };
10989        self.reload(project, window, cx)
10990            .detach_and_notify_err(window, cx);
10991    }
10992
10993    pub fn restore_file(
10994        &mut self,
10995        _: &::git::RestoreFile,
10996        window: &mut Window,
10997        cx: &mut Context<Self>,
10998    ) {
10999        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11000        let mut buffer_ids = HashSet::default();
11001        let snapshot = self.buffer().read(cx).snapshot(cx);
11002        for selection in self
11003            .selections
11004            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11005        {
11006            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11007        }
11008
11009        let buffer = self.buffer().read(cx);
11010        let ranges = buffer_ids
11011            .into_iter()
11012            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11013            .collect::<Vec<_>>();
11014
11015        self.restore_hunks_in_ranges(ranges, window, cx);
11016    }
11017
11018    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11019        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11020        let selections = self
11021            .selections
11022            .all(&self.display_snapshot(cx))
11023            .into_iter()
11024            .map(|s| s.range())
11025            .collect();
11026        self.restore_hunks_in_ranges(selections, window, cx);
11027    }
11028
11029    pub fn restore_hunks_in_ranges(
11030        &mut self,
11031        ranges: Vec<Range<Point>>,
11032        window: &mut Window,
11033        cx: &mut Context<Editor>,
11034    ) {
11035        let mut revert_changes = HashMap::default();
11036        let chunk_by = self
11037            .snapshot(window, cx)
11038            .hunks_for_ranges(ranges)
11039            .into_iter()
11040            .chunk_by(|hunk| hunk.buffer_id);
11041        for (buffer_id, hunks) in &chunk_by {
11042            let hunks = hunks.collect::<Vec<_>>();
11043            for hunk in &hunks {
11044                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11045            }
11046            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11047        }
11048        drop(chunk_by);
11049        if !revert_changes.is_empty() {
11050            self.transact(window, cx, |editor, window, cx| {
11051                editor.restore(revert_changes, window, cx);
11052            });
11053        }
11054    }
11055
11056    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11057        if let Some(status) = self
11058            .addons
11059            .iter()
11060            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11061        {
11062            return Some(status);
11063        }
11064        self.project
11065            .as_ref()?
11066            .read(cx)
11067            .status_for_buffer_id(buffer_id, cx)
11068    }
11069
11070    pub fn open_active_item_in_terminal(
11071        &mut self,
11072        _: &OpenInTerminal,
11073        window: &mut Window,
11074        cx: &mut Context<Self>,
11075    ) {
11076        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11077            let project_path = buffer.read(cx).project_path(cx)?;
11078            let project = self.project()?.read(cx);
11079            let entry = project.entry_for_path(&project_path, cx)?;
11080            let parent = match &entry.canonical_path {
11081                Some(canonical_path) => canonical_path.to_path_buf(),
11082                None => project.absolute_path(&project_path, cx)?,
11083            }
11084            .parent()?
11085            .to_path_buf();
11086            Some(parent)
11087        }) {
11088            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11089        }
11090    }
11091
11092    fn set_breakpoint_context_menu(
11093        &mut self,
11094        display_row: DisplayRow,
11095        position: Option<Anchor>,
11096        clicked_point: gpui::Point<Pixels>,
11097        window: &mut Window,
11098        cx: &mut Context<Self>,
11099    ) {
11100        let source = self
11101            .buffer
11102            .read(cx)
11103            .snapshot(cx)
11104            .anchor_before(Point::new(display_row.0, 0u32));
11105
11106        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11107
11108        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11109            self,
11110            source,
11111            clicked_point,
11112            context_menu,
11113            window,
11114            cx,
11115        );
11116    }
11117
11118    fn add_edit_breakpoint_block(
11119        &mut self,
11120        anchor: Anchor,
11121        breakpoint: &Breakpoint,
11122        edit_action: BreakpointPromptEditAction,
11123        window: &mut Window,
11124        cx: &mut Context<Self>,
11125    ) {
11126        let weak_editor = cx.weak_entity();
11127        let bp_prompt = cx.new(|cx| {
11128            BreakpointPromptEditor::new(
11129                weak_editor,
11130                anchor,
11131                breakpoint.clone(),
11132                edit_action,
11133                window,
11134                cx,
11135            )
11136        });
11137
11138        let height = bp_prompt.update(cx, |this, cx| {
11139            this.prompt
11140                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11141        });
11142        let cloned_prompt = bp_prompt.clone();
11143        let blocks = vec![BlockProperties {
11144            style: BlockStyle::Sticky,
11145            placement: BlockPlacement::Above(anchor),
11146            height: Some(height),
11147            render: Arc::new(move |cx| {
11148                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11149                cloned_prompt.clone().into_any_element()
11150            }),
11151            priority: 0,
11152        }];
11153
11154        let focus_handle = bp_prompt.focus_handle(cx);
11155        window.focus(&focus_handle, cx);
11156
11157        let block_ids = self.insert_blocks(blocks, None, cx);
11158        bp_prompt.update(cx, |prompt, _| {
11159            prompt.add_block_ids(block_ids);
11160        });
11161    }
11162
11163    pub(crate) fn breakpoint_at_row(
11164        &self,
11165        row: u32,
11166        window: &mut Window,
11167        cx: &mut Context<Self>,
11168    ) -> Option<(Anchor, Breakpoint)> {
11169        let snapshot = self.snapshot(window, cx);
11170        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11171
11172        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11173    }
11174
11175    pub(crate) fn breakpoint_at_anchor(
11176        &self,
11177        breakpoint_position: Anchor,
11178        snapshot: &EditorSnapshot,
11179        cx: &mut Context<Self>,
11180    ) -> Option<(Anchor, Breakpoint)> {
11181        let buffer = self
11182            .buffer
11183            .read(cx)
11184            .buffer_for_anchor(breakpoint_position, cx)?;
11185
11186        let enclosing_excerpt = breakpoint_position.excerpt_id;
11187        let buffer_snapshot = buffer.read(cx).snapshot();
11188
11189        let row = buffer_snapshot
11190            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11191            .row;
11192
11193        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11194        let anchor_end = snapshot
11195            .buffer_snapshot()
11196            .anchor_after(Point::new(row, line_len));
11197
11198        self.breakpoint_store
11199            .as_ref()?
11200            .read_with(cx, |breakpoint_store, cx| {
11201                breakpoint_store
11202                    .breakpoints(
11203                        &buffer,
11204                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11205                        &buffer_snapshot,
11206                        cx,
11207                    )
11208                    .next()
11209                    .and_then(|(bp, _)| {
11210                        let breakpoint_row = buffer_snapshot
11211                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11212                            .row;
11213
11214                        if breakpoint_row == row {
11215                            snapshot
11216                                .buffer_snapshot()
11217                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11218                                .map(|position| (position, bp.bp.clone()))
11219                        } else {
11220                            None
11221                        }
11222                    })
11223            })
11224    }
11225
11226    pub fn edit_log_breakpoint(
11227        &mut self,
11228        _: &EditLogBreakpoint,
11229        window: &mut Window,
11230        cx: &mut Context<Self>,
11231    ) {
11232        if self.breakpoint_store.is_none() {
11233            return;
11234        }
11235
11236        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11237            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11238                message: None,
11239                state: BreakpointState::Enabled,
11240                condition: None,
11241                hit_condition: None,
11242            });
11243
11244            self.add_edit_breakpoint_block(
11245                anchor,
11246                &breakpoint,
11247                BreakpointPromptEditAction::Log,
11248                window,
11249                cx,
11250            );
11251        }
11252    }
11253
11254    fn breakpoints_at_cursors(
11255        &self,
11256        window: &mut Window,
11257        cx: &mut Context<Self>,
11258    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11259        let snapshot = self.snapshot(window, cx);
11260        let cursors = self
11261            .selections
11262            .disjoint_anchors_arc()
11263            .iter()
11264            .map(|selection| {
11265                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11266
11267                let breakpoint_position = self
11268                    .breakpoint_at_row(cursor_position.row, window, cx)
11269                    .map(|bp| bp.0)
11270                    .unwrap_or_else(|| {
11271                        snapshot
11272                            .display_snapshot
11273                            .buffer_snapshot()
11274                            .anchor_after(Point::new(cursor_position.row, 0))
11275                    });
11276
11277                let breakpoint = self
11278                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11279                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11280
11281                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11282            })
11283            // There might be multiple cursors on the same line; all of them should have the same anchors though as their breakpoints positions, which makes it possible to sort and dedup the list.
11284            .collect::<HashMap<Anchor, _>>();
11285
11286        cursors.into_iter().collect()
11287    }
11288
11289    pub fn enable_breakpoint(
11290        &mut self,
11291        _: &crate::actions::EnableBreakpoint,
11292        window: &mut Window,
11293        cx: &mut Context<Self>,
11294    ) {
11295        if self.breakpoint_store.is_none() {
11296            return;
11297        }
11298
11299        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11300            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11301                continue;
11302            };
11303            self.edit_breakpoint_at_anchor(
11304                anchor,
11305                breakpoint,
11306                BreakpointEditAction::InvertState,
11307                cx,
11308            );
11309        }
11310    }
11311
11312    pub fn disable_breakpoint(
11313        &mut self,
11314        _: &crate::actions::DisableBreakpoint,
11315        window: &mut Window,
11316        cx: &mut Context<Self>,
11317    ) {
11318        if self.breakpoint_store.is_none() {
11319            return;
11320        }
11321
11322        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11323            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11324                continue;
11325            };
11326            self.edit_breakpoint_at_anchor(
11327                anchor,
11328                breakpoint,
11329                BreakpointEditAction::InvertState,
11330                cx,
11331            );
11332        }
11333    }
11334
11335    pub fn toggle_breakpoint(
11336        &mut self,
11337        _: &crate::actions::ToggleBreakpoint,
11338        window: &mut Window,
11339        cx: &mut Context<Self>,
11340    ) {
11341        if self.breakpoint_store.is_none() {
11342            return;
11343        }
11344
11345        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11346            if let Some(breakpoint) = breakpoint {
11347                self.edit_breakpoint_at_anchor(
11348                    anchor,
11349                    breakpoint,
11350                    BreakpointEditAction::Toggle,
11351                    cx,
11352                );
11353            } else {
11354                self.edit_breakpoint_at_anchor(
11355                    anchor,
11356                    Breakpoint::new_standard(),
11357                    BreakpointEditAction::Toggle,
11358                    cx,
11359                );
11360            }
11361        }
11362    }
11363
11364    pub fn edit_breakpoint_at_anchor(
11365        &mut self,
11366        breakpoint_position: Anchor,
11367        breakpoint: Breakpoint,
11368        edit_action: BreakpointEditAction,
11369        cx: &mut Context<Self>,
11370    ) {
11371        let Some(breakpoint_store) = &self.breakpoint_store else {
11372            return;
11373        };
11374
11375        let Some(buffer) = self
11376            .buffer
11377            .read(cx)
11378            .buffer_for_anchor(breakpoint_position, cx)
11379        else {
11380            return;
11381        };
11382
11383        breakpoint_store.update(cx, |breakpoint_store, cx| {
11384            breakpoint_store.toggle_breakpoint(
11385                buffer,
11386                BreakpointWithPosition {
11387                    position: breakpoint_position.text_anchor,
11388                    bp: breakpoint,
11389                },
11390                edit_action,
11391                cx,
11392            );
11393        });
11394
11395        cx.notify();
11396    }
11397
11398    #[cfg(any(test, feature = "test-support"))]
11399    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11400        self.breakpoint_store.clone()
11401    }
11402
11403    pub fn prepare_restore_change(
11404        &self,
11405        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11406        hunk: &MultiBufferDiffHunk,
11407        cx: &mut App,
11408    ) -> Option<()> {
11409        if hunk.is_created_file() {
11410            return None;
11411        }
11412        let buffer = self.buffer.read(cx);
11413        let diff = buffer.diff_for(hunk.buffer_id)?;
11414        let buffer = buffer.buffer(hunk.buffer_id)?;
11415        let buffer = buffer.read(cx);
11416        let original_text = diff
11417            .read(cx)
11418            .base_text()
11419            .as_rope()
11420            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11421        let buffer_snapshot = buffer.snapshot();
11422        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11423        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11424            probe
11425                .0
11426                .start
11427                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11428                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11429        }) {
11430            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11431            Some(())
11432        } else {
11433            None
11434        }
11435    }
11436
11437    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11438        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11439    }
11440
11441    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11442        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11443    }
11444
11445    pub fn rotate_selections_forward(
11446        &mut self,
11447        _: &RotateSelectionsForward,
11448        window: &mut Window,
11449        cx: &mut Context<Self>,
11450    ) {
11451        self.rotate_selections(window, cx, false)
11452    }
11453
11454    pub fn rotate_selections_backward(
11455        &mut self,
11456        _: &RotateSelectionsBackward,
11457        window: &mut Window,
11458        cx: &mut Context<Self>,
11459    ) {
11460        self.rotate_selections(window, cx, true)
11461    }
11462
11463    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11464        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11465        let display_snapshot = self.display_snapshot(cx);
11466        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11467
11468        if selections.len() < 2 {
11469            return;
11470        }
11471
11472        let (edits, new_selections) = {
11473            let buffer = self.buffer.read(cx).read(cx);
11474            let has_selections = selections.iter().any(|s| !s.is_empty());
11475            if has_selections {
11476                let mut selected_texts: Vec<String> = selections
11477                    .iter()
11478                    .map(|selection| {
11479                        buffer
11480                            .text_for_range(selection.start..selection.end)
11481                            .collect()
11482                    })
11483                    .collect();
11484
11485                if reverse {
11486                    selected_texts.rotate_left(1);
11487                } else {
11488                    selected_texts.rotate_right(1);
11489                }
11490
11491                let mut offset_delta: i64 = 0;
11492                let mut new_selections = Vec::new();
11493                let edits: Vec<_> = selections
11494                    .iter()
11495                    .zip(selected_texts.iter())
11496                    .map(|(selection, new_text)| {
11497                        let old_len = (selection.end.0 - selection.start.0) as i64;
11498                        let new_len = new_text.len() as i64;
11499                        let adjusted_start =
11500                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11501                        let adjusted_end =
11502                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11503
11504                        new_selections.push(Selection {
11505                            id: selection.id,
11506                            start: adjusted_start,
11507                            end: adjusted_end,
11508                            reversed: selection.reversed,
11509                            goal: selection.goal,
11510                        });
11511
11512                        offset_delta += new_len - old_len;
11513                        (selection.start..selection.end, new_text.clone())
11514                    })
11515                    .collect();
11516                (edits, new_selections)
11517            } else {
11518                let mut all_rows: Vec<u32> = selections
11519                    .iter()
11520                    .map(|selection| buffer.offset_to_point(selection.start).row)
11521                    .collect();
11522                all_rows.sort_unstable();
11523                all_rows.dedup();
11524
11525                if all_rows.len() < 2 {
11526                    return;
11527                }
11528
11529                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11530                    .iter()
11531                    .map(|&row| {
11532                        let start = Point::new(row, 0);
11533                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11534                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11535                    })
11536                    .collect();
11537
11538                let mut line_texts: Vec<String> = line_ranges
11539                    .iter()
11540                    .map(|range| buffer.text_for_range(range.clone()).collect())
11541                    .collect();
11542
11543                if reverse {
11544                    line_texts.rotate_left(1);
11545                } else {
11546                    line_texts.rotate_right(1);
11547                }
11548
11549                let edits = line_ranges
11550                    .iter()
11551                    .zip(line_texts.iter())
11552                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11553                    .collect();
11554
11555                let num_rows = all_rows.len();
11556                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11557                    .iter()
11558                    .enumerate()
11559                    .map(|(i, &row)| (row, i))
11560                    .collect();
11561
11562                // Compute new line start offsets after rotation (handles CRLF)
11563                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11564                let first_line_start = line_ranges[0].start.0;
11565                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11566                for text in line_texts.iter().take(num_rows - 1) {
11567                    let prev_start = *new_line_starts.last().unwrap();
11568                    new_line_starts.push(prev_start + text.len() + newline_len);
11569                }
11570
11571                let new_selections = selections
11572                    .iter()
11573                    .map(|selection| {
11574                        let point = buffer.offset_to_point(selection.start);
11575                        let old_index = row_to_index[&point.row];
11576                        let new_index = if reverse {
11577                            (old_index + num_rows - 1) % num_rows
11578                        } else {
11579                            (old_index + 1) % num_rows
11580                        };
11581                        let new_offset =
11582                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11583                        Selection {
11584                            id: selection.id,
11585                            start: new_offset,
11586                            end: new_offset,
11587                            reversed: selection.reversed,
11588                            goal: selection.goal,
11589                        }
11590                    })
11591                    .collect();
11592
11593                (edits, new_selections)
11594            }
11595        };
11596
11597        self.transact(window, cx, |this, window, cx| {
11598            this.buffer.update(cx, |buffer, cx| {
11599                buffer.edit(edits, None, cx);
11600            });
11601            this.change_selections(Default::default(), window, cx, |s| {
11602                s.select(new_selections);
11603            });
11604        });
11605    }
11606
11607    fn manipulate_lines<M>(
11608        &mut self,
11609        window: &mut Window,
11610        cx: &mut Context<Self>,
11611        mut manipulate: M,
11612    ) where
11613        M: FnMut(&str) -> LineManipulationResult,
11614    {
11615        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11616
11617        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11618        let buffer = self.buffer.read(cx).snapshot(cx);
11619
11620        let mut edits = Vec::new();
11621
11622        let selections = self.selections.all::<Point>(&display_map);
11623        let mut selections = selections.iter().peekable();
11624        let mut contiguous_row_selections = Vec::new();
11625        let mut new_selections = Vec::new();
11626        let mut added_lines = 0;
11627        let mut removed_lines = 0;
11628
11629        while let Some(selection) = selections.next() {
11630            let (start_row, end_row) = consume_contiguous_rows(
11631                &mut contiguous_row_selections,
11632                selection,
11633                &display_map,
11634                &mut selections,
11635            );
11636
11637            let start_point = Point::new(start_row.0, 0);
11638            let end_point = Point::new(
11639                end_row.previous_row().0,
11640                buffer.line_len(end_row.previous_row()),
11641            );
11642            let text = buffer
11643                .text_for_range(start_point..end_point)
11644                .collect::<String>();
11645
11646            let LineManipulationResult {
11647                new_text,
11648                line_count_before,
11649                line_count_after,
11650            } = manipulate(&text);
11651
11652            edits.push((start_point..end_point, new_text));
11653
11654            // Selections must change based on added and removed line count
11655            let start_row =
11656                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11657            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11658            new_selections.push(Selection {
11659                id: selection.id,
11660                start: start_row,
11661                end: end_row,
11662                goal: SelectionGoal::None,
11663                reversed: selection.reversed,
11664            });
11665
11666            if line_count_after > line_count_before {
11667                added_lines += line_count_after - line_count_before;
11668            } else if line_count_before > line_count_after {
11669                removed_lines += line_count_before - line_count_after;
11670            }
11671        }
11672
11673        self.transact(window, cx, |this, window, cx| {
11674            let buffer = this.buffer.update(cx, |buffer, cx| {
11675                buffer.edit(edits, None, cx);
11676                buffer.snapshot(cx)
11677            });
11678
11679            // Recalculate offsets on newly edited buffer
11680            let new_selections = new_selections
11681                .iter()
11682                .map(|s| {
11683                    let start_point = Point::new(s.start.0, 0);
11684                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11685                    Selection {
11686                        id: s.id,
11687                        start: buffer.point_to_offset(start_point),
11688                        end: buffer.point_to_offset(end_point),
11689                        goal: s.goal,
11690                        reversed: s.reversed,
11691                    }
11692                })
11693                .collect();
11694
11695            this.change_selections(Default::default(), window, cx, |s| {
11696                s.select(new_selections);
11697            });
11698
11699            this.request_autoscroll(Autoscroll::fit(), cx);
11700        });
11701    }
11702
11703    fn manipulate_immutable_lines<Fn>(
11704        &mut self,
11705        window: &mut Window,
11706        cx: &mut Context<Self>,
11707        mut callback: Fn,
11708    ) where
11709        Fn: FnMut(&mut Vec<&str>),
11710    {
11711        self.manipulate_lines(window, cx, |text| {
11712            let mut lines: Vec<&str> = text.split('\n').collect();
11713            let line_count_before = lines.len();
11714
11715            callback(&mut lines);
11716
11717            LineManipulationResult {
11718                new_text: lines.join("\n"),
11719                line_count_before,
11720                line_count_after: lines.len(),
11721            }
11722        });
11723    }
11724
11725    fn manipulate_mutable_lines<Fn>(
11726        &mut self,
11727        window: &mut Window,
11728        cx: &mut Context<Self>,
11729        mut callback: Fn,
11730    ) where
11731        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11732    {
11733        self.manipulate_lines(window, cx, |text| {
11734            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11735            let line_count_before = lines.len();
11736
11737            callback(&mut lines);
11738
11739            LineManipulationResult {
11740                new_text: lines.join("\n"),
11741                line_count_before,
11742                line_count_after: lines.len(),
11743            }
11744        });
11745    }
11746
11747    pub fn convert_indentation_to_spaces(
11748        &mut self,
11749        _: &ConvertIndentationToSpaces,
11750        window: &mut Window,
11751        cx: &mut Context<Self>,
11752    ) {
11753        let settings = self.buffer.read(cx).language_settings(cx);
11754        let tab_size = settings.tab_size.get() as usize;
11755
11756        self.manipulate_mutable_lines(window, cx, |lines| {
11757            // Allocates a reasonably sized scratch buffer once for the whole loop
11758            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11759            // Avoids recomputing spaces that could be inserted many times
11760            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11761                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11762                .collect();
11763
11764            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11765                let mut chars = line.as_ref().chars();
11766                let mut col = 0;
11767                let mut changed = false;
11768
11769                for ch in chars.by_ref() {
11770                    match ch {
11771                        ' ' => {
11772                            reindented_line.push(' ');
11773                            col += 1;
11774                        }
11775                        '\t' => {
11776                            // \t are converted to spaces depending on the current column
11777                            let spaces_len = tab_size - (col % tab_size);
11778                            reindented_line.extend(&space_cache[spaces_len - 1]);
11779                            col += spaces_len;
11780                            changed = true;
11781                        }
11782                        _ => {
11783                            // If we dont append before break, the character is consumed
11784                            reindented_line.push(ch);
11785                            break;
11786                        }
11787                    }
11788                }
11789
11790                if !changed {
11791                    reindented_line.clear();
11792                    continue;
11793                }
11794                // Append the rest of the line and replace old reference with new one
11795                reindented_line.extend(chars);
11796                *line = Cow::Owned(reindented_line.clone());
11797                reindented_line.clear();
11798            }
11799        });
11800    }
11801
11802    pub fn convert_indentation_to_tabs(
11803        &mut self,
11804        _: &ConvertIndentationToTabs,
11805        window: &mut Window,
11806        cx: &mut Context<Self>,
11807    ) {
11808        let settings = self.buffer.read(cx).language_settings(cx);
11809        let tab_size = settings.tab_size.get() as usize;
11810
11811        self.manipulate_mutable_lines(window, cx, |lines| {
11812            // Allocates a reasonably sized buffer once for the whole loop
11813            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11814            // Avoids recomputing spaces that could be inserted many times
11815            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11816                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11817                .collect();
11818
11819            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11820                let mut chars = line.chars();
11821                let mut spaces_count = 0;
11822                let mut first_non_indent_char = None;
11823                let mut changed = false;
11824
11825                for ch in chars.by_ref() {
11826                    match ch {
11827                        ' ' => {
11828                            // Keep track of spaces. Append \t when we reach tab_size
11829                            spaces_count += 1;
11830                            changed = true;
11831                            if spaces_count == tab_size {
11832                                reindented_line.push('\t');
11833                                spaces_count = 0;
11834                            }
11835                        }
11836                        '\t' => {
11837                            reindented_line.push('\t');
11838                            spaces_count = 0;
11839                        }
11840                        _ => {
11841                            // Dont append it yet, we might have remaining spaces
11842                            first_non_indent_char = Some(ch);
11843                            break;
11844                        }
11845                    }
11846                }
11847
11848                if !changed {
11849                    reindented_line.clear();
11850                    continue;
11851                }
11852                // Remaining spaces that didn't make a full tab stop
11853                if spaces_count > 0 {
11854                    reindented_line.extend(&space_cache[spaces_count - 1]);
11855                }
11856                // If we consume an extra character that was not indentation, add it back
11857                if let Some(extra_char) = first_non_indent_char {
11858                    reindented_line.push(extra_char);
11859                }
11860                // Append the rest of the line and replace old reference with new one
11861                reindented_line.extend(chars);
11862                *line = Cow::Owned(reindented_line.clone());
11863                reindented_line.clear();
11864            }
11865        });
11866    }
11867
11868    pub fn convert_to_upper_case(
11869        &mut self,
11870        _: &ConvertToUpperCase,
11871        window: &mut Window,
11872        cx: &mut Context<Self>,
11873    ) {
11874        self.manipulate_text(window, cx, |text| text.to_uppercase())
11875    }
11876
11877    pub fn convert_to_lower_case(
11878        &mut self,
11879        _: &ConvertToLowerCase,
11880        window: &mut Window,
11881        cx: &mut Context<Self>,
11882    ) {
11883        self.manipulate_text(window, cx, |text| text.to_lowercase())
11884    }
11885
11886    pub fn convert_to_title_case(
11887        &mut self,
11888        _: &ConvertToTitleCase,
11889        window: &mut Window,
11890        cx: &mut Context<Self>,
11891    ) {
11892        self.manipulate_text(window, cx, |text| {
11893            text.split('\n')
11894                .map(|line| line.to_case(Case::Title))
11895                .join("\n")
11896        })
11897    }
11898
11899    pub fn convert_to_snake_case(
11900        &mut self,
11901        _: &ConvertToSnakeCase,
11902        window: &mut Window,
11903        cx: &mut Context<Self>,
11904    ) {
11905        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11906    }
11907
11908    pub fn convert_to_kebab_case(
11909        &mut self,
11910        _: &ConvertToKebabCase,
11911        window: &mut Window,
11912        cx: &mut Context<Self>,
11913    ) {
11914        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11915    }
11916
11917    pub fn convert_to_upper_camel_case(
11918        &mut self,
11919        _: &ConvertToUpperCamelCase,
11920        window: &mut Window,
11921        cx: &mut Context<Self>,
11922    ) {
11923        self.manipulate_text(window, cx, |text| {
11924            text.split('\n')
11925                .map(|line| line.to_case(Case::UpperCamel))
11926                .join("\n")
11927        })
11928    }
11929
11930    pub fn convert_to_lower_camel_case(
11931        &mut self,
11932        _: &ConvertToLowerCamelCase,
11933        window: &mut Window,
11934        cx: &mut Context<Self>,
11935    ) {
11936        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11937    }
11938
11939    pub fn convert_to_opposite_case(
11940        &mut self,
11941        _: &ConvertToOppositeCase,
11942        window: &mut Window,
11943        cx: &mut Context<Self>,
11944    ) {
11945        self.manipulate_text(window, cx, |text| {
11946            text.chars()
11947                .fold(String::with_capacity(text.len()), |mut t, c| {
11948                    if c.is_uppercase() {
11949                        t.extend(c.to_lowercase());
11950                    } else {
11951                        t.extend(c.to_uppercase());
11952                    }
11953                    t
11954                })
11955        })
11956    }
11957
11958    pub fn convert_to_sentence_case(
11959        &mut self,
11960        _: &ConvertToSentenceCase,
11961        window: &mut Window,
11962        cx: &mut Context<Self>,
11963    ) {
11964        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11965    }
11966
11967    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11968        self.manipulate_text(window, cx, |text| {
11969            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11970            if has_upper_case_characters {
11971                text.to_lowercase()
11972            } else {
11973                text.to_uppercase()
11974            }
11975        })
11976    }
11977
11978    pub fn convert_to_rot13(
11979        &mut self,
11980        _: &ConvertToRot13,
11981        window: &mut Window,
11982        cx: &mut Context<Self>,
11983    ) {
11984        self.manipulate_text(window, cx, |text| {
11985            text.chars()
11986                .map(|c| match c {
11987                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11988                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11989                    _ => c,
11990                })
11991                .collect()
11992        })
11993    }
11994
11995    pub fn convert_to_rot47(
11996        &mut self,
11997        _: &ConvertToRot47,
11998        window: &mut Window,
11999        cx: &mut Context<Self>,
12000    ) {
12001        self.manipulate_text(window, cx, |text| {
12002            text.chars()
12003                .map(|c| {
12004                    let code_point = c as u32;
12005                    if code_point >= 33 && code_point <= 126 {
12006                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12007                    }
12008                    c
12009                })
12010                .collect()
12011        })
12012    }
12013
12014    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12015    where
12016        Fn: FnMut(&str) -> String,
12017    {
12018        let buffer = self.buffer.read(cx).snapshot(cx);
12019
12020        let mut new_selections = Vec::new();
12021        let mut edits = Vec::new();
12022        let mut selection_adjustment = 0isize;
12023
12024        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12025            let selection_is_empty = selection.is_empty();
12026
12027            let (start, end) = if selection_is_empty {
12028                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12029                (word_range.start, word_range.end)
12030            } else {
12031                (
12032                    buffer.point_to_offset(selection.start),
12033                    buffer.point_to_offset(selection.end),
12034                )
12035            };
12036
12037            let text = buffer.text_for_range(start..end).collect::<String>();
12038            let old_length = text.len() as isize;
12039            let text = callback(&text);
12040
12041            new_selections.push(Selection {
12042                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12043                end: MultiBufferOffset(
12044                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12045                ),
12046                goal: SelectionGoal::None,
12047                id: selection.id,
12048                reversed: selection.reversed,
12049            });
12050
12051            selection_adjustment += old_length - text.len() as isize;
12052
12053            edits.push((start..end, text));
12054        }
12055
12056        self.transact(window, cx, |this, window, cx| {
12057            this.buffer.update(cx, |buffer, cx| {
12058                buffer.edit(edits, None, cx);
12059            });
12060
12061            this.change_selections(Default::default(), window, cx, |s| {
12062                s.select(new_selections);
12063            });
12064
12065            this.request_autoscroll(Autoscroll::fit(), cx);
12066        });
12067    }
12068
12069    pub fn move_selection_on_drop(
12070        &mut self,
12071        selection: &Selection<Anchor>,
12072        target: DisplayPoint,
12073        is_cut: bool,
12074        window: &mut Window,
12075        cx: &mut Context<Self>,
12076    ) {
12077        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12078        let buffer = display_map.buffer_snapshot();
12079        let mut edits = Vec::new();
12080        let insert_point = display_map
12081            .clip_point(target, Bias::Left)
12082            .to_point(&display_map);
12083        let text = buffer
12084            .text_for_range(selection.start..selection.end)
12085            .collect::<String>();
12086        if is_cut {
12087            edits.push(((selection.start..selection.end), String::new()));
12088        }
12089        let insert_anchor = buffer.anchor_before(insert_point);
12090        edits.push(((insert_anchor..insert_anchor), text));
12091        let last_edit_start = insert_anchor.bias_left(buffer);
12092        let last_edit_end = insert_anchor.bias_right(buffer);
12093        self.transact(window, cx, |this, window, cx| {
12094            this.buffer.update(cx, |buffer, cx| {
12095                buffer.edit(edits, None, cx);
12096            });
12097            this.change_selections(Default::default(), window, cx, |s| {
12098                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12099            });
12100        });
12101    }
12102
12103    pub fn clear_selection_drag_state(&mut self) {
12104        self.selection_drag_state = SelectionDragState::None;
12105    }
12106
12107    pub fn duplicate(
12108        &mut self,
12109        upwards: bool,
12110        whole_lines: bool,
12111        window: &mut Window,
12112        cx: &mut Context<Self>,
12113    ) {
12114        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12115
12116        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12117        let buffer = display_map.buffer_snapshot();
12118        let selections = self.selections.all::<Point>(&display_map);
12119
12120        let mut edits = Vec::new();
12121        let mut selections_iter = selections.iter().peekable();
12122        while let Some(selection) = selections_iter.next() {
12123            let mut rows = selection.spanned_rows(false, &display_map);
12124            // duplicate line-wise
12125            if whole_lines || selection.start == selection.end {
12126                // Avoid duplicating the same lines twice.
12127                while let Some(next_selection) = selections_iter.peek() {
12128                    let next_rows = next_selection.spanned_rows(false, &display_map);
12129                    if next_rows.start < rows.end {
12130                        rows.end = next_rows.end;
12131                        selections_iter.next().unwrap();
12132                    } else {
12133                        break;
12134                    }
12135                }
12136
12137                // Copy the text from the selected row region and splice it either at the start
12138                // or end of the region.
12139                let start = Point::new(rows.start.0, 0);
12140                let end = Point::new(
12141                    rows.end.previous_row().0,
12142                    buffer.line_len(rows.end.previous_row()),
12143                );
12144
12145                let mut text = buffer.text_for_range(start..end).collect::<String>();
12146
12147                let insert_location = if upwards {
12148                    // When duplicating upward, we need to insert before the current line.
12149                    // If we're on the last line and it doesn't end with a newline,
12150                    // we need to add a newline before the duplicated content.
12151                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12152                        && buffer.max_point().column > 0
12153                        && !text.ends_with('\n');
12154
12155                    if needs_leading_newline {
12156                        text.insert(0, '\n');
12157                        end
12158                    } else {
12159                        text.push('\n');
12160                        Point::new(rows.start.0, 0)
12161                    }
12162                } else {
12163                    text.push('\n');
12164                    start
12165                };
12166                edits.push((insert_location..insert_location, text));
12167            } else {
12168                // duplicate character-wise
12169                let start = selection.start;
12170                let end = selection.end;
12171                let text = buffer.text_for_range(start..end).collect::<String>();
12172                edits.push((selection.end..selection.end, text));
12173            }
12174        }
12175
12176        self.transact(window, cx, |this, window, cx| {
12177            this.buffer.update(cx, |buffer, cx| {
12178                buffer.edit(edits, None, cx);
12179            });
12180
12181            // When duplicating upward with whole lines, move the cursor to the duplicated line
12182            if upwards && whole_lines {
12183                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12184
12185                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12186                    let mut new_ranges = Vec::new();
12187                    let selections = s.all::<Point>(&display_map);
12188                    let mut selections_iter = selections.iter().peekable();
12189
12190                    while let Some(first_selection) = selections_iter.next() {
12191                        // Group contiguous selections together to find the total row span
12192                        let mut group_selections = vec![first_selection];
12193                        let mut rows = first_selection.spanned_rows(false, &display_map);
12194
12195                        while let Some(next_selection) = selections_iter.peek() {
12196                            let next_rows = next_selection.spanned_rows(false, &display_map);
12197                            if next_rows.start < rows.end {
12198                                rows.end = next_rows.end;
12199                                group_selections.push(selections_iter.next().unwrap());
12200                            } else {
12201                                break;
12202                            }
12203                        }
12204
12205                        let row_count = rows.end.0 - rows.start.0;
12206
12207                        // Move all selections in this group up by the total number of duplicated rows
12208                        for selection in group_selections {
12209                            let new_start = Point::new(
12210                                selection.start.row.saturating_sub(row_count),
12211                                selection.start.column,
12212                            );
12213
12214                            let new_end = Point::new(
12215                                selection.end.row.saturating_sub(row_count),
12216                                selection.end.column,
12217                            );
12218
12219                            new_ranges.push(new_start..new_end);
12220                        }
12221                    }
12222
12223                    s.select_ranges(new_ranges);
12224                });
12225            }
12226
12227            this.request_autoscroll(Autoscroll::fit(), cx);
12228        });
12229    }
12230
12231    pub fn duplicate_line_up(
12232        &mut self,
12233        _: &DuplicateLineUp,
12234        window: &mut Window,
12235        cx: &mut Context<Self>,
12236    ) {
12237        self.duplicate(true, true, window, cx);
12238    }
12239
12240    pub fn duplicate_line_down(
12241        &mut self,
12242        _: &DuplicateLineDown,
12243        window: &mut Window,
12244        cx: &mut Context<Self>,
12245    ) {
12246        self.duplicate(false, true, window, cx);
12247    }
12248
12249    pub fn duplicate_selection(
12250        &mut self,
12251        _: &DuplicateSelection,
12252        window: &mut Window,
12253        cx: &mut Context<Self>,
12254    ) {
12255        self.duplicate(false, false, window, cx);
12256    }
12257
12258    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12259        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12260        if self.mode.is_single_line() {
12261            cx.propagate();
12262            return;
12263        }
12264
12265        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12266        let buffer = self.buffer.read(cx).snapshot(cx);
12267
12268        let mut edits = Vec::new();
12269        let mut unfold_ranges = Vec::new();
12270        let mut refold_creases = Vec::new();
12271
12272        let selections = self.selections.all::<Point>(&display_map);
12273        let mut selections = selections.iter().peekable();
12274        let mut contiguous_row_selections = Vec::new();
12275        let mut new_selections = Vec::new();
12276
12277        while let Some(selection) = selections.next() {
12278            // Find all the selections that span a contiguous row range
12279            let (start_row, end_row) = consume_contiguous_rows(
12280                &mut contiguous_row_selections,
12281                selection,
12282                &display_map,
12283                &mut selections,
12284            );
12285
12286            // Move the text spanned by the row range to be before the line preceding the row range
12287            if start_row.0 > 0 {
12288                let range_to_move = Point::new(
12289                    start_row.previous_row().0,
12290                    buffer.line_len(start_row.previous_row()),
12291                )
12292                    ..Point::new(
12293                        end_row.previous_row().0,
12294                        buffer.line_len(end_row.previous_row()),
12295                    );
12296                let insertion_point = display_map
12297                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12298                    .0;
12299
12300                // Don't move lines across excerpts
12301                if buffer
12302                    .excerpt_containing(insertion_point..range_to_move.end)
12303                    .is_some()
12304                {
12305                    let text = buffer
12306                        .text_for_range(range_to_move.clone())
12307                        .flat_map(|s| s.chars())
12308                        .skip(1)
12309                        .chain(['\n'])
12310                        .collect::<String>();
12311
12312                    edits.push((
12313                        buffer.anchor_after(range_to_move.start)
12314                            ..buffer.anchor_before(range_to_move.end),
12315                        String::new(),
12316                    ));
12317                    let insertion_anchor = buffer.anchor_after(insertion_point);
12318                    edits.push((insertion_anchor..insertion_anchor, text));
12319
12320                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12321
12322                    // Move selections up
12323                    new_selections.extend(contiguous_row_selections.drain(..).map(
12324                        |mut selection| {
12325                            selection.start.row -= row_delta;
12326                            selection.end.row -= row_delta;
12327                            selection
12328                        },
12329                    ));
12330
12331                    // Move folds up
12332                    unfold_ranges.push(range_to_move.clone());
12333                    for fold in display_map.folds_in_range(
12334                        buffer.anchor_before(range_to_move.start)
12335                            ..buffer.anchor_after(range_to_move.end),
12336                    ) {
12337                        let mut start = fold.range.start.to_point(&buffer);
12338                        let mut end = fold.range.end.to_point(&buffer);
12339                        start.row -= row_delta;
12340                        end.row -= row_delta;
12341                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12342                    }
12343                }
12344            }
12345
12346            // If we didn't move line(s), preserve the existing selections
12347            new_selections.append(&mut contiguous_row_selections);
12348        }
12349
12350        self.transact(window, cx, |this, window, cx| {
12351            this.unfold_ranges(&unfold_ranges, true, true, cx);
12352            this.buffer.update(cx, |buffer, cx| {
12353                for (range, text) in edits {
12354                    buffer.edit([(range, text)], None, cx);
12355                }
12356            });
12357            this.fold_creases(refold_creases, true, window, cx);
12358            this.change_selections(Default::default(), window, cx, |s| {
12359                s.select(new_selections);
12360            })
12361        });
12362    }
12363
12364    pub fn move_line_down(
12365        &mut self,
12366        _: &MoveLineDown,
12367        window: &mut Window,
12368        cx: &mut Context<Self>,
12369    ) {
12370        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12371        if self.mode.is_single_line() {
12372            cx.propagate();
12373            return;
12374        }
12375
12376        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12377        let buffer = self.buffer.read(cx).snapshot(cx);
12378
12379        let mut edits = Vec::new();
12380        let mut unfold_ranges = Vec::new();
12381        let mut refold_creases = Vec::new();
12382
12383        let selections = self.selections.all::<Point>(&display_map);
12384        let mut selections = selections.iter().peekable();
12385        let mut contiguous_row_selections = Vec::new();
12386        let mut new_selections = Vec::new();
12387
12388        while let Some(selection) = selections.next() {
12389            // Find all the selections that span a contiguous row range
12390            let (start_row, end_row) = consume_contiguous_rows(
12391                &mut contiguous_row_selections,
12392                selection,
12393                &display_map,
12394                &mut selections,
12395            );
12396
12397            // Move the text spanned by the row range to be after the last line of the row range
12398            if end_row.0 <= buffer.max_point().row {
12399                let range_to_move =
12400                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12401                let insertion_point = display_map
12402                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12403                    .0;
12404
12405                // Don't move lines across excerpt boundaries
12406                if buffer
12407                    .excerpt_containing(range_to_move.start..insertion_point)
12408                    .is_some()
12409                {
12410                    let mut text = String::from("\n");
12411                    text.extend(buffer.text_for_range(range_to_move.clone()));
12412                    text.pop(); // Drop trailing newline
12413                    edits.push((
12414                        buffer.anchor_after(range_to_move.start)
12415                            ..buffer.anchor_before(range_to_move.end),
12416                        String::new(),
12417                    ));
12418                    let insertion_anchor = buffer.anchor_after(insertion_point);
12419                    edits.push((insertion_anchor..insertion_anchor, text));
12420
12421                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12422
12423                    // Move selections down
12424                    new_selections.extend(contiguous_row_selections.drain(..).map(
12425                        |mut selection| {
12426                            selection.start.row += row_delta;
12427                            selection.end.row += row_delta;
12428                            selection
12429                        },
12430                    ));
12431
12432                    // Move folds down
12433                    unfold_ranges.push(range_to_move.clone());
12434                    for fold in display_map.folds_in_range(
12435                        buffer.anchor_before(range_to_move.start)
12436                            ..buffer.anchor_after(range_to_move.end),
12437                    ) {
12438                        let mut start = fold.range.start.to_point(&buffer);
12439                        let mut end = fold.range.end.to_point(&buffer);
12440                        start.row += row_delta;
12441                        end.row += row_delta;
12442                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12443                    }
12444                }
12445            }
12446
12447            // If we didn't move line(s), preserve the existing selections
12448            new_selections.append(&mut contiguous_row_selections);
12449        }
12450
12451        self.transact(window, cx, |this, window, cx| {
12452            this.unfold_ranges(&unfold_ranges, true, true, cx);
12453            this.buffer.update(cx, |buffer, cx| {
12454                for (range, text) in edits {
12455                    buffer.edit([(range, text)], None, cx);
12456                }
12457            });
12458            this.fold_creases(refold_creases, true, window, cx);
12459            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12460        });
12461    }
12462
12463    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12464        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12465        let text_layout_details = &self.text_layout_details(window);
12466        self.transact(window, cx, |this, window, cx| {
12467            let edits = this.change_selections(Default::default(), window, cx, |s| {
12468                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12469                s.move_with(|display_map, selection| {
12470                    if !selection.is_empty() {
12471                        return;
12472                    }
12473
12474                    let mut head = selection.head();
12475                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12476                    if head.column() == display_map.line_len(head.row()) {
12477                        transpose_offset = display_map
12478                            .buffer_snapshot()
12479                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12480                    }
12481
12482                    if transpose_offset == MultiBufferOffset(0) {
12483                        return;
12484                    }
12485
12486                    *head.column_mut() += 1;
12487                    head = display_map.clip_point(head, Bias::Right);
12488                    let goal = SelectionGoal::HorizontalPosition(
12489                        display_map
12490                            .x_for_display_point(head, text_layout_details)
12491                            .into(),
12492                    );
12493                    selection.collapse_to(head, goal);
12494
12495                    let transpose_start = display_map
12496                        .buffer_snapshot()
12497                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12498                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12499                        let transpose_end = display_map
12500                            .buffer_snapshot()
12501                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12502                        if let Some(ch) = display_map
12503                            .buffer_snapshot()
12504                            .chars_at(transpose_start)
12505                            .next()
12506                        {
12507                            edits.push((transpose_start..transpose_offset, String::new()));
12508                            edits.push((transpose_end..transpose_end, ch.to_string()));
12509                        }
12510                    }
12511                });
12512                edits
12513            });
12514            this.buffer
12515                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12516            let selections = this
12517                .selections
12518                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12519            this.change_selections(Default::default(), window, cx, |s| {
12520                s.select(selections);
12521            });
12522        });
12523    }
12524
12525    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12526        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12527        if self.mode.is_single_line() {
12528            cx.propagate();
12529            return;
12530        }
12531
12532        self.rewrap_impl(RewrapOptions::default(), cx)
12533    }
12534
12535    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12536        let buffer = self.buffer.read(cx).snapshot(cx);
12537        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12538
12539        #[derive(Clone, Debug, PartialEq)]
12540        enum CommentFormat {
12541            /// single line comment, with prefix for line
12542            Line(String),
12543            /// single line within a block comment, with prefix for line
12544            BlockLine(String),
12545            /// a single line of a block comment that includes the initial delimiter
12546            BlockCommentWithStart(BlockCommentConfig),
12547            /// a single line of a block comment that includes the ending delimiter
12548            BlockCommentWithEnd(BlockCommentConfig),
12549        }
12550
12551        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12552        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12553            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12554                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12555                .peekable();
12556
12557            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12558                row
12559            } else {
12560                return Vec::new();
12561            };
12562
12563            let language_settings = buffer.language_settings_at(selection.head(), cx);
12564            let language_scope = buffer.language_scope_at(selection.head());
12565
12566            let indent_and_prefix_for_row =
12567                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12568                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12569                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12570                        &language_scope
12571                    {
12572                        let indent_end = Point::new(row, indent.len);
12573                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12574                        let line_text_after_indent = buffer
12575                            .text_for_range(indent_end..line_end)
12576                            .collect::<String>();
12577
12578                        let is_within_comment_override = buffer
12579                            .language_scope_at(indent_end)
12580                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12581                        let comment_delimiters = if is_within_comment_override {
12582                            // we are within a comment syntax node, but we don't
12583                            // yet know what kind of comment: block, doc or line
12584                            match (
12585                                language_scope.documentation_comment(),
12586                                language_scope.block_comment(),
12587                            ) {
12588                                (Some(config), _) | (_, Some(config))
12589                                    if buffer.contains_str_at(indent_end, &config.start) =>
12590                                {
12591                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12592                                }
12593                                (Some(config), _) | (_, Some(config))
12594                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12595                                {
12596                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12597                                }
12598                                (Some(config), _) | (_, Some(config))
12599                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12600                                {
12601                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12602                                }
12603                                (_, _) => language_scope
12604                                    .line_comment_prefixes()
12605                                    .iter()
12606                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12607                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12608                            }
12609                        } else {
12610                            // we not in an overridden comment node, but we may
12611                            // be within a non-overridden line comment node
12612                            language_scope
12613                                .line_comment_prefixes()
12614                                .iter()
12615                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12616                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12617                        };
12618
12619                        let rewrap_prefix = language_scope
12620                            .rewrap_prefixes()
12621                            .iter()
12622                            .find_map(|prefix_regex| {
12623                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12624                                    if mat.start() == 0 {
12625                                        Some(mat.as_str().to_string())
12626                                    } else {
12627                                        None
12628                                    }
12629                                })
12630                            })
12631                            .flatten();
12632                        (comment_delimiters, rewrap_prefix)
12633                    } else {
12634                        (None, None)
12635                    };
12636                    (indent, comment_prefix, rewrap_prefix)
12637                };
12638
12639            let mut ranges = Vec::new();
12640            let from_empty_selection = selection.is_empty();
12641
12642            let mut current_range_start = first_row;
12643            let mut prev_row = first_row;
12644            let (
12645                mut current_range_indent,
12646                mut current_range_comment_delimiters,
12647                mut current_range_rewrap_prefix,
12648            ) = indent_and_prefix_for_row(first_row);
12649
12650            for row in non_blank_rows_iter.skip(1) {
12651                let has_paragraph_break = row > prev_row + 1;
12652
12653                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12654                    indent_and_prefix_for_row(row);
12655
12656                let has_indent_change = row_indent != current_range_indent;
12657                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12658
12659                let has_boundary_change = has_comment_change
12660                    || row_rewrap_prefix.is_some()
12661                    || (has_indent_change && current_range_comment_delimiters.is_some());
12662
12663                if has_paragraph_break || has_boundary_change {
12664                    ranges.push((
12665                        language_settings.clone(),
12666                        Point::new(current_range_start, 0)
12667                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12668                        current_range_indent,
12669                        current_range_comment_delimiters.clone(),
12670                        current_range_rewrap_prefix.clone(),
12671                        from_empty_selection,
12672                    ));
12673                    current_range_start = row;
12674                    current_range_indent = row_indent;
12675                    current_range_comment_delimiters = row_comment_delimiters;
12676                    current_range_rewrap_prefix = row_rewrap_prefix;
12677                }
12678                prev_row = row;
12679            }
12680
12681            ranges.push((
12682                language_settings.clone(),
12683                Point::new(current_range_start, 0)
12684                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12685                current_range_indent,
12686                current_range_comment_delimiters,
12687                current_range_rewrap_prefix,
12688                from_empty_selection,
12689            ));
12690
12691            ranges
12692        });
12693
12694        let mut edits = Vec::new();
12695        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12696
12697        for (
12698            language_settings,
12699            wrap_range,
12700            mut indent_size,
12701            comment_prefix,
12702            rewrap_prefix,
12703            from_empty_selection,
12704        ) in wrap_ranges
12705        {
12706            let mut start_row = wrap_range.start.row;
12707            let mut end_row = wrap_range.end.row;
12708
12709            // Skip selections that overlap with a range that has already been rewrapped.
12710            let selection_range = start_row..end_row;
12711            if rewrapped_row_ranges
12712                .iter()
12713                .any(|range| range.overlaps(&selection_range))
12714            {
12715                continue;
12716            }
12717
12718            let tab_size = language_settings.tab_size;
12719
12720            let (line_prefix, inside_comment) = match &comment_prefix {
12721                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12722                    (Some(prefix.as_str()), true)
12723                }
12724                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12725                    (Some(prefix.as_ref()), true)
12726                }
12727                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12728                    start: _,
12729                    end: _,
12730                    prefix,
12731                    tab_size,
12732                })) => {
12733                    indent_size.len += tab_size;
12734                    (Some(prefix.as_ref()), true)
12735                }
12736                None => (None, false),
12737            };
12738            let indent_prefix = indent_size.chars().collect::<String>();
12739            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12740
12741            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12742                RewrapBehavior::InComments => inside_comment,
12743                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12744                RewrapBehavior::Anywhere => true,
12745            };
12746
12747            let should_rewrap = options.override_language_settings
12748                || allow_rewrap_based_on_language
12749                || self.hard_wrap.is_some();
12750            if !should_rewrap {
12751                continue;
12752            }
12753
12754            if from_empty_selection {
12755                'expand_upwards: while start_row > 0 {
12756                    let prev_row = start_row - 1;
12757                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12758                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12759                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12760                    {
12761                        start_row = prev_row;
12762                    } else {
12763                        break 'expand_upwards;
12764                    }
12765                }
12766
12767                'expand_downwards: while end_row < buffer.max_point().row {
12768                    let next_row = end_row + 1;
12769                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12770                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12771                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12772                    {
12773                        end_row = next_row;
12774                    } else {
12775                        break 'expand_downwards;
12776                    }
12777                }
12778            }
12779
12780            let start = Point::new(start_row, 0);
12781            let start_offset = ToOffset::to_offset(&start, &buffer);
12782            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12783            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12784            let mut first_line_delimiter = None;
12785            let mut last_line_delimiter = None;
12786            let Some(lines_without_prefixes) = selection_text
12787                .lines()
12788                .enumerate()
12789                .map(|(ix, line)| {
12790                    let line_trimmed = line.trim_start();
12791                    if rewrap_prefix.is_some() && ix > 0 {
12792                        Ok(line_trimmed)
12793                    } else if let Some(
12794                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12795                            start,
12796                            prefix,
12797                            end,
12798                            tab_size,
12799                        })
12800                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12801                            start,
12802                            prefix,
12803                            end,
12804                            tab_size,
12805                        }),
12806                    ) = &comment_prefix
12807                    {
12808                        let line_trimmed = line_trimmed
12809                            .strip_prefix(start.as_ref())
12810                            .map(|s| {
12811                                let mut indent_size = indent_size;
12812                                indent_size.len -= tab_size;
12813                                let indent_prefix: String = indent_size.chars().collect();
12814                                first_line_delimiter = Some((indent_prefix, start));
12815                                s.trim_start()
12816                            })
12817                            .unwrap_or(line_trimmed);
12818                        let line_trimmed = line_trimmed
12819                            .strip_suffix(end.as_ref())
12820                            .map(|s| {
12821                                last_line_delimiter = Some(end);
12822                                s.trim_end()
12823                            })
12824                            .unwrap_or(line_trimmed);
12825                        let line_trimmed = line_trimmed
12826                            .strip_prefix(prefix.as_ref())
12827                            .unwrap_or(line_trimmed);
12828                        Ok(line_trimmed)
12829                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12830                        line_trimmed.strip_prefix(prefix).with_context(|| {
12831                            format!("line did not start with prefix {prefix:?}: {line:?}")
12832                        })
12833                    } else {
12834                        line_trimmed
12835                            .strip_prefix(&line_prefix.trim_start())
12836                            .with_context(|| {
12837                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12838                            })
12839                    }
12840                })
12841                .collect::<Result<Vec<_>, _>>()
12842                .log_err()
12843            else {
12844                continue;
12845            };
12846
12847            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12848                buffer
12849                    .language_settings_at(Point::new(start_row, 0), cx)
12850                    .preferred_line_length as usize
12851            });
12852
12853            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12854                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12855            } else {
12856                line_prefix.clone()
12857            };
12858
12859            let wrapped_text = {
12860                let mut wrapped_text = wrap_with_prefix(
12861                    line_prefix,
12862                    subsequent_lines_prefix,
12863                    lines_without_prefixes.join("\n"),
12864                    wrap_column,
12865                    tab_size,
12866                    options.preserve_existing_whitespace,
12867                );
12868
12869                if let Some((indent, delimiter)) = first_line_delimiter {
12870                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12871                }
12872                if let Some(last_line) = last_line_delimiter {
12873                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12874                }
12875
12876                wrapped_text
12877            };
12878
12879            // TODO: should always use char-based diff while still supporting cursor behavior that
12880            // matches vim.
12881            let mut diff_options = DiffOptions::default();
12882            if options.override_language_settings {
12883                diff_options.max_word_diff_len = 0;
12884                diff_options.max_word_diff_line_count = 0;
12885            } else {
12886                diff_options.max_word_diff_len = usize::MAX;
12887                diff_options.max_word_diff_line_count = usize::MAX;
12888            }
12889
12890            for (old_range, new_text) in
12891                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12892            {
12893                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12894                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12895                edits.push((edit_start..edit_end, new_text));
12896            }
12897
12898            rewrapped_row_ranges.push(start_row..=end_row);
12899        }
12900
12901        self.buffer
12902            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12903    }
12904
12905    pub fn cut_common(
12906        &mut self,
12907        cut_no_selection_line: bool,
12908        window: &mut Window,
12909        cx: &mut Context<Self>,
12910    ) -> ClipboardItem {
12911        let mut text = String::new();
12912        let buffer = self.buffer.read(cx).snapshot(cx);
12913        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12914        let mut clipboard_selections = Vec::with_capacity(selections.len());
12915        {
12916            let max_point = buffer.max_point();
12917            let mut is_first = true;
12918            let mut prev_selection_was_entire_line = false;
12919            for selection in &mut selections {
12920                let is_entire_line =
12921                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12922                if is_entire_line {
12923                    selection.start = Point::new(selection.start.row, 0);
12924                    if !selection.is_empty() && selection.end.column == 0 {
12925                        selection.end = cmp::min(max_point, selection.end);
12926                    } else {
12927                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12928                    }
12929                    selection.goal = SelectionGoal::None;
12930                }
12931                if is_first {
12932                    is_first = false;
12933                } else if !prev_selection_was_entire_line {
12934                    text += "\n";
12935                }
12936                prev_selection_was_entire_line = is_entire_line;
12937                let mut len = 0;
12938                for chunk in buffer.text_for_range(selection.start..selection.end) {
12939                    text.push_str(chunk);
12940                    len += chunk.len();
12941                }
12942
12943                clipboard_selections.push(ClipboardSelection::for_buffer(
12944                    len,
12945                    is_entire_line,
12946                    selection.range(),
12947                    &buffer,
12948                    self.project.as_ref(),
12949                    cx,
12950                ));
12951            }
12952        }
12953
12954        self.transact(window, cx, |this, window, cx| {
12955            this.change_selections(Default::default(), window, cx, |s| {
12956                s.select(selections);
12957            });
12958            this.insert("", window, cx);
12959        });
12960        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12961    }
12962
12963    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12964        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12965        let item = self.cut_common(true, window, cx);
12966        cx.write_to_clipboard(item);
12967    }
12968
12969    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12970        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12971        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12972            s.move_with(|snapshot, sel| {
12973                if sel.is_empty() {
12974                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12975                }
12976                if sel.is_empty() {
12977                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12978                }
12979            });
12980        });
12981        let item = self.cut_common(false, window, cx);
12982        cx.set_global(KillRing(item))
12983    }
12984
12985    pub fn kill_ring_yank(
12986        &mut self,
12987        _: &KillRingYank,
12988        window: &mut Window,
12989        cx: &mut Context<Self>,
12990    ) {
12991        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12992        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12993            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12994                (kill_ring.text().to_string(), kill_ring.metadata_json())
12995            } else {
12996                return;
12997            }
12998        } else {
12999            return;
13000        };
13001        self.do_paste(&text, metadata, false, window, cx);
13002    }
13003
13004    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13005        self.do_copy(true, cx);
13006    }
13007
13008    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13009        self.do_copy(false, cx);
13010    }
13011
13012    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13013        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13014        let buffer = self.buffer.read(cx).read(cx);
13015        let mut text = String::new();
13016
13017        let mut clipboard_selections = Vec::with_capacity(selections.len());
13018        {
13019            let max_point = buffer.max_point();
13020            let mut is_first = true;
13021            let mut prev_selection_was_entire_line = false;
13022            for selection in &selections {
13023                let mut start = selection.start;
13024                let mut end = selection.end;
13025                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13026                let mut add_trailing_newline = false;
13027                if is_entire_line {
13028                    start = Point::new(start.row, 0);
13029                    let next_line_start = Point::new(end.row + 1, 0);
13030                    if next_line_start <= max_point {
13031                        end = next_line_start;
13032                    } else {
13033                        // We're on the last line without a trailing newline.
13034                        // Copy to the end of the line and add a newline afterwards.
13035                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13036                        add_trailing_newline = true;
13037                    }
13038                }
13039
13040                let mut trimmed_selections = Vec::new();
13041                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13042                    let row = MultiBufferRow(start.row);
13043                    let first_indent = buffer.indent_size_for_line(row);
13044                    if first_indent.len == 0 || start.column > first_indent.len {
13045                        trimmed_selections.push(start..end);
13046                    } else {
13047                        trimmed_selections.push(
13048                            Point::new(row.0, first_indent.len)
13049                                ..Point::new(row.0, buffer.line_len(row)),
13050                        );
13051                        for row in start.row + 1..=end.row {
13052                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13053                            if row == end.row {
13054                                line_len = end.column;
13055                            }
13056                            if line_len == 0 {
13057                                trimmed_selections
13058                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13059                                continue;
13060                            }
13061                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13062                            if row_indent_size.len >= first_indent.len {
13063                                trimmed_selections.push(
13064                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13065                                );
13066                            } else {
13067                                trimmed_selections.clear();
13068                                trimmed_selections.push(start..end);
13069                                break;
13070                            }
13071                        }
13072                    }
13073                } else {
13074                    trimmed_selections.push(start..end);
13075                }
13076
13077                for trimmed_range in trimmed_selections {
13078                    if is_first {
13079                        is_first = false;
13080                    } else if !prev_selection_was_entire_line {
13081                        text += "\n";
13082                    }
13083                    prev_selection_was_entire_line = is_entire_line;
13084                    let mut len = 0;
13085                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13086                        text.push_str(chunk);
13087                        len += chunk.len();
13088                    }
13089                    if add_trailing_newline {
13090                        text.push('\n');
13091                        len += 1;
13092                    }
13093                    clipboard_selections.push(ClipboardSelection::for_buffer(
13094                        len,
13095                        is_entire_line,
13096                        trimmed_range,
13097                        &buffer,
13098                        self.project.as_ref(),
13099                        cx,
13100                    ));
13101                }
13102            }
13103        }
13104
13105        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13106            text,
13107            clipboard_selections,
13108        ));
13109    }
13110
13111    pub fn do_paste(
13112        &mut self,
13113        text: &String,
13114        clipboard_selections: Option<Vec<ClipboardSelection>>,
13115        handle_entire_lines: bool,
13116        window: &mut Window,
13117        cx: &mut Context<Self>,
13118    ) {
13119        if self.read_only(cx) {
13120            return;
13121        }
13122
13123        let clipboard_text = Cow::Borrowed(text.as_str());
13124
13125        self.transact(window, cx, |this, window, cx| {
13126            let had_active_edit_prediction = this.has_active_edit_prediction();
13127            let display_map = this.display_snapshot(cx);
13128            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13129            let cursor_offset = this
13130                .selections
13131                .last::<MultiBufferOffset>(&display_map)
13132                .head();
13133
13134            if let Some(mut clipboard_selections) = clipboard_selections {
13135                let all_selections_were_entire_line =
13136                    clipboard_selections.iter().all(|s| s.is_entire_line);
13137                let first_selection_indent_column =
13138                    clipboard_selections.first().map(|s| s.first_line_indent);
13139                if clipboard_selections.len() != old_selections.len() {
13140                    clipboard_selections.drain(..);
13141                }
13142                let mut auto_indent_on_paste = true;
13143
13144                this.buffer.update(cx, |buffer, cx| {
13145                    let snapshot = buffer.read(cx);
13146                    auto_indent_on_paste = snapshot
13147                        .language_settings_at(cursor_offset, cx)
13148                        .auto_indent_on_paste;
13149
13150                    let mut start_offset = 0;
13151                    let mut edits = Vec::new();
13152                    let mut original_indent_columns = Vec::new();
13153                    for (ix, selection) in old_selections.iter().enumerate() {
13154                        let to_insert;
13155                        let entire_line;
13156                        let original_indent_column;
13157                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13158                            let end_offset = start_offset + clipboard_selection.len;
13159                            to_insert = &clipboard_text[start_offset..end_offset];
13160                            entire_line = clipboard_selection.is_entire_line;
13161                            start_offset = if entire_line {
13162                                end_offset
13163                            } else {
13164                                end_offset + 1
13165                            };
13166                            original_indent_column = Some(clipboard_selection.first_line_indent);
13167                        } else {
13168                            to_insert = &*clipboard_text;
13169                            entire_line = all_selections_were_entire_line;
13170                            original_indent_column = first_selection_indent_column
13171                        }
13172
13173                        let (range, to_insert) =
13174                            if selection.is_empty() && handle_entire_lines && entire_line {
13175                                // If the corresponding selection was empty when this slice of the
13176                                // clipboard text was written, then the entire line containing the
13177                                // selection was copied. If this selection is also currently empty,
13178                                // then paste the line before the current line of the buffer.
13179                                let column = selection.start.to_point(&snapshot).column as usize;
13180                                let line_start = selection.start - column;
13181                                (line_start..line_start, Cow::Borrowed(to_insert))
13182                            } else {
13183                                let language = snapshot.language_at(selection.head());
13184                                let range = selection.range();
13185                                if let Some(language) = language
13186                                    && language.name() == "Markdown".into()
13187                                {
13188                                    edit_for_markdown_paste(
13189                                        &snapshot,
13190                                        range,
13191                                        to_insert,
13192                                        url::Url::parse(to_insert).ok(),
13193                                    )
13194                                } else {
13195                                    (range, Cow::Borrowed(to_insert))
13196                                }
13197                            };
13198
13199                        edits.push((range, to_insert));
13200                        original_indent_columns.push(original_indent_column);
13201                    }
13202                    drop(snapshot);
13203
13204                    buffer.edit(
13205                        edits,
13206                        if auto_indent_on_paste {
13207                            Some(AutoindentMode::Block {
13208                                original_indent_columns,
13209                            })
13210                        } else {
13211                            None
13212                        },
13213                        cx,
13214                    );
13215                });
13216
13217                let selections = this
13218                    .selections
13219                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13220                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13221            } else {
13222                let url = url::Url::parse(&clipboard_text).ok();
13223
13224                let auto_indent_mode = if !clipboard_text.is_empty() {
13225                    Some(AutoindentMode::Block {
13226                        original_indent_columns: Vec::new(),
13227                    })
13228                } else {
13229                    None
13230                };
13231
13232                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13233                    let snapshot = buffer.snapshot(cx);
13234
13235                    let anchors = old_selections
13236                        .iter()
13237                        .map(|s| {
13238                            let anchor = snapshot.anchor_after(s.head());
13239                            s.map(|_| anchor)
13240                        })
13241                        .collect::<Vec<_>>();
13242
13243                    let mut edits = Vec::new();
13244
13245                    for selection in old_selections.iter() {
13246                        let language = snapshot.language_at(selection.head());
13247                        let range = selection.range();
13248
13249                        let (edit_range, edit_text) = if let Some(language) = language
13250                            && language.name() == "Markdown".into()
13251                        {
13252                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13253                        } else {
13254                            (range, clipboard_text.clone())
13255                        };
13256
13257                        edits.push((edit_range, edit_text));
13258                    }
13259
13260                    drop(snapshot);
13261                    buffer.edit(edits, auto_indent_mode, cx);
13262
13263                    anchors
13264                });
13265
13266                this.change_selections(Default::default(), window, cx, |s| {
13267                    s.select_anchors(selection_anchors);
13268                });
13269            }
13270
13271            //   🤔                 |    ..     | show_in_menu |
13272            // | ..                  |   true        true
13273            // | had_edit_prediction |   false       true
13274
13275            let trigger_in_words =
13276                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13277
13278            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13279        });
13280    }
13281
13282    pub fn diff_clipboard_with_selection(
13283        &mut self,
13284        _: &DiffClipboardWithSelection,
13285        window: &mut Window,
13286        cx: &mut Context<Self>,
13287    ) {
13288        let selections = self
13289            .selections
13290            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13291
13292        if selections.is_empty() {
13293            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13294            return;
13295        };
13296
13297        let clipboard_text = match cx.read_from_clipboard() {
13298            Some(item) => match item.entries().first() {
13299                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13300                _ => None,
13301            },
13302            None => None,
13303        };
13304
13305        let Some(clipboard_text) = clipboard_text else {
13306            log::warn!("Clipboard doesn't contain text.");
13307            return;
13308        };
13309
13310        window.dispatch_action(
13311            Box::new(DiffClipboardWithSelectionData {
13312                clipboard_text,
13313                editor: cx.entity(),
13314            }),
13315            cx,
13316        );
13317    }
13318
13319    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13320        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13321        if let Some(item) = cx.read_from_clipboard() {
13322            let entries = item.entries();
13323
13324            match entries.first() {
13325                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13326                // of all the pasted entries.
13327                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13328                    .do_paste(
13329                        clipboard_string.text(),
13330                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13331                        true,
13332                        window,
13333                        cx,
13334                    ),
13335                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13336            }
13337        }
13338    }
13339
13340    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13341        if self.read_only(cx) {
13342            return;
13343        }
13344
13345        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13346
13347        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13348            if let Some((selections, _)) =
13349                self.selection_history.transaction(transaction_id).cloned()
13350            {
13351                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13352                    s.select_anchors(selections.to_vec());
13353                });
13354            } else {
13355                log::error!(
13356                    "No entry in selection_history found for undo. \
13357                     This may correspond to a bug where undo does not update the selection. \
13358                     If this is occurring, please add details to \
13359                     https://github.com/zed-industries/zed/issues/22692"
13360                );
13361            }
13362            self.request_autoscroll(Autoscroll::fit(), cx);
13363            self.unmark_text(window, cx);
13364            self.refresh_edit_prediction(true, false, window, cx);
13365            cx.emit(EditorEvent::Edited { transaction_id });
13366            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13367        }
13368    }
13369
13370    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13371        if self.read_only(cx) {
13372            return;
13373        }
13374
13375        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13376
13377        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13378            if let Some((_, Some(selections))) =
13379                self.selection_history.transaction(transaction_id).cloned()
13380            {
13381                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13382                    s.select_anchors(selections.to_vec());
13383                });
13384            } else {
13385                log::error!(
13386                    "No entry in selection_history found for redo. \
13387                     This may correspond to a bug where undo does not update the selection. \
13388                     If this is occurring, please add details to \
13389                     https://github.com/zed-industries/zed/issues/22692"
13390                );
13391            }
13392            self.request_autoscroll(Autoscroll::fit(), cx);
13393            self.unmark_text(window, cx);
13394            self.refresh_edit_prediction(true, false, window, cx);
13395            cx.emit(EditorEvent::Edited { transaction_id });
13396        }
13397    }
13398
13399    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13400        self.buffer
13401            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13402    }
13403
13404    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13405        self.buffer
13406            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13407    }
13408
13409    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13410        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13411        self.change_selections(Default::default(), window, cx, |s| {
13412            s.move_with(|map, selection| {
13413                let cursor = if selection.is_empty() {
13414                    movement::left(map, selection.start)
13415                } else {
13416                    selection.start
13417                };
13418                selection.collapse_to(cursor, SelectionGoal::None);
13419            });
13420        })
13421    }
13422
13423    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13424        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13425        self.change_selections(Default::default(), window, cx, |s| {
13426            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13427        })
13428    }
13429
13430    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13431        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13432        self.change_selections(Default::default(), window, cx, |s| {
13433            s.move_with(|map, selection| {
13434                let cursor = if selection.is_empty() {
13435                    movement::right(map, selection.end)
13436                } else {
13437                    selection.end
13438                };
13439                selection.collapse_to(cursor, SelectionGoal::None)
13440            });
13441        })
13442    }
13443
13444    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13445        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13446        self.change_selections(Default::default(), window, cx, |s| {
13447            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13448        });
13449    }
13450
13451    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13452        if self.take_rename(true, window, cx).is_some() {
13453            return;
13454        }
13455
13456        if self.mode.is_single_line() {
13457            cx.propagate();
13458            return;
13459        }
13460
13461        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13462
13463        let text_layout_details = &self.text_layout_details(window);
13464        let selection_count = self.selections.count();
13465        let first_selection = self.selections.first_anchor();
13466
13467        self.change_selections(Default::default(), window, cx, |s| {
13468            s.move_with(|map, selection| {
13469                if !selection.is_empty() {
13470                    selection.goal = SelectionGoal::None;
13471                }
13472                let (cursor, goal) = movement::up(
13473                    map,
13474                    selection.start,
13475                    selection.goal,
13476                    false,
13477                    text_layout_details,
13478                );
13479                selection.collapse_to(cursor, goal);
13480            });
13481        });
13482
13483        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13484        {
13485            cx.propagate();
13486        }
13487    }
13488
13489    pub fn move_up_by_lines(
13490        &mut self,
13491        action: &MoveUpByLines,
13492        window: &mut Window,
13493        cx: &mut Context<Self>,
13494    ) {
13495        if self.take_rename(true, window, cx).is_some() {
13496            return;
13497        }
13498
13499        if self.mode.is_single_line() {
13500            cx.propagate();
13501            return;
13502        }
13503
13504        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13505
13506        let text_layout_details = &self.text_layout_details(window);
13507
13508        self.change_selections(Default::default(), window, cx, |s| {
13509            s.move_with(|map, selection| {
13510                if !selection.is_empty() {
13511                    selection.goal = SelectionGoal::None;
13512                }
13513                let (cursor, goal) = movement::up_by_rows(
13514                    map,
13515                    selection.start,
13516                    action.lines,
13517                    selection.goal,
13518                    false,
13519                    text_layout_details,
13520                );
13521                selection.collapse_to(cursor, goal);
13522            });
13523        })
13524    }
13525
13526    pub fn move_down_by_lines(
13527        &mut self,
13528        action: &MoveDownByLines,
13529        window: &mut Window,
13530        cx: &mut Context<Self>,
13531    ) {
13532        if self.take_rename(true, window, cx).is_some() {
13533            return;
13534        }
13535
13536        if self.mode.is_single_line() {
13537            cx.propagate();
13538            return;
13539        }
13540
13541        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13542
13543        let text_layout_details = &self.text_layout_details(window);
13544
13545        self.change_selections(Default::default(), window, cx, |s| {
13546            s.move_with(|map, selection| {
13547                if !selection.is_empty() {
13548                    selection.goal = SelectionGoal::None;
13549                }
13550                let (cursor, goal) = movement::down_by_rows(
13551                    map,
13552                    selection.start,
13553                    action.lines,
13554                    selection.goal,
13555                    false,
13556                    text_layout_details,
13557                );
13558                selection.collapse_to(cursor, goal);
13559            });
13560        })
13561    }
13562
13563    pub fn select_down_by_lines(
13564        &mut self,
13565        action: &SelectDownByLines,
13566        window: &mut Window,
13567        cx: &mut Context<Self>,
13568    ) {
13569        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13570        let text_layout_details = &self.text_layout_details(window);
13571        self.change_selections(Default::default(), window, cx, |s| {
13572            s.move_heads_with(|map, head, goal| {
13573                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13574            })
13575        })
13576    }
13577
13578    pub fn select_up_by_lines(
13579        &mut self,
13580        action: &SelectUpByLines,
13581        window: &mut Window,
13582        cx: &mut Context<Self>,
13583    ) {
13584        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13585        let text_layout_details = &self.text_layout_details(window);
13586        self.change_selections(Default::default(), window, cx, |s| {
13587            s.move_heads_with(|map, head, goal| {
13588                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13589            })
13590        })
13591    }
13592
13593    pub fn select_page_up(
13594        &mut self,
13595        _: &SelectPageUp,
13596        window: &mut Window,
13597        cx: &mut Context<Self>,
13598    ) {
13599        let Some(row_count) = self.visible_row_count() else {
13600            return;
13601        };
13602
13603        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13604
13605        let text_layout_details = &self.text_layout_details(window);
13606
13607        self.change_selections(Default::default(), window, cx, |s| {
13608            s.move_heads_with(|map, head, goal| {
13609                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13610            })
13611        })
13612    }
13613
13614    pub fn move_page_up(
13615        &mut self,
13616        action: &MovePageUp,
13617        window: &mut Window,
13618        cx: &mut Context<Self>,
13619    ) {
13620        if self.take_rename(true, window, cx).is_some() {
13621            return;
13622        }
13623
13624        if self
13625            .context_menu
13626            .borrow_mut()
13627            .as_mut()
13628            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13629            .unwrap_or(false)
13630        {
13631            return;
13632        }
13633
13634        if matches!(self.mode, EditorMode::SingleLine) {
13635            cx.propagate();
13636            return;
13637        }
13638
13639        let Some(row_count) = self.visible_row_count() else {
13640            return;
13641        };
13642
13643        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13644
13645        let effects = if action.center_cursor {
13646            SelectionEffects::scroll(Autoscroll::center())
13647        } else {
13648            SelectionEffects::default()
13649        };
13650
13651        let text_layout_details = &self.text_layout_details(window);
13652
13653        self.change_selections(effects, window, cx, |s| {
13654            s.move_with(|map, selection| {
13655                if !selection.is_empty() {
13656                    selection.goal = SelectionGoal::None;
13657                }
13658                let (cursor, goal) = movement::up_by_rows(
13659                    map,
13660                    selection.end,
13661                    row_count,
13662                    selection.goal,
13663                    false,
13664                    text_layout_details,
13665                );
13666                selection.collapse_to(cursor, goal);
13667            });
13668        });
13669    }
13670
13671    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13672        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13673        let text_layout_details = &self.text_layout_details(window);
13674        self.change_selections(Default::default(), window, cx, |s| {
13675            s.move_heads_with(|map, head, goal| {
13676                movement::up(map, head, goal, false, text_layout_details)
13677            })
13678        })
13679    }
13680
13681    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13682        self.take_rename(true, window, cx);
13683
13684        if self.mode.is_single_line() {
13685            cx.propagate();
13686            return;
13687        }
13688
13689        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13690
13691        let text_layout_details = &self.text_layout_details(window);
13692        let selection_count = self.selections.count();
13693        let first_selection = self.selections.first_anchor();
13694
13695        self.change_selections(Default::default(), window, cx, |s| {
13696            s.move_with(|map, selection| {
13697                if !selection.is_empty() {
13698                    selection.goal = SelectionGoal::None;
13699                }
13700                let (cursor, goal) = movement::down(
13701                    map,
13702                    selection.end,
13703                    selection.goal,
13704                    false,
13705                    text_layout_details,
13706                );
13707                selection.collapse_to(cursor, goal);
13708            });
13709        });
13710
13711        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13712        {
13713            cx.propagate();
13714        }
13715    }
13716
13717    pub fn select_page_down(
13718        &mut self,
13719        _: &SelectPageDown,
13720        window: &mut Window,
13721        cx: &mut Context<Self>,
13722    ) {
13723        let Some(row_count) = self.visible_row_count() else {
13724            return;
13725        };
13726
13727        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13728
13729        let text_layout_details = &self.text_layout_details(window);
13730
13731        self.change_selections(Default::default(), window, cx, |s| {
13732            s.move_heads_with(|map, head, goal| {
13733                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13734            })
13735        })
13736    }
13737
13738    pub fn move_page_down(
13739        &mut self,
13740        action: &MovePageDown,
13741        window: &mut Window,
13742        cx: &mut Context<Self>,
13743    ) {
13744        if self.take_rename(true, window, cx).is_some() {
13745            return;
13746        }
13747
13748        if self
13749            .context_menu
13750            .borrow_mut()
13751            .as_mut()
13752            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13753            .unwrap_or(false)
13754        {
13755            return;
13756        }
13757
13758        if matches!(self.mode, EditorMode::SingleLine) {
13759            cx.propagate();
13760            return;
13761        }
13762
13763        let Some(row_count) = self.visible_row_count() else {
13764            return;
13765        };
13766
13767        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13768
13769        let effects = if action.center_cursor {
13770            SelectionEffects::scroll(Autoscroll::center())
13771        } else {
13772            SelectionEffects::default()
13773        };
13774
13775        let text_layout_details = &self.text_layout_details(window);
13776        self.change_selections(effects, 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_by_rows(
13782                    map,
13783                    selection.end,
13784                    row_count,
13785                    selection.goal,
13786                    false,
13787                    text_layout_details,
13788                );
13789                selection.collapse_to(cursor, goal);
13790            });
13791        });
13792    }
13793
13794    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13795        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13796        let text_layout_details = &self.text_layout_details(window);
13797        self.change_selections(Default::default(), window, cx, |s| {
13798            s.move_heads_with(|map, head, goal| {
13799                movement::down(map, head, goal, false, text_layout_details)
13800            })
13801        });
13802    }
13803
13804    pub fn context_menu_first(
13805        &mut self,
13806        _: &ContextMenuFirst,
13807        window: &mut Window,
13808        cx: &mut Context<Self>,
13809    ) {
13810        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13811            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13812        }
13813    }
13814
13815    pub fn context_menu_prev(
13816        &mut self,
13817        _: &ContextMenuPrevious,
13818        window: &mut Window,
13819        cx: &mut Context<Self>,
13820    ) {
13821        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13822            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13823        }
13824    }
13825
13826    pub fn context_menu_next(
13827        &mut self,
13828        _: &ContextMenuNext,
13829        window: &mut Window,
13830        cx: &mut Context<Self>,
13831    ) {
13832        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13833            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13834        }
13835    }
13836
13837    pub fn context_menu_last(
13838        &mut self,
13839        _: &ContextMenuLast,
13840        window: &mut Window,
13841        cx: &mut Context<Self>,
13842    ) {
13843        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13844            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13845        }
13846    }
13847
13848    pub fn signature_help_prev(
13849        &mut self,
13850        _: &SignatureHelpPrevious,
13851        _: &mut Window,
13852        cx: &mut Context<Self>,
13853    ) {
13854        if let Some(popover) = self.signature_help_state.popover_mut() {
13855            if popover.current_signature == 0 {
13856                popover.current_signature = popover.signatures.len() - 1;
13857            } else {
13858                popover.current_signature -= 1;
13859            }
13860            cx.notify();
13861        }
13862    }
13863
13864    pub fn signature_help_next(
13865        &mut self,
13866        _: &SignatureHelpNext,
13867        _: &mut Window,
13868        cx: &mut Context<Self>,
13869    ) {
13870        if let Some(popover) = self.signature_help_state.popover_mut() {
13871            if popover.current_signature + 1 == popover.signatures.len() {
13872                popover.current_signature = 0;
13873            } else {
13874                popover.current_signature += 1;
13875            }
13876            cx.notify();
13877        }
13878    }
13879
13880    pub fn move_to_previous_word_start(
13881        &mut self,
13882        _: &MoveToPreviousWordStart,
13883        window: &mut Window,
13884        cx: &mut Context<Self>,
13885    ) {
13886        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13887        self.change_selections(Default::default(), window, cx, |s| {
13888            s.move_cursors_with(|map, head, _| {
13889                (
13890                    movement::previous_word_start(map, head),
13891                    SelectionGoal::None,
13892                )
13893            });
13894        })
13895    }
13896
13897    pub fn move_to_previous_subword_start(
13898        &mut self,
13899        _: &MoveToPreviousSubwordStart,
13900        window: &mut Window,
13901        cx: &mut Context<Self>,
13902    ) {
13903        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13904        self.change_selections(Default::default(), window, cx, |s| {
13905            s.move_cursors_with(|map, head, _| {
13906                (
13907                    movement::previous_subword_start(map, head),
13908                    SelectionGoal::None,
13909                )
13910            });
13911        })
13912    }
13913
13914    pub fn select_to_previous_word_start(
13915        &mut self,
13916        _: &SelectToPreviousWordStart,
13917        window: &mut Window,
13918        cx: &mut Context<Self>,
13919    ) {
13920        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13921        self.change_selections(Default::default(), window, cx, |s| {
13922            s.move_heads_with(|map, head, _| {
13923                (
13924                    movement::previous_word_start(map, head),
13925                    SelectionGoal::None,
13926                )
13927            });
13928        })
13929    }
13930
13931    pub fn select_to_previous_subword_start(
13932        &mut self,
13933        _: &SelectToPreviousSubwordStart,
13934        window: &mut Window,
13935        cx: &mut Context<Self>,
13936    ) {
13937        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13938        self.change_selections(Default::default(), window, cx, |s| {
13939            s.move_heads_with(|map, head, _| {
13940                (
13941                    movement::previous_subword_start(map, head),
13942                    SelectionGoal::None,
13943                )
13944            });
13945        })
13946    }
13947
13948    pub fn delete_to_previous_word_start(
13949        &mut self,
13950        action: &DeleteToPreviousWordStart,
13951        window: &mut Window,
13952        cx: &mut Context<Self>,
13953    ) {
13954        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13955        self.transact(window, cx, |this, window, cx| {
13956            this.select_autoclose_pair(window, cx);
13957            this.change_selections(Default::default(), window, cx, |s| {
13958                s.move_with(|map, selection| {
13959                    if selection.is_empty() {
13960                        let mut cursor = if action.ignore_newlines {
13961                            movement::previous_word_start(map, selection.head())
13962                        } else {
13963                            movement::previous_word_start_or_newline(map, selection.head())
13964                        };
13965                        cursor = movement::adjust_greedy_deletion(
13966                            map,
13967                            selection.head(),
13968                            cursor,
13969                            action.ignore_brackets,
13970                        );
13971                        selection.set_head(cursor, SelectionGoal::None);
13972                    }
13973                });
13974            });
13975            this.insert("", window, cx);
13976        });
13977    }
13978
13979    pub fn delete_to_previous_subword_start(
13980        &mut self,
13981        _: &DeleteToPreviousSubwordStart,
13982        window: &mut Window,
13983        cx: &mut Context<Self>,
13984    ) {
13985        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13986        self.transact(window, cx, |this, window, cx| {
13987            this.select_autoclose_pair(window, cx);
13988            this.change_selections(Default::default(), window, cx, |s| {
13989                s.move_with(|map, selection| {
13990                    if selection.is_empty() {
13991                        let mut cursor = movement::previous_subword_start(map, selection.head());
13992                        cursor =
13993                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13994                        selection.set_head(cursor, SelectionGoal::None);
13995                    }
13996                });
13997            });
13998            this.insert("", window, cx);
13999        });
14000    }
14001
14002    pub fn move_to_next_word_end(
14003        &mut self,
14004        _: &MoveToNextWordEnd,
14005        window: &mut Window,
14006        cx: &mut Context<Self>,
14007    ) {
14008        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14009        self.change_selections(Default::default(), window, cx, |s| {
14010            s.move_cursors_with(|map, head, _| {
14011                (movement::next_word_end(map, head), SelectionGoal::None)
14012            });
14013        })
14014    }
14015
14016    pub fn move_to_next_subword_end(
14017        &mut self,
14018        _: &MoveToNextSubwordEnd,
14019        window: &mut Window,
14020        cx: &mut Context<Self>,
14021    ) {
14022        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14023        self.change_selections(Default::default(), window, cx, |s| {
14024            s.move_cursors_with(|map, head, _| {
14025                (movement::next_subword_end(map, head), SelectionGoal::None)
14026            });
14027        })
14028    }
14029
14030    pub fn select_to_next_word_end(
14031        &mut self,
14032        _: &SelectToNextWordEnd,
14033        window: &mut Window,
14034        cx: &mut Context<Self>,
14035    ) {
14036        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14037        self.change_selections(Default::default(), window, cx, |s| {
14038            s.move_heads_with(|map, head, _| {
14039                (movement::next_word_end(map, head), SelectionGoal::None)
14040            });
14041        })
14042    }
14043
14044    pub fn select_to_next_subword_end(
14045        &mut self,
14046        _: &SelectToNextSubwordEnd,
14047        window: &mut Window,
14048        cx: &mut Context<Self>,
14049    ) {
14050        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14051        self.change_selections(Default::default(), window, cx, |s| {
14052            s.move_heads_with(|map, head, _| {
14053                (movement::next_subword_end(map, head), SelectionGoal::None)
14054            });
14055        })
14056    }
14057
14058    pub fn delete_to_next_word_end(
14059        &mut self,
14060        action: &DeleteToNextWordEnd,
14061        window: &mut Window,
14062        cx: &mut Context<Self>,
14063    ) {
14064        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14065        self.transact(window, cx, |this, window, cx| {
14066            this.change_selections(Default::default(), window, cx, |s| {
14067                s.move_with(|map, selection| {
14068                    if selection.is_empty() {
14069                        let mut cursor = if action.ignore_newlines {
14070                            movement::next_word_end(map, selection.head())
14071                        } else {
14072                            movement::next_word_end_or_newline(map, selection.head())
14073                        };
14074                        cursor = movement::adjust_greedy_deletion(
14075                            map,
14076                            selection.head(),
14077                            cursor,
14078                            action.ignore_brackets,
14079                        );
14080                        selection.set_head(cursor, SelectionGoal::None);
14081                    }
14082                });
14083            });
14084            this.insert("", window, cx);
14085        });
14086    }
14087
14088    pub fn delete_to_next_subword_end(
14089        &mut self,
14090        _: &DeleteToNextSubwordEnd,
14091        window: &mut Window,
14092        cx: &mut Context<Self>,
14093    ) {
14094        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14095        self.transact(window, cx, |this, window, cx| {
14096            this.change_selections(Default::default(), window, cx, |s| {
14097                s.move_with(|map, selection| {
14098                    if selection.is_empty() {
14099                        let mut cursor = movement::next_subword_end(map, selection.head());
14100                        cursor =
14101                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14102                        selection.set_head(cursor, SelectionGoal::None);
14103                    }
14104                });
14105            });
14106            this.insert("", window, cx);
14107        });
14108    }
14109
14110    pub fn move_to_beginning_of_line(
14111        &mut self,
14112        action: &MoveToBeginningOfLine,
14113        window: &mut Window,
14114        cx: &mut Context<Self>,
14115    ) {
14116        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14117        self.change_selections(Default::default(), window, cx, |s| {
14118            s.move_cursors_with(|map, head, _| {
14119                (
14120                    movement::indented_line_beginning(
14121                        map,
14122                        head,
14123                        action.stop_at_soft_wraps,
14124                        action.stop_at_indent,
14125                    ),
14126                    SelectionGoal::None,
14127                )
14128            });
14129        })
14130    }
14131
14132    pub fn select_to_beginning_of_line(
14133        &mut self,
14134        action: &SelectToBeginningOfLine,
14135        window: &mut Window,
14136        cx: &mut Context<Self>,
14137    ) {
14138        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14139        self.change_selections(Default::default(), window, cx, |s| {
14140            s.move_heads_with(|map, head, _| {
14141                (
14142                    movement::indented_line_beginning(
14143                        map,
14144                        head,
14145                        action.stop_at_soft_wraps,
14146                        action.stop_at_indent,
14147                    ),
14148                    SelectionGoal::None,
14149                )
14150            });
14151        });
14152    }
14153
14154    pub fn delete_to_beginning_of_line(
14155        &mut self,
14156        action: &DeleteToBeginningOfLine,
14157        window: &mut Window,
14158        cx: &mut Context<Self>,
14159    ) {
14160        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14161        self.transact(window, cx, |this, window, cx| {
14162            this.change_selections(Default::default(), window, cx, |s| {
14163                s.move_with(|_, selection| {
14164                    selection.reversed = true;
14165                });
14166            });
14167
14168            this.select_to_beginning_of_line(
14169                &SelectToBeginningOfLine {
14170                    stop_at_soft_wraps: false,
14171                    stop_at_indent: action.stop_at_indent,
14172                },
14173                window,
14174                cx,
14175            );
14176            this.backspace(&Backspace, window, cx);
14177        });
14178    }
14179
14180    pub fn move_to_end_of_line(
14181        &mut self,
14182        action: &MoveToEndOfLine,
14183        window: &mut Window,
14184        cx: &mut Context<Self>,
14185    ) {
14186        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14187        self.change_selections(Default::default(), window, cx, |s| {
14188            s.move_cursors_with(|map, head, _| {
14189                (
14190                    movement::line_end(map, head, action.stop_at_soft_wraps),
14191                    SelectionGoal::None,
14192                )
14193            });
14194        })
14195    }
14196
14197    pub fn select_to_end_of_line(
14198        &mut self,
14199        action: &SelectToEndOfLine,
14200        window: &mut Window,
14201        cx: &mut Context<Self>,
14202    ) {
14203        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14204        self.change_selections(Default::default(), window, cx, |s| {
14205            s.move_heads_with(|map, head, _| {
14206                (
14207                    movement::line_end(map, head, action.stop_at_soft_wraps),
14208                    SelectionGoal::None,
14209                )
14210            });
14211        })
14212    }
14213
14214    pub fn delete_to_end_of_line(
14215        &mut self,
14216        _: &DeleteToEndOfLine,
14217        window: &mut Window,
14218        cx: &mut Context<Self>,
14219    ) {
14220        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14221        self.transact(window, cx, |this, window, cx| {
14222            this.select_to_end_of_line(
14223                &SelectToEndOfLine {
14224                    stop_at_soft_wraps: false,
14225                },
14226                window,
14227                cx,
14228            );
14229            this.delete(&Delete, window, cx);
14230        });
14231    }
14232
14233    pub fn cut_to_end_of_line(
14234        &mut self,
14235        action: &CutToEndOfLine,
14236        window: &mut Window,
14237        cx: &mut Context<Self>,
14238    ) {
14239        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14240        self.transact(window, cx, |this, window, cx| {
14241            this.select_to_end_of_line(
14242                &SelectToEndOfLine {
14243                    stop_at_soft_wraps: false,
14244                },
14245                window,
14246                cx,
14247            );
14248            if !action.stop_at_newlines {
14249                this.change_selections(Default::default(), window, cx, |s| {
14250                    s.move_with(|_, sel| {
14251                        if sel.is_empty() {
14252                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14253                        }
14254                    });
14255                });
14256            }
14257            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14258            let item = this.cut_common(false, window, cx);
14259            cx.write_to_clipboard(item);
14260        });
14261    }
14262
14263    pub fn move_to_start_of_paragraph(
14264        &mut self,
14265        _: &MoveToStartOfParagraph,
14266        window: &mut Window,
14267        cx: &mut Context<Self>,
14268    ) {
14269        if matches!(self.mode, EditorMode::SingleLine) {
14270            cx.propagate();
14271            return;
14272        }
14273        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14274        self.change_selections(Default::default(), window, cx, |s| {
14275            s.move_with(|map, selection| {
14276                selection.collapse_to(
14277                    movement::start_of_paragraph(map, selection.head(), 1),
14278                    SelectionGoal::None,
14279                )
14280            });
14281        })
14282    }
14283
14284    pub fn move_to_end_of_paragraph(
14285        &mut self,
14286        _: &MoveToEndOfParagraph,
14287        window: &mut Window,
14288        cx: &mut Context<Self>,
14289    ) {
14290        if matches!(self.mode, EditorMode::SingleLine) {
14291            cx.propagate();
14292            return;
14293        }
14294        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14295        self.change_selections(Default::default(), window, cx, |s| {
14296            s.move_with(|map, selection| {
14297                selection.collapse_to(
14298                    movement::end_of_paragraph(map, selection.head(), 1),
14299                    SelectionGoal::None,
14300                )
14301            });
14302        })
14303    }
14304
14305    pub fn select_to_start_of_paragraph(
14306        &mut self,
14307        _: &SelectToStartOfParagraph,
14308        window: &mut Window,
14309        cx: &mut Context<Self>,
14310    ) {
14311        if matches!(self.mode, EditorMode::SingleLine) {
14312            cx.propagate();
14313            return;
14314        }
14315        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14316        self.change_selections(Default::default(), window, cx, |s| {
14317            s.move_heads_with(|map, head, _| {
14318                (
14319                    movement::start_of_paragraph(map, head, 1),
14320                    SelectionGoal::None,
14321                )
14322            });
14323        })
14324    }
14325
14326    pub fn select_to_end_of_paragraph(
14327        &mut self,
14328        _: &SelectToEndOfParagraph,
14329        window: &mut Window,
14330        cx: &mut Context<Self>,
14331    ) {
14332        if matches!(self.mode, EditorMode::SingleLine) {
14333            cx.propagate();
14334            return;
14335        }
14336        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14337        self.change_selections(Default::default(), window, cx, |s| {
14338            s.move_heads_with(|map, head, _| {
14339                (
14340                    movement::end_of_paragraph(map, head, 1),
14341                    SelectionGoal::None,
14342                )
14343            });
14344        })
14345    }
14346
14347    pub fn move_to_start_of_excerpt(
14348        &mut self,
14349        _: &MoveToStartOfExcerpt,
14350        window: &mut Window,
14351        cx: &mut Context<Self>,
14352    ) {
14353        if matches!(self.mode, EditorMode::SingleLine) {
14354            cx.propagate();
14355            return;
14356        }
14357        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14358        self.change_selections(Default::default(), window, cx, |s| {
14359            s.move_with(|map, selection| {
14360                selection.collapse_to(
14361                    movement::start_of_excerpt(
14362                        map,
14363                        selection.head(),
14364                        workspace::searchable::Direction::Prev,
14365                    ),
14366                    SelectionGoal::None,
14367                )
14368            });
14369        })
14370    }
14371
14372    pub fn move_to_start_of_next_excerpt(
14373        &mut self,
14374        _: &MoveToStartOfNextExcerpt,
14375        window: &mut Window,
14376        cx: &mut Context<Self>,
14377    ) {
14378        if matches!(self.mode, EditorMode::SingleLine) {
14379            cx.propagate();
14380            return;
14381        }
14382
14383        self.change_selections(Default::default(), window, cx, |s| {
14384            s.move_with(|map, selection| {
14385                selection.collapse_to(
14386                    movement::start_of_excerpt(
14387                        map,
14388                        selection.head(),
14389                        workspace::searchable::Direction::Next,
14390                    ),
14391                    SelectionGoal::None,
14392                )
14393            });
14394        })
14395    }
14396
14397    pub fn move_to_end_of_excerpt(
14398        &mut self,
14399        _: &MoveToEndOfExcerpt,
14400        window: &mut Window,
14401        cx: &mut Context<Self>,
14402    ) {
14403        if matches!(self.mode, EditorMode::SingleLine) {
14404            cx.propagate();
14405            return;
14406        }
14407        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14408        self.change_selections(Default::default(), window, cx, |s| {
14409            s.move_with(|map, selection| {
14410                selection.collapse_to(
14411                    movement::end_of_excerpt(
14412                        map,
14413                        selection.head(),
14414                        workspace::searchable::Direction::Next,
14415                    ),
14416                    SelectionGoal::None,
14417                )
14418            });
14419        })
14420    }
14421
14422    pub fn move_to_end_of_previous_excerpt(
14423        &mut self,
14424        _: &MoveToEndOfPreviousExcerpt,
14425        window: &mut Window,
14426        cx: &mut Context<Self>,
14427    ) {
14428        if matches!(self.mode, EditorMode::SingleLine) {
14429            cx.propagate();
14430            return;
14431        }
14432        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14433        self.change_selections(Default::default(), window, cx, |s| {
14434            s.move_with(|map, selection| {
14435                selection.collapse_to(
14436                    movement::end_of_excerpt(
14437                        map,
14438                        selection.head(),
14439                        workspace::searchable::Direction::Prev,
14440                    ),
14441                    SelectionGoal::None,
14442                )
14443            });
14444        })
14445    }
14446
14447    pub fn select_to_start_of_excerpt(
14448        &mut self,
14449        _: &SelectToStartOfExcerpt,
14450        window: &mut Window,
14451        cx: &mut Context<Self>,
14452    ) {
14453        if matches!(self.mode, EditorMode::SingleLine) {
14454            cx.propagate();
14455            return;
14456        }
14457        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14458        self.change_selections(Default::default(), window, cx, |s| {
14459            s.move_heads_with(|map, head, _| {
14460                (
14461                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14462                    SelectionGoal::None,
14463                )
14464            });
14465        })
14466    }
14467
14468    pub fn select_to_start_of_next_excerpt(
14469        &mut self,
14470        _: &SelectToStartOfNextExcerpt,
14471        window: &mut Window,
14472        cx: &mut Context<Self>,
14473    ) {
14474        if matches!(self.mode, EditorMode::SingleLine) {
14475            cx.propagate();
14476            return;
14477        }
14478        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14479        self.change_selections(Default::default(), window, cx, |s| {
14480            s.move_heads_with(|map, head, _| {
14481                (
14482                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14483                    SelectionGoal::None,
14484                )
14485            });
14486        })
14487    }
14488
14489    pub fn select_to_end_of_excerpt(
14490        &mut self,
14491        _: &SelectToEndOfExcerpt,
14492        window: &mut Window,
14493        cx: &mut Context<Self>,
14494    ) {
14495        if matches!(self.mode, EditorMode::SingleLine) {
14496            cx.propagate();
14497            return;
14498        }
14499        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14500        self.change_selections(Default::default(), window, cx, |s| {
14501            s.move_heads_with(|map, head, _| {
14502                (
14503                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14504                    SelectionGoal::None,
14505                )
14506            });
14507        })
14508    }
14509
14510    pub fn select_to_end_of_previous_excerpt(
14511        &mut self,
14512        _: &SelectToEndOfPreviousExcerpt,
14513        window: &mut Window,
14514        cx: &mut Context<Self>,
14515    ) {
14516        if matches!(self.mode, EditorMode::SingleLine) {
14517            cx.propagate();
14518            return;
14519        }
14520        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14521        self.change_selections(Default::default(), window, cx, |s| {
14522            s.move_heads_with(|map, head, _| {
14523                (
14524                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14525                    SelectionGoal::None,
14526                )
14527            });
14528        })
14529    }
14530
14531    pub fn move_to_beginning(
14532        &mut self,
14533        _: &MoveToBeginning,
14534        window: &mut Window,
14535        cx: &mut Context<Self>,
14536    ) {
14537        if matches!(self.mode, EditorMode::SingleLine) {
14538            cx.propagate();
14539            return;
14540        }
14541        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14542        self.change_selections(Default::default(), window, cx, |s| {
14543            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14544        });
14545    }
14546
14547    pub fn select_to_beginning(
14548        &mut self,
14549        _: &SelectToBeginning,
14550        window: &mut Window,
14551        cx: &mut Context<Self>,
14552    ) {
14553        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14554        selection.set_head(Point::zero(), SelectionGoal::None);
14555        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14556        self.change_selections(Default::default(), window, cx, |s| {
14557            s.select(vec![selection]);
14558        });
14559    }
14560
14561    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14562        if matches!(self.mode, EditorMode::SingleLine) {
14563            cx.propagate();
14564            return;
14565        }
14566        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14567        let cursor = self.buffer.read(cx).read(cx).len();
14568        self.change_selections(Default::default(), window, cx, |s| {
14569            s.select_ranges(vec![cursor..cursor])
14570        });
14571    }
14572
14573    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14574        self.nav_history = nav_history;
14575    }
14576
14577    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14578        self.nav_history.as_ref()
14579    }
14580
14581    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14582        self.push_to_nav_history(
14583            self.selections.newest_anchor().head(),
14584            None,
14585            false,
14586            true,
14587            cx,
14588        );
14589    }
14590
14591    fn push_to_nav_history(
14592        &mut self,
14593        cursor_anchor: Anchor,
14594        new_position: Option<Point>,
14595        is_deactivate: bool,
14596        always: bool,
14597        cx: &mut Context<Self>,
14598    ) {
14599        if let Some(nav_history) = self.nav_history.as_mut() {
14600            let buffer = self.buffer.read(cx).read(cx);
14601            let cursor_position = cursor_anchor.to_point(&buffer);
14602            let scroll_state = self.scroll_manager.anchor();
14603            let scroll_top_row = scroll_state.top_row(&buffer);
14604            drop(buffer);
14605
14606            if let Some(new_position) = new_position {
14607                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14608                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14609                    return;
14610                }
14611            }
14612
14613            nav_history.push(
14614                Some(NavigationData {
14615                    cursor_anchor,
14616                    cursor_position,
14617                    scroll_anchor: scroll_state,
14618                    scroll_top_row,
14619                }),
14620                cx,
14621            );
14622            cx.emit(EditorEvent::PushedToNavHistory {
14623                anchor: cursor_anchor,
14624                is_deactivate,
14625            })
14626        }
14627    }
14628
14629    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14630        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14631        let buffer = self.buffer.read(cx).snapshot(cx);
14632        let mut selection = self
14633            .selections
14634            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14635        selection.set_head(buffer.len(), SelectionGoal::None);
14636        self.change_selections(Default::default(), window, cx, |s| {
14637            s.select(vec![selection]);
14638        });
14639    }
14640
14641    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14642        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14643        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14644            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14645        });
14646    }
14647
14648    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14649        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14650        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14651        let mut selections = self.selections.all::<Point>(&display_map);
14652        let max_point = display_map.buffer_snapshot().max_point();
14653        for selection in &mut selections {
14654            let rows = selection.spanned_rows(true, &display_map);
14655            selection.start = Point::new(rows.start.0, 0);
14656            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14657            selection.reversed = false;
14658        }
14659        self.change_selections(Default::default(), window, cx, |s| {
14660            s.select(selections);
14661        });
14662    }
14663
14664    pub fn split_selection_into_lines(
14665        &mut self,
14666        action: &SplitSelectionIntoLines,
14667        window: &mut Window,
14668        cx: &mut Context<Self>,
14669    ) {
14670        let selections = self
14671            .selections
14672            .all::<Point>(&self.display_snapshot(cx))
14673            .into_iter()
14674            .map(|selection| selection.start..selection.end)
14675            .collect::<Vec<_>>();
14676        self.unfold_ranges(&selections, true, true, cx);
14677
14678        let mut new_selection_ranges = Vec::new();
14679        {
14680            let buffer = self.buffer.read(cx).read(cx);
14681            for selection in selections {
14682                for row in selection.start.row..selection.end.row {
14683                    let line_start = Point::new(row, 0);
14684                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14685
14686                    if action.keep_selections {
14687                        // Keep the selection range for each line
14688                        let selection_start = if row == selection.start.row {
14689                            selection.start
14690                        } else {
14691                            line_start
14692                        };
14693                        new_selection_ranges.push(selection_start..line_end);
14694                    } else {
14695                        // Collapse to cursor at end of line
14696                        new_selection_ranges.push(line_end..line_end);
14697                    }
14698                }
14699
14700                let is_multiline_selection = selection.start.row != selection.end.row;
14701                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14702                // so this action feels more ergonomic when paired with other selection operations
14703                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14704                if !should_skip_last {
14705                    if action.keep_selections {
14706                        if is_multiline_selection {
14707                            let line_start = Point::new(selection.end.row, 0);
14708                            new_selection_ranges.push(line_start..selection.end);
14709                        } else {
14710                            new_selection_ranges.push(selection.start..selection.end);
14711                        }
14712                    } else {
14713                        new_selection_ranges.push(selection.end..selection.end);
14714                    }
14715                }
14716            }
14717        }
14718        self.change_selections(Default::default(), window, cx, |s| {
14719            s.select_ranges(new_selection_ranges);
14720        });
14721    }
14722
14723    pub fn add_selection_above(
14724        &mut self,
14725        action: &AddSelectionAbove,
14726        window: &mut Window,
14727        cx: &mut Context<Self>,
14728    ) {
14729        self.add_selection(true, action.skip_soft_wrap, window, cx);
14730    }
14731
14732    pub fn add_selection_below(
14733        &mut self,
14734        action: &AddSelectionBelow,
14735        window: &mut Window,
14736        cx: &mut Context<Self>,
14737    ) {
14738        self.add_selection(false, action.skip_soft_wrap, window, cx);
14739    }
14740
14741    fn add_selection(
14742        &mut self,
14743        above: bool,
14744        skip_soft_wrap: bool,
14745        window: &mut Window,
14746        cx: &mut Context<Self>,
14747    ) {
14748        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14749
14750        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14751        let all_selections = self.selections.all::<Point>(&display_map);
14752        let text_layout_details = self.text_layout_details(window);
14753
14754        let (mut columnar_selections, new_selections_to_columnarize) = {
14755            if let Some(state) = self.add_selections_state.as_ref() {
14756                let columnar_selection_ids: HashSet<_> = state
14757                    .groups
14758                    .iter()
14759                    .flat_map(|group| group.stack.iter())
14760                    .copied()
14761                    .collect();
14762
14763                all_selections
14764                    .into_iter()
14765                    .partition(|s| columnar_selection_ids.contains(&s.id))
14766            } else {
14767                (Vec::new(), all_selections)
14768            }
14769        };
14770
14771        let mut state = self
14772            .add_selections_state
14773            .take()
14774            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14775
14776        for selection in new_selections_to_columnarize {
14777            let range = selection.display_range(&display_map).sorted();
14778            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14779            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14780            let positions = start_x.min(end_x)..start_x.max(end_x);
14781            let mut stack = Vec::new();
14782            for row in range.start.row().0..=range.end.row().0 {
14783                if let Some(selection) = self.selections.build_columnar_selection(
14784                    &display_map,
14785                    DisplayRow(row),
14786                    &positions,
14787                    selection.reversed,
14788                    &text_layout_details,
14789                ) {
14790                    stack.push(selection.id);
14791                    columnar_selections.push(selection);
14792                }
14793            }
14794            if !stack.is_empty() {
14795                if above {
14796                    stack.reverse();
14797                }
14798                state.groups.push(AddSelectionsGroup { above, stack });
14799            }
14800        }
14801
14802        let mut final_selections = Vec::new();
14803        let end_row = if above {
14804            DisplayRow(0)
14805        } else {
14806            display_map.max_point().row()
14807        };
14808
14809        let mut last_added_item_per_group = HashMap::default();
14810        for group in state.groups.iter_mut() {
14811            if let Some(last_id) = group.stack.last() {
14812                last_added_item_per_group.insert(*last_id, group);
14813            }
14814        }
14815
14816        for selection in columnar_selections {
14817            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14818                if above == group.above {
14819                    let range = selection.display_range(&display_map).sorted();
14820                    debug_assert_eq!(range.start.row(), range.end.row());
14821                    let mut row = range.start.row();
14822                    let positions =
14823                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14824                            Pixels::from(start)..Pixels::from(end)
14825                        } else {
14826                            let start_x =
14827                                display_map.x_for_display_point(range.start, &text_layout_details);
14828                            let end_x =
14829                                display_map.x_for_display_point(range.end, &text_layout_details);
14830                            start_x.min(end_x)..start_x.max(end_x)
14831                        };
14832
14833                    let mut maybe_new_selection = None;
14834                    let direction = if above { -1 } else { 1 };
14835
14836                    while row != end_row {
14837                        if skip_soft_wrap {
14838                            row = display_map
14839                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14840                                .row();
14841                        } else if above {
14842                            row.0 -= 1;
14843                        } else {
14844                            row.0 += 1;
14845                        }
14846
14847                        if let Some(new_selection) = self.selections.build_columnar_selection(
14848                            &display_map,
14849                            row,
14850                            &positions,
14851                            selection.reversed,
14852                            &text_layout_details,
14853                        ) {
14854                            maybe_new_selection = Some(new_selection);
14855                            break;
14856                        }
14857                    }
14858
14859                    if let Some(new_selection) = maybe_new_selection {
14860                        group.stack.push(new_selection.id);
14861                        if above {
14862                            final_selections.push(new_selection);
14863                            final_selections.push(selection);
14864                        } else {
14865                            final_selections.push(selection);
14866                            final_selections.push(new_selection);
14867                        }
14868                    } else {
14869                        final_selections.push(selection);
14870                    }
14871                } else {
14872                    group.stack.pop();
14873                }
14874            } else {
14875                final_selections.push(selection);
14876            }
14877        }
14878
14879        self.change_selections(Default::default(), window, cx, |s| {
14880            s.select(final_selections);
14881        });
14882
14883        let final_selection_ids: HashSet<_> = self
14884            .selections
14885            .all::<Point>(&display_map)
14886            .iter()
14887            .map(|s| s.id)
14888            .collect();
14889        state.groups.retain_mut(|group| {
14890            // selections might get merged above so we remove invalid items from stacks
14891            group.stack.retain(|id| final_selection_ids.contains(id));
14892
14893            // single selection in stack can be treated as initial state
14894            group.stack.len() > 1
14895        });
14896
14897        if !state.groups.is_empty() {
14898            self.add_selections_state = Some(state);
14899        }
14900    }
14901
14902    pub fn insert_snippet_at_selections(
14903        &mut self,
14904        action: &InsertSnippet,
14905        window: &mut Window,
14906        cx: &mut Context<Self>,
14907    ) {
14908        self.try_insert_snippet_at_selections(action, window, cx)
14909            .log_err();
14910    }
14911
14912    fn try_insert_snippet_at_selections(
14913        &mut self,
14914        action: &InsertSnippet,
14915        window: &mut Window,
14916        cx: &mut Context<Self>,
14917    ) -> Result<()> {
14918        let insertion_ranges = self
14919            .selections
14920            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
14921            .into_iter()
14922            .map(|selection| selection.range())
14923            .collect_vec();
14924
14925        let snippet = if let Some(snippet_body) = &action.snippet {
14926            if action.language.is_none() && action.name.is_none() {
14927                Snippet::parse(snippet_body)?
14928            } else {
14929                bail!("`snippet` is mutually exclusive with `language` and `name`")
14930            }
14931        } else if let Some(name) = &action.name {
14932            let project = self.project().context("no project")?;
14933            let snippet_store = project.read(cx).snippets().read(cx);
14934            let snippet = snippet_store
14935                .snippets_for(action.language.clone(), cx)
14936                .into_iter()
14937                .find(|snippet| snippet.name == *name)
14938                .context("snippet not found")?;
14939            Snippet::parse(&snippet.body)?
14940        } else {
14941            // todo(andrew): open modal to select snippet
14942            bail!("`name` or `snippet` is required")
14943        };
14944
14945        self.insert_snippet(&insertion_ranges, snippet, window, cx)
14946    }
14947
14948    fn select_match_ranges(
14949        &mut self,
14950        range: Range<MultiBufferOffset>,
14951        reversed: bool,
14952        replace_newest: bool,
14953        auto_scroll: Option<Autoscroll>,
14954        window: &mut Window,
14955        cx: &mut Context<Editor>,
14956    ) {
14957        self.unfold_ranges(
14958            std::slice::from_ref(&range),
14959            false,
14960            auto_scroll.is_some(),
14961            cx,
14962        );
14963        let effects = if let Some(scroll) = auto_scroll {
14964            SelectionEffects::scroll(scroll)
14965        } else {
14966            SelectionEffects::no_scroll()
14967        };
14968        self.change_selections(effects, window, cx, |s| {
14969            if replace_newest {
14970                s.delete(s.newest_anchor().id);
14971            }
14972            if reversed {
14973                s.insert_range(range.end..range.start);
14974            } else {
14975                s.insert_range(range);
14976            }
14977        });
14978    }
14979
14980    pub fn select_next_match_internal(
14981        &mut self,
14982        display_map: &DisplaySnapshot,
14983        replace_newest: bool,
14984        autoscroll: Option<Autoscroll>,
14985        window: &mut Window,
14986        cx: &mut Context<Self>,
14987    ) -> Result<()> {
14988        let buffer = display_map.buffer_snapshot();
14989        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14990        if let Some(mut select_next_state) = self.select_next_state.take() {
14991            let query = &select_next_state.query;
14992            if !select_next_state.done {
14993                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14994                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14995                let mut next_selected_range = None;
14996
14997                let bytes_after_last_selection =
14998                    buffer.bytes_in_range(last_selection.end..buffer.len());
14999                let bytes_before_first_selection =
15000                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15001                let query_matches = query
15002                    .stream_find_iter(bytes_after_last_selection)
15003                    .map(|result| (last_selection.end, result))
15004                    .chain(
15005                        query
15006                            .stream_find_iter(bytes_before_first_selection)
15007                            .map(|result| (MultiBufferOffset(0), result)),
15008                    );
15009
15010                for (start_offset, query_match) in query_matches {
15011                    let query_match = query_match.unwrap(); // can only fail due to I/O
15012                    let offset_range =
15013                        start_offset + query_match.start()..start_offset + query_match.end();
15014
15015                    if !select_next_state.wordwise
15016                        || (!buffer.is_inside_word(offset_range.start, None)
15017                            && !buffer.is_inside_word(offset_range.end, None))
15018                    {
15019                        let idx = selections
15020                            .partition_point(|selection| selection.end <= offset_range.start);
15021                        let overlaps = selections
15022                            .get(idx)
15023                            .map_or(false, |selection| selection.start < offset_range.end);
15024
15025                        if !overlaps {
15026                            next_selected_range = Some(offset_range);
15027                            break;
15028                        }
15029                    }
15030                }
15031
15032                if let Some(next_selected_range) = next_selected_range {
15033                    self.select_match_ranges(
15034                        next_selected_range,
15035                        last_selection.reversed,
15036                        replace_newest,
15037                        autoscroll,
15038                        window,
15039                        cx,
15040                    );
15041                } else {
15042                    select_next_state.done = true;
15043                }
15044            }
15045
15046            self.select_next_state = Some(select_next_state);
15047        } else {
15048            let mut only_carets = true;
15049            let mut same_text_selected = true;
15050            let mut selected_text = None;
15051
15052            let mut selections_iter = selections.iter().peekable();
15053            while let Some(selection) = selections_iter.next() {
15054                if selection.start != selection.end {
15055                    only_carets = false;
15056                }
15057
15058                if same_text_selected {
15059                    if selected_text.is_none() {
15060                        selected_text =
15061                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15062                    }
15063
15064                    if let Some(next_selection) = selections_iter.peek() {
15065                        if next_selection.len() == selection.len() {
15066                            let next_selected_text = buffer
15067                                .text_for_range(next_selection.range())
15068                                .collect::<String>();
15069                            if Some(next_selected_text) != selected_text {
15070                                same_text_selected = false;
15071                                selected_text = None;
15072                            }
15073                        } else {
15074                            same_text_selected = false;
15075                            selected_text = None;
15076                        }
15077                    }
15078                }
15079            }
15080
15081            if only_carets {
15082                for selection in &mut selections {
15083                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15084                    selection.start = word_range.start;
15085                    selection.end = word_range.end;
15086                    selection.goal = SelectionGoal::None;
15087                    selection.reversed = false;
15088                    self.select_match_ranges(
15089                        selection.start..selection.end,
15090                        selection.reversed,
15091                        replace_newest,
15092                        autoscroll,
15093                        window,
15094                        cx,
15095                    );
15096                }
15097
15098                if selections.len() == 1 {
15099                    let selection = selections
15100                        .last()
15101                        .expect("ensured that there's only one selection");
15102                    let query = buffer
15103                        .text_for_range(selection.start..selection.end)
15104                        .collect::<String>();
15105                    let is_empty = query.is_empty();
15106                    let select_state = SelectNextState {
15107                        query: self.build_query(&[query], cx)?,
15108                        wordwise: true,
15109                        done: is_empty,
15110                    };
15111                    self.select_next_state = Some(select_state);
15112                } else {
15113                    self.select_next_state = None;
15114                }
15115            } else if let Some(selected_text) = selected_text {
15116                self.select_next_state = Some(SelectNextState {
15117                    query: self.build_query(&[selected_text], cx)?,
15118                    wordwise: false,
15119                    done: false,
15120                });
15121                self.select_next_match_internal(
15122                    display_map,
15123                    replace_newest,
15124                    autoscroll,
15125                    window,
15126                    cx,
15127                )?;
15128            }
15129        }
15130        Ok(())
15131    }
15132
15133    pub fn select_all_matches(
15134        &mut self,
15135        _action: &SelectAllMatches,
15136        window: &mut Window,
15137        cx: &mut Context<Self>,
15138    ) -> Result<()> {
15139        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15140
15141        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15142
15143        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15144        let Some(select_next_state) = self.select_next_state.as_mut() else {
15145            return Ok(());
15146        };
15147        if select_next_state.done {
15148            return Ok(());
15149        }
15150
15151        let mut new_selections = Vec::new();
15152
15153        let reversed = self
15154            .selections
15155            .oldest::<MultiBufferOffset>(&display_map)
15156            .reversed;
15157        let buffer = display_map.buffer_snapshot();
15158        let query_matches = select_next_state
15159            .query
15160            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15161
15162        for query_match in query_matches.into_iter() {
15163            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15164            let offset_range = if reversed {
15165                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15166            } else {
15167                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15168            };
15169
15170            if !select_next_state.wordwise
15171                || (!buffer.is_inside_word(offset_range.start, None)
15172                    && !buffer.is_inside_word(offset_range.end, None))
15173            {
15174                new_selections.push(offset_range.start..offset_range.end);
15175            }
15176        }
15177
15178        select_next_state.done = true;
15179
15180        if new_selections.is_empty() {
15181            log::error!("bug: new_selections is empty in select_all_matches");
15182            return Ok(());
15183        }
15184
15185        self.unfold_ranges(&new_selections.clone(), false, false, cx);
15186        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15187            selections.select_ranges(new_selections)
15188        });
15189
15190        Ok(())
15191    }
15192
15193    pub fn select_next(
15194        &mut self,
15195        action: &SelectNext,
15196        window: &mut Window,
15197        cx: &mut Context<Self>,
15198    ) -> Result<()> {
15199        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15200        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15201        self.select_next_match_internal(
15202            &display_map,
15203            action.replace_newest,
15204            Some(Autoscroll::newest()),
15205            window,
15206            cx,
15207        )?;
15208        Ok(())
15209    }
15210
15211    pub fn select_previous(
15212        &mut self,
15213        action: &SelectPrevious,
15214        window: &mut Window,
15215        cx: &mut Context<Self>,
15216    ) -> Result<()> {
15217        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15218        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15219        let buffer = display_map.buffer_snapshot();
15220        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15221        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15222            let query = &select_prev_state.query;
15223            if !select_prev_state.done {
15224                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15225                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15226                let mut next_selected_range = None;
15227                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15228                let bytes_before_last_selection =
15229                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15230                let bytes_after_first_selection =
15231                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15232                let query_matches = query
15233                    .stream_find_iter(bytes_before_last_selection)
15234                    .map(|result| (last_selection.start, result))
15235                    .chain(
15236                        query
15237                            .stream_find_iter(bytes_after_first_selection)
15238                            .map(|result| (buffer.len(), result)),
15239                    );
15240                for (end_offset, query_match) in query_matches {
15241                    let query_match = query_match.unwrap(); // can only fail due to I/O
15242                    let offset_range =
15243                        end_offset - query_match.end()..end_offset - query_match.start();
15244
15245                    if !select_prev_state.wordwise
15246                        || (!buffer.is_inside_word(offset_range.start, None)
15247                            && !buffer.is_inside_word(offset_range.end, None))
15248                    {
15249                        next_selected_range = Some(offset_range);
15250                        break;
15251                    }
15252                }
15253
15254                if let Some(next_selected_range) = next_selected_range {
15255                    self.select_match_ranges(
15256                        next_selected_range,
15257                        last_selection.reversed,
15258                        action.replace_newest,
15259                        Some(Autoscroll::newest()),
15260                        window,
15261                        cx,
15262                    );
15263                } else {
15264                    select_prev_state.done = true;
15265                }
15266            }
15267
15268            self.select_prev_state = Some(select_prev_state);
15269        } else {
15270            let mut only_carets = true;
15271            let mut same_text_selected = true;
15272            let mut selected_text = None;
15273
15274            let mut selections_iter = selections.iter().peekable();
15275            while let Some(selection) = selections_iter.next() {
15276                if selection.start != selection.end {
15277                    only_carets = false;
15278                }
15279
15280                if same_text_selected {
15281                    if selected_text.is_none() {
15282                        selected_text =
15283                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15284                    }
15285
15286                    if let Some(next_selection) = selections_iter.peek() {
15287                        if next_selection.len() == selection.len() {
15288                            let next_selected_text = buffer
15289                                .text_for_range(next_selection.range())
15290                                .collect::<String>();
15291                            if Some(next_selected_text) != selected_text {
15292                                same_text_selected = false;
15293                                selected_text = None;
15294                            }
15295                        } else {
15296                            same_text_selected = false;
15297                            selected_text = None;
15298                        }
15299                    }
15300                }
15301            }
15302
15303            if only_carets {
15304                for selection in &mut selections {
15305                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15306                    selection.start = word_range.start;
15307                    selection.end = word_range.end;
15308                    selection.goal = SelectionGoal::None;
15309                    selection.reversed = false;
15310                    self.select_match_ranges(
15311                        selection.start..selection.end,
15312                        selection.reversed,
15313                        action.replace_newest,
15314                        Some(Autoscroll::newest()),
15315                        window,
15316                        cx,
15317                    );
15318                }
15319                if selections.len() == 1 {
15320                    let selection = selections
15321                        .last()
15322                        .expect("ensured that there's only one selection");
15323                    let query = buffer
15324                        .text_for_range(selection.start..selection.end)
15325                        .collect::<String>();
15326                    let is_empty = query.is_empty();
15327                    let select_state = SelectNextState {
15328                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15329                        wordwise: true,
15330                        done: is_empty,
15331                    };
15332                    self.select_prev_state = Some(select_state);
15333                } else {
15334                    self.select_prev_state = None;
15335                }
15336            } else if let Some(selected_text) = selected_text {
15337                self.select_prev_state = Some(SelectNextState {
15338                    query: self
15339                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15340                    wordwise: false,
15341                    done: false,
15342                });
15343                self.select_previous(action, window, cx)?;
15344            }
15345        }
15346        Ok(())
15347    }
15348
15349    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15350    /// setting the case sensitivity based on the global
15351    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15352    /// editor's settings.
15353    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15354    where
15355        I: IntoIterator<Item = P>,
15356        P: AsRef<[u8]>,
15357    {
15358        let case_sensitive = self
15359            .select_next_is_case_sensitive
15360            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
15361
15362        let mut builder = AhoCorasickBuilder::new();
15363        builder.ascii_case_insensitive(!case_sensitive);
15364        builder.build(patterns)
15365    }
15366
15367    pub fn find_next_match(
15368        &mut self,
15369        _: &FindNextMatch,
15370        window: &mut Window,
15371        cx: &mut Context<Self>,
15372    ) -> Result<()> {
15373        let selections = self.selections.disjoint_anchors_arc();
15374        match selections.first() {
15375            Some(first) if selections.len() >= 2 => {
15376                self.change_selections(Default::default(), window, cx, |s| {
15377                    s.select_ranges([first.range()]);
15378                });
15379            }
15380            _ => self.select_next(
15381                &SelectNext {
15382                    replace_newest: true,
15383                },
15384                window,
15385                cx,
15386            )?,
15387        }
15388        Ok(())
15389    }
15390
15391    pub fn find_previous_match(
15392        &mut self,
15393        _: &FindPreviousMatch,
15394        window: &mut Window,
15395        cx: &mut Context<Self>,
15396    ) -> Result<()> {
15397        let selections = self.selections.disjoint_anchors_arc();
15398        match selections.last() {
15399            Some(last) if selections.len() >= 2 => {
15400                self.change_selections(Default::default(), window, cx, |s| {
15401                    s.select_ranges([last.range()]);
15402                });
15403            }
15404            _ => self.select_previous(
15405                &SelectPrevious {
15406                    replace_newest: true,
15407                },
15408                window,
15409                cx,
15410            )?,
15411        }
15412        Ok(())
15413    }
15414
15415    pub fn toggle_comments(
15416        &mut self,
15417        action: &ToggleComments,
15418        window: &mut Window,
15419        cx: &mut Context<Self>,
15420    ) {
15421        if self.read_only(cx) {
15422            return;
15423        }
15424        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15425        let text_layout_details = &self.text_layout_details(window);
15426        self.transact(window, cx, |this, window, cx| {
15427            let mut selections = this
15428                .selections
15429                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15430            let mut edits = Vec::new();
15431            let mut selection_edit_ranges = Vec::new();
15432            let mut last_toggled_row = None;
15433            let snapshot = this.buffer.read(cx).read(cx);
15434            let empty_str: Arc<str> = Arc::default();
15435            let mut suffixes_inserted = Vec::new();
15436            let ignore_indent = action.ignore_indent;
15437
15438            fn comment_prefix_range(
15439                snapshot: &MultiBufferSnapshot,
15440                row: MultiBufferRow,
15441                comment_prefix: &str,
15442                comment_prefix_whitespace: &str,
15443                ignore_indent: bool,
15444            ) -> Range<Point> {
15445                let indent_size = if ignore_indent {
15446                    0
15447                } else {
15448                    snapshot.indent_size_for_line(row).len
15449                };
15450
15451                let start = Point::new(row.0, indent_size);
15452
15453                let mut line_bytes = snapshot
15454                    .bytes_in_range(start..snapshot.max_point())
15455                    .flatten()
15456                    .copied();
15457
15458                // If this line currently begins with the line comment prefix, then record
15459                // the range containing the prefix.
15460                if line_bytes
15461                    .by_ref()
15462                    .take(comment_prefix.len())
15463                    .eq(comment_prefix.bytes())
15464                {
15465                    // Include any whitespace that matches the comment prefix.
15466                    let matching_whitespace_len = line_bytes
15467                        .zip(comment_prefix_whitespace.bytes())
15468                        .take_while(|(a, b)| a == b)
15469                        .count() as u32;
15470                    let end = Point::new(
15471                        start.row,
15472                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15473                    );
15474                    start..end
15475                } else {
15476                    start..start
15477                }
15478            }
15479
15480            fn comment_suffix_range(
15481                snapshot: &MultiBufferSnapshot,
15482                row: MultiBufferRow,
15483                comment_suffix: &str,
15484                comment_suffix_has_leading_space: bool,
15485            ) -> Range<Point> {
15486                let end = Point::new(row.0, snapshot.line_len(row));
15487                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15488
15489                let mut line_end_bytes = snapshot
15490                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15491                    .flatten()
15492                    .copied();
15493
15494                let leading_space_len = if suffix_start_column > 0
15495                    && line_end_bytes.next() == Some(b' ')
15496                    && comment_suffix_has_leading_space
15497                {
15498                    1
15499                } else {
15500                    0
15501                };
15502
15503                // If this line currently begins with the line comment prefix, then record
15504                // the range containing the prefix.
15505                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15506                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15507                    start..end
15508                } else {
15509                    end..end
15510                }
15511            }
15512
15513            // TODO: Handle selections that cross excerpts
15514            for selection in &mut selections {
15515                let start_column = snapshot
15516                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15517                    .len;
15518                let language = if let Some(language) =
15519                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15520                {
15521                    language
15522                } else {
15523                    continue;
15524                };
15525
15526                selection_edit_ranges.clear();
15527
15528                // If multiple selections contain a given row, avoid processing that
15529                // row more than once.
15530                let mut start_row = MultiBufferRow(selection.start.row);
15531                if last_toggled_row == Some(start_row) {
15532                    start_row = start_row.next_row();
15533                }
15534                let end_row =
15535                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15536                        MultiBufferRow(selection.end.row - 1)
15537                    } else {
15538                        MultiBufferRow(selection.end.row)
15539                    };
15540                last_toggled_row = Some(end_row);
15541
15542                if start_row > end_row {
15543                    continue;
15544                }
15545
15546                // If the language has line comments, toggle those.
15547                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15548
15549                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15550                if ignore_indent {
15551                    full_comment_prefixes = full_comment_prefixes
15552                        .into_iter()
15553                        .map(|s| Arc::from(s.trim_end()))
15554                        .collect();
15555                }
15556
15557                if !full_comment_prefixes.is_empty() {
15558                    let first_prefix = full_comment_prefixes
15559                        .first()
15560                        .expect("prefixes is non-empty");
15561                    let prefix_trimmed_lengths = full_comment_prefixes
15562                        .iter()
15563                        .map(|p| p.trim_end_matches(' ').len())
15564                        .collect::<SmallVec<[usize; 4]>>();
15565
15566                    let mut all_selection_lines_are_comments = true;
15567
15568                    for row in start_row.0..=end_row.0 {
15569                        let row = MultiBufferRow(row);
15570                        if start_row < end_row && snapshot.is_line_blank(row) {
15571                            continue;
15572                        }
15573
15574                        let prefix_range = full_comment_prefixes
15575                            .iter()
15576                            .zip(prefix_trimmed_lengths.iter().copied())
15577                            .map(|(prefix, trimmed_prefix_len)| {
15578                                comment_prefix_range(
15579                                    snapshot.deref(),
15580                                    row,
15581                                    &prefix[..trimmed_prefix_len],
15582                                    &prefix[trimmed_prefix_len..],
15583                                    ignore_indent,
15584                                )
15585                            })
15586                            .max_by_key(|range| range.end.column - range.start.column)
15587                            .expect("prefixes is non-empty");
15588
15589                        if prefix_range.is_empty() {
15590                            all_selection_lines_are_comments = false;
15591                        }
15592
15593                        selection_edit_ranges.push(prefix_range);
15594                    }
15595
15596                    if all_selection_lines_are_comments {
15597                        edits.extend(
15598                            selection_edit_ranges
15599                                .iter()
15600                                .cloned()
15601                                .map(|range| (range, empty_str.clone())),
15602                        );
15603                    } else {
15604                        let min_column = selection_edit_ranges
15605                            .iter()
15606                            .map(|range| range.start.column)
15607                            .min()
15608                            .unwrap_or(0);
15609                        edits.extend(selection_edit_ranges.iter().map(|range| {
15610                            let position = Point::new(range.start.row, min_column);
15611                            (position..position, first_prefix.clone())
15612                        }));
15613                    }
15614                } else if let Some(BlockCommentConfig {
15615                    start: full_comment_prefix,
15616                    end: comment_suffix,
15617                    ..
15618                }) = language.block_comment()
15619                {
15620                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15621                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15622                    let prefix_range = comment_prefix_range(
15623                        snapshot.deref(),
15624                        start_row,
15625                        comment_prefix,
15626                        comment_prefix_whitespace,
15627                        ignore_indent,
15628                    );
15629                    let suffix_range = comment_suffix_range(
15630                        snapshot.deref(),
15631                        end_row,
15632                        comment_suffix.trim_start_matches(' '),
15633                        comment_suffix.starts_with(' '),
15634                    );
15635
15636                    if prefix_range.is_empty() || suffix_range.is_empty() {
15637                        edits.push((
15638                            prefix_range.start..prefix_range.start,
15639                            full_comment_prefix.clone(),
15640                        ));
15641                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15642                        suffixes_inserted.push((end_row, comment_suffix.len()));
15643                    } else {
15644                        edits.push((prefix_range, empty_str.clone()));
15645                        edits.push((suffix_range, empty_str.clone()));
15646                    }
15647                } else {
15648                    continue;
15649                }
15650            }
15651
15652            drop(snapshot);
15653            this.buffer.update(cx, |buffer, cx| {
15654                buffer.edit(edits, None, cx);
15655            });
15656
15657            // Adjust selections so that they end before any comment suffixes that
15658            // were inserted.
15659            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15660            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15661            let snapshot = this.buffer.read(cx).read(cx);
15662            for selection in &mut selections {
15663                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15664                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15665                        Ordering::Less => {
15666                            suffixes_inserted.next();
15667                            continue;
15668                        }
15669                        Ordering::Greater => break,
15670                        Ordering::Equal => {
15671                            if selection.end.column == snapshot.line_len(row) {
15672                                if selection.is_empty() {
15673                                    selection.start.column -= suffix_len as u32;
15674                                }
15675                                selection.end.column -= suffix_len as u32;
15676                            }
15677                            break;
15678                        }
15679                    }
15680                }
15681            }
15682
15683            drop(snapshot);
15684            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15685
15686            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15687            let selections_on_single_row = selections.windows(2).all(|selections| {
15688                selections[0].start.row == selections[1].start.row
15689                    && selections[0].end.row == selections[1].end.row
15690                    && selections[0].start.row == selections[0].end.row
15691            });
15692            let selections_selecting = selections
15693                .iter()
15694                .any(|selection| selection.start != selection.end);
15695            let advance_downwards = action.advance_downwards
15696                && selections_on_single_row
15697                && !selections_selecting
15698                && !matches!(this.mode, EditorMode::SingleLine);
15699
15700            if advance_downwards {
15701                let snapshot = this.buffer.read(cx).snapshot(cx);
15702
15703                this.change_selections(Default::default(), window, cx, |s| {
15704                    s.move_cursors_with(|display_snapshot, display_point, _| {
15705                        let mut point = display_point.to_point(display_snapshot);
15706                        point.row += 1;
15707                        point = snapshot.clip_point(point, Bias::Left);
15708                        let display_point = point.to_display_point(display_snapshot);
15709                        let goal = SelectionGoal::HorizontalPosition(
15710                            display_snapshot
15711                                .x_for_display_point(display_point, text_layout_details)
15712                                .into(),
15713                        );
15714                        (display_point, goal)
15715                    })
15716                });
15717            }
15718        });
15719    }
15720
15721    pub fn select_enclosing_symbol(
15722        &mut self,
15723        _: &SelectEnclosingSymbol,
15724        window: &mut Window,
15725        cx: &mut Context<Self>,
15726    ) {
15727        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15728
15729        let buffer = self.buffer.read(cx).snapshot(cx);
15730        let old_selections = self
15731            .selections
15732            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15733            .into_boxed_slice();
15734
15735        fn update_selection(
15736            selection: &Selection<MultiBufferOffset>,
15737            buffer_snap: &MultiBufferSnapshot,
15738        ) -> Option<Selection<MultiBufferOffset>> {
15739            let cursor = selection.head();
15740            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15741            for symbol in symbols.iter().rev() {
15742                let start = symbol.range.start.to_offset(buffer_snap);
15743                let end = symbol.range.end.to_offset(buffer_snap);
15744                let new_range = start..end;
15745                if start < selection.start || end > selection.end {
15746                    return Some(Selection {
15747                        id: selection.id,
15748                        start: new_range.start,
15749                        end: new_range.end,
15750                        goal: SelectionGoal::None,
15751                        reversed: selection.reversed,
15752                    });
15753                }
15754            }
15755            None
15756        }
15757
15758        let mut selected_larger_symbol = false;
15759        let new_selections = old_selections
15760            .iter()
15761            .map(|selection| match update_selection(selection, &buffer) {
15762                Some(new_selection) => {
15763                    if new_selection.range() != selection.range() {
15764                        selected_larger_symbol = true;
15765                    }
15766                    new_selection
15767                }
15768                None => selection.clone(),
15769            })
15770            .collect::<Vec<_>>();
15771
15772        if selected_larger_symbol {
15773            self.change_selections(Default::default(), window, cx, |s| {
15774                s.select(new_selections);
15775            });
15776        }
15777    }
15778
15779    pub fn select_larger_syntax_node(
15780        &mut self,
15781        _: &SelectLargerSyntaxNode,
15782        window: &mut Window,
15783        cx: &mut Context<Self>,
15784    ) {
15785        let Some(visible_row_count) = self.visible_row_count() else {
15786            return;
15787        };
15788        let old_selections: Box<[_]> = self
15789            .selections
15790            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15791            .into();
15792        if old_selections.is_empty() {
15793            return;
15794        }
15795
15796        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15797
15798        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15799        let buffer = self.buffer.read(cx).snapshot(cx);
15800
15801        let mut selected_larger_node = false;
15802        let mut new_selections = old_selections
15803            .iter()
15804            .map(|selection| {
15805                let old_range = selection.start..selection.end;
15806
15807                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15808                    // manually select word at selection
15809                    if ["string_content", "inline"].contains(&node.kind()) {
15810                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15811                        // ignore if word is already selected
15812                        if !word_range.is_empty() && old_range != word_range {
15813                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15814                            // only select word if start and end point belongs to same word
15815                            if word_range == last_word_range {
15816                                selected_larger_node = true;
15817                                return Selection {
15818                                    id: selection.id,
15819                                    start: word_range.start,
15820                                    end: word_range.end,
15821                                    goal: SelectionGoal::None,
15822                                    reversed: selection.reversed,
15823                                };
15824                            }
15825                        }
15826                    }
15827                }
15828
15829                let mut new_range = old_range.clone();
15830                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15831                    new_range = range;
15832                    if !node.is_named() {
15833                        continue;
15834                    }
15835                    if !display_map.intersects_fold(new_range.start)
15836                        && !display_map.intersects_fold(new_range.end)
15837                    {
15838                        break;
15839                    }
15840                }
15841
15842                selected_larger_node |= new_range != old_range;
15843                Selection {
15844                    id: selection.id,
15845                    start: new_range.start,
15846                    end: new_range.end,
15847                    goal: SelectionGoal::None,
15848                    reversed: selection.reversed,
15849                }
15850            })
15851            .collect::<Vec<_>>();
15852
15853        if !selected_larger_node {
15854            return; // don't put this call in the history
15855        }
15856
15857        // scroll based on transformation done to the last selection created by the user
15858        let (last_old, last_new) = old_selections
15859            .last()
15860            .zip(new_selections.last().cloned())
15861            .expect("old_selections isn't empty");
15862
15863        // revert selection
15864        let is_selection_reversed = {
15865            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15866            new_selections.last_mut().expect("checked above").reversed =
15867                should_newest_selection_be_reversed;
15868            should_newest_selection_be_reversed
15869        };
15870
15871        if selected_larger_node {
15872            self.select_syntax_node_history.disable_clearing = true;
15873            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15874                s.select(new_selections.clone());
15875            });
15876            self.select_syntax_node_history.disable_clearing = false;
15877        }
15878
15879        let start_row = last_new.start.to_display_point(&display_map).row().0;
15880        let end_row = last_new.end.to_display_point(&display_map).row().0;
15881        let selection_height = end_row - start_row + 1;
15882        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15883
15884        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15885        let scroll_behavior = if fits_on_the_screen {
15886            self.request_autoscroll(Autoscroll::fit(), cx);
15887            SelectSyntaxNodeScrollBehavior::FitSelection
15888        } else if is_selection_reversed {
15889            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15890            SelectSyntaxNodeScrollBehavior::CursorTop
15891        } else {
15892            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15893            SelectSyntaxNodeScrollBehavior::CursorBottom
15894        };
15895
15896        self.select_syntax_node_history.push((
15897            old_selections,
15898            scroll_behavior,
15899            is_selection_reversed,
15900        ));
15901    }
15902
15903    pub fn select_smaller_syntax_node(
15904        &mut self,
15905        _: &SelectSmallerSyntaxNode,
15906        window: &mut Window,
15907        cx: &mut Context<Self>,
15908    ) {
15909        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15910
15911        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15912            self.select_syntax_node_history.pop()
15913        {
15914            if let Some(selection) = selections.last_mut() {
15915                selection.reversed = is_selection_reversed;
15916            }
15917
15918            self.select_syntax_node_history.disable_clearing = true;
15919            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15920                s.select(selections.to_vec());
15921            });
15922            self.select_syntax_node_history.disable_clearing = false;
15923
15924            match scroll_behavior {
15925                SelectSyntaxNodeScrollBehavior::CursorTop => {
15926                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15927                }
15928                SelectSyntaxNodeScrollBehavior::FitSelection => {
15929                    self.request_autoscroll(Autoscroll::fit(), cx);
15930                }
15931                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15932                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15933                }
15934            }
15935        }
15936    }
15937
15938    pub fn unwrap_syntax_node(
15939        &mut self,
15940        _: &UnwrapSyntaxNode,
15941        window: &mut Window,
15942        cx: &mut Context<Self>,
15943    ) {
15944        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15945
15946        let buffer = self.buffer.read(cx).snapshot(cx);
15947        let selections = self
15948            .selections
15949            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15950            .into_iter()
15951            // subtracting the offset requires sorting
15952            .sorted_by_key(|i| i.start);
15953
15954        let full_edits = selections
15955            .into_iter()
15956            .filter_map(|selection| {
15957                let child = if selection.is_empty()
15958                    && let Some((_, ancestor_range)) =
15959                        buffer.syntax_ancestor(selection.start..selection.end)
15960                {
15961                    ancestor_range
15962                } else {
15963                    selection.range()
15964                };
15965
15966                let mut parent = child.clone();
15967                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15968                    parent = ancestor_range;
15969                    if parent.start < child.start || parent.end > child.end {
15970                        break;
15971                    }
15972                }
15973
15974                if parent == child {
15975                    return None;
15976                }
15977                let text = buffer.text_for_range(child).collect::<String>();
15978                Some((selection.id, parent, text))
15979            })
15980            .collect::<Vec<_>>();
15981        if full_edits.is_empty() {
15982            return;
15983        }
15984
15985        self.transact(window, cx, |this, window, cx| {
15986            this.buffer.update(cx, |buffer, cx| {
15987                buffer.edit(
15988                    full_edits
15989                        .iter()
15990                        .map(|(_, p, t)| (p.clone(), t.clone()))
15991                        .collect::<Vec<_>>(),
15992                    None,
15993                    cx,
15994                );
15995            });
15996            this.change_selections(Default::default(), window, cx, |s| {
15997                let mut offset = 0;
15998                let mut selections = vec![];
15999                for (id, parent, text) in full_edits {
16000                    let start = parent.start - offset;
16001                    offset += (parent.end - parent.start) - text.len();
16002                    selections.push(Selection {
16003                        id,
16004                        start,
16005                        end: start + text.len(),
16006                        reversed: false,
16007                        goal: Default::default(),
16008                    });
16009                }
16010                s.select(selections);
16011            });
16012        });
16013    }
16014
16015    pub fn select_next_syntax_node(
16016        &mut self,
16017        _: &SelectNextSyntaxNode,
16018        window: &mut Window,
16019        cx: &mut Context<Self>,
16020    ) {
16021        let old_selections: Box<[_]> = self
16022            .selections
16023            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16024            .into();
16025        if old_selections.is_empty() {
16026            return;
16027        }
16028
16029        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16030
16031        let buffer = self.buffer.read(cx).snapshot(cx);
16032        let mut selected_sibling = false;
16033
16034        let new_selections = old_selections
16035            .iter()
16036            .map(|selection| {
16037                let old_range = selection.start..selection.end;
16038
16039                let old_range =
16040                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16041                let excerpt = buffer.excerpt_containing(old_range.clone());
16042
16043                if let Some(mut excerpt) = excerpt
16044                    && let Some(node) = excerpt
16045                        .buffer()
16046                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16047                {
16048                    let new_range = excerpt.map_range_from_buffer(
16049                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16050                    );
16051                    selected_sibling = true;
16052                    Selection {
16053                        id: selection.id,
16054                        start: new_range.start,
16055                        end: new_range.end,
16056                        goal: SelectionGoal::None,
16057                        reversed: selection.reversed,
16058                    }
16059                } else {
16060                    selection.clone()
16061                }
16062            })
16063            .collect::<Vec<_>>();
16064
16065        if selected_sibling {
16066            self.change_selections(
16067                SelectionEffects::scroll(Autoscroll::fit()),
16068                window,
16069                cx,
16070                |s| {
16071                    s.select(new_selections);
16072                },
16073            );
16074        }
16075    }
16076
16077    pub fn select_prev_syntax_node(
16078        &mut self,
16079        _: &SelectPreviousSyntaxNode,
16080        window: &mut Window,
16081        cx: &mut Context<Self>,
16082    ) {
16083        let old_selections: Box<[_]> = self
16084            .selections
16085            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16086            .into();
16087        if old_selections.is_empty() {
16088            return;
16089        }
16090
16091        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16092
16093        let buffer = self.buffer.read(cx).snapshot(cx);
16094        let mut selected_sibling = false;
16095
16096        let new_selections = old_selections
16097            .iter()
16098            .map(|selection| {
16099                let old_range = selection.start..selection.end;
16100                let old_range =
16101                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16102                let excerpt = buffer.excerpt_containing(old_range.clone());
16103
16104                if let Some(mut excerpt) = excerpt
16105                    && let Some(node) = excerpt
16106                        .buffer()
16107                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16108                {
16109                    let new_range = excerpt.map_range_from_buffer(
16110                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16111                    );
16112                    selected_sibling = true;
16113                    Selection {
16114                        id: selection.id,
16115                        start: new_range.start,
16116                        end: new_range.end,
16117                        goal: SelectionGoal::None,
16118                        reversed: selection.reversed,
16119                    }
16120                } else {
16121                    selection.clone()
16122                }
16123            })
16124            .collect::<Vec<_>>();
16125
16126        if selected_sibling {
16127            self.change_selections(
16128                SelectionEffects::scroll(Autoscroll::fit()),
16129                window,
16130                cx,
16131                |s| {
16132                    s.select(new_selections);
16133                },
16134            );
16135        }
16136    }
16137
16138    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16139        if !EditorSettings::get_global(cx).gutter.runnables {
16140            self.clear_tasks();
16141            return Task::ready(());
16142        }
16143        let project = self.project().map(Entity::downgrade);
16144        let task_sources = self.lsp_task_sources(cx);
16145        let multi_buffer = self.buffer.downgrade();
16146        cx.spawn_in(window, async move |editor, cx| {
16147            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16148            let Some(project) = project.and_then(|p| p.upgrade()) else {
16149                return;
16150            };
16151            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16152                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16153            }) else {
16154                return;
16155            };
16156
16157            let hide_runnables = project
16158                .update(cx, |project, _| project.is_via_collab())
16159                .unwrap_or(true);
16160            if hide_runnables {
16161                return;
16162            }
16163            let new_rows =
16164                cx.background_spawn({
16165                    let snapshot = display_snapshot.clone();
16166                    async move {
16167                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16168                    }
16169                })
16170                    .await;
16171            let Ok(lsp_tasks) =
16172                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16173            else {
16174                return;
16175            };
16176            let lsp_tasks = lsp_tasks.await;
16177
16178            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16179                lsp_tasks
16180                    .into_iter()
16181                    .flat_map(|(kind, tasks)| {
16182                        tasks.into_iter().filter_map(move |(location, task)| {
16183                            Some((kind.clone(), location?, task))
16184                        })
16185                    })
16186                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16187                        let buffer = location.target.buffer;
16188                        let buffer_snapshot = buffer.read(cx).snapshot();
16189                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16190                            |(excerpt_id, snapshot, _)| {
16191                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16192                                    display_snapshot
16193                                        .buffer_snapshot()
16194                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16195                                } else {
16196                                    None
16197                                }
16198                            },
16199                        );
16200                        if let Some(offset) = offset {
16201                            let task_buffer_range =
16202                                location.target.range.to_point(&buffer_snapshot);
16203                            let context_buffer_range =
16204                                task_buffer_range.to_offset(&buffer_snapshot);
16205                            let context_range = BufferOffset(context_buffer_range.start)
16206                                ..BufferOffset(context_buffer_range.end);
16207
16208                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16209                                .or_insert_with(|| RunnableTasks {
16210                                    templates: Vec::new(),
16211                                    offset,
16212                                    column: task_buffer_range.start.column,
16213                                    extra_variables: HashMap::default(),
16214                                    context_range,
16215                                })
16216                                .templates
16217                                .push((kind, task.original_task().clone()));
16218                        }
16219
16220                        acc
16221                    })
16222            }) else {
16223                return;
16224            };
16225
16226            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16227                buffer.language_settings(cx).tasks.prefer_lsp
16228            }) else {
16229                return;
16230            };
16231
16232            let rows = Self::runnable_rows(
16233                project,
16234                display_snapshot,
16235                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16236                new_rows,
16237                cx.clone(),
16238            )
16239            .await;
16240            editor
16241                .update(cx, |editor, _| {
16242                    editor.clear_tasks();
16243                    for (key, mut value) in rows {
16244                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16245                            value.templates.extend(lsp_tasks.templates);
16246                        }
16247
16248                        editor.insert_tasks(key, value);
16249                    }
16250                    for (key, value) in lsp_tasks_by_rows {
16251                        editor.insert_tasks(key, value);
16252                    }
16253                })
16254                .ok();
16255        })
16256    }
16257    fn fetch_runnable_ranges(
16258        snapshot: &DisplaySnapshot,
16259        range: Range<Anchor>,
16260    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16261        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16262    }
16263
16264    fn runnable_rows(
16265        project: Entity<Project>,
16266        snapshot: DisplaySnapshot,
16267        prefer_lsp: bool,
16268        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16269        cx: AsyncWindowContext,
16270    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16271        cx.spawn(async move |cx| {
16272            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16273            for (run_range, mut runnable) in runnable_ranges {
16274                let Some(tasks) = cx
16275                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16276                    .ok()
16277                else {
16278                    continue;
16279                };
16280                let mut tasks = tasks.await;
16281
16282                if prefer_lsp {
16283                    tasks.retain(|(task_kind, _)| {
16284                        !matches!(task_kind, TaskSourceKind::Language { .. })
16285                    });
16286                }
16287                if tasks.is_empty() {
16288                    continue;
16289                }
16290
16291                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16292                let Some(row) = snapshot
16293                    .buffer_snapshot()
16294                    .buffer_line_for_row(MultiBufferRow(point.row))
16295                    .map(|(_, range)| range.start.row)
16296                else {
16297                    continue;
16298                };
16299
16300                let context_range =
16301                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16302                runnable_rows.push((
16303                    (runnable.buffer_id, row),
16304                    RunnableTasks {
16305                        templates: tasks,
16306                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16307                        context_range,
16308                        column: point.column,
16309                        extra_variables: runnable.extra_captures,
16310                    },
16311                ));
16312            }
16313            runnable_rows
16314        })
16315    }
16316
16317    fn templates_with_tags(
16318        project: &Entity<Project>,
16319        runnable: &mut Runnable,
16320        cx: &mut App,
16321    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16322        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16323            let (worktree_id, file) = project
16324                .buffer_for_id(runnable.buffer, cx)
16325                .and_then(|buffer| buffer.read(cx).file())
16326                .map(|file| (file.worktree_id(cx), file.clone()))
16327                .unzip();
16328
16329            (
16330                project.task_store().read(cx).task_inventory().cloned(),
16331                worktree_id,
16332                file,
16333            )
16334        });
16335
16336        let tags = mem::take(&mut runnable.tags);
16337        let language = runnable.language.clone();
16338        cx.spawn(async move |cx| {
16339            let mut templates_with_tags = Vec::new();
16340            if let Some(inventory) = inventory {
16341                for RunnableTag(tag) in tags {
16342                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16343                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16344                    }) else {
16345                        return templates_with_tags;
16346                    };
16347                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16348                        move |(_, template)| {
16349                            template.tags.iter().any(|source_tag| source_tag == &tag)
16350                        },
16351                    ));
16352                }
16353            }
16354            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16355
16356            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16357                // Strongest source wins; if we have worktree tag binding, prefer that to
16358                // global and language bindings;
16359                // if we have a global binding, prefer that to language binding.
16360                let first_mismatch = templates_with_tags
16361                    .iter()
16362                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16363                if let Some(index) = first_mismatch {
16364                    templates_with_tags.truncate(index);
16365                }
16366            }
16367
16368            templates_with_tags
16369        })
16370    }
16371
16372    pub fn move_to_enclosing_bracket(
16373        &mut self,
16374        _: &MoveToEnclosingBracket,
16375        window: &mut Window,
16376        cx: &mut Context<Self>,
16377    ) {
16378        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16379        self.change_selections(Default::default(), window, cx, |s| {
16380            s.move_offsets_with(|snapshot, selection| {
16381                let Some(enclosing_bracket_ranges) =
16382                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16383                else {
16384                    return;
16385                };
16386
16387                let mut best_length = usize::MAX;
16388                let mut best_inside = false;
16389                let mut best_in_bracket_range = false;
16390                let mut best_destination = None;
16391                for (open, close) in enclosing_bracket_ranges {
16392                    let close = close.to_inclusive();
16393                    let length = *close.end() - open.start;
16394                    let inside = selection.start >= open.end && selection.end <= *close.start();
16395                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16396                        || close.contains(&selection.head());
16397
16398                    // If best is next to a bracket and current isn't, skip
16399                    if !in_bracket_range && best_in_bracket_range {
16400                        continue;
16401                    }
16402
16403                    // Prefer smaller lengths unless best is inside and current isn't
16404                    if length > best_length && (best_inside || !inside) {
16405                        continue;
16406                    }
16407
16408                    best_length = length;
16409                    best_inside = inside;
16410                    best_in_bracket_range = in_bracket_range;
16411                    best_destination = Some(
16412                        if close.contains(&selection.start) && close.contains(&selection.end) {
16413                            if inside { open.end } else { open.start }
16414                        } else if inside {
16415                            *close.start()
16416                        } else {
16417                            *close.end()
16418                        },
16419                    );
16420                }
16421
16422                if let Some(destination) = best_destination {
16423                    selection.collapse_to(destination, SelectionGoal::None);
16424                }
16425            })
16426        });
16427    }
16428
16429    pub fn undo_selection(
16430        &mut self,
16431        _: &UndoSelection,
16432        window: &mut Window,
16433        cx: &mut Context<Self>,
16434    ) {
16435        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16436        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16437            self.selection_history.mode = SelectionHistoryMode::Undoing;
16438            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16439                this.end_selection(window, cx);
16440                this.change_selections(
16441                    SelectionEffects::scroll(Autoscroll::newest()),
16442                    window,
16443                    cx,
16444                    |s| s.select_anchors(entry.selections.to_vec()),
16445                );
16446            });
16447            self.selection_history.mode = SelectionHistoryMode::Normal;
16448
16449            self.select_next_state = entry.select_next_state;
16450            self.select_prev_state = entry.select_prev_state;
16451            self.add_selections_state = entry.add_selections_state;
16452        }
16453    }
16454
16455    pub fn redo_selection(
16456        &mut self,
16457        _: &RedoSelection,
16458        window: &mut Window,
16459        cx: &mut Context<Self>,
16460    ) {
16461        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16462        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16463            self.selection_history.mode = SelectionHistoryMode::Redoing;
16464            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16465                this.end_selection(window, cx);
16466                this.change_selections(
16467                    SelectionEffects::scroll(Autoscroll::newest()),
16468                    window,
16469                    cx,
16470                    |s| s.select_anchors(entry.selections.to_vec()),
16471                );
16472            });
16473            self.selection_history.mode = SelectionHistoryMode::Normal;
16474
16475            self.select_next_state = entry.select_next_state;
16476            self.select_prev_state = entry.select_prev_state;
16477            self.add_selections_state = entry.add_selections_state;
16478        }
16479    }
16480
16481    pub fn expand_excerpts(
16482        &mut self,
16483        action: &ExpandExcerpts,
16484        _: &mut Window,
16485        cx: &mut Context<Self>,
16486    ) {
16487        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16488    }
16489
16490    pub fn expand_excerpts_down(
16491        &mut self,
16492        action: &ExpandExcerptsDown,
16493        _: &mut Window,
16494        cx: &mut Context<Self>,
16495    ) {
16496        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16497    }
16498
16499    pub fn expand_excerpts_up(
16500        &mut self,
16501        action: &ExpandExcerptsUp,
16502        _: &mut Window,
16503        cx: &mut Context<Self>,
16504    ) {
16505        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16506    }
16507
16508    pub fn expand_excerpts_for_direction(
16509        &mut self,
16510        lines: u32,
16511        direction: ExpandExcerptDirection,
16512
16513        cx: &mut Context<Self>,
16514    ) {
16515        let selections = self.selections.disjoint_anchors_arc();
16516
16517        let lines = if lines == 0 {
16518            EditorSettings::get_global(cx).expand_excerpt_lines
16519        } else {
16520            lines
16521        };
16522
16523        self.buffer.update(cx, |buffer, cx| {
16524            let snapshot = buffer.snapshot(cx);
16525            let mut excerpt_ids = selections
16526                .iter()
16527                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16528                .collect::<Vec<_>>();
16529            excerpt_ids.sort();
16530            excerpt_ids.dedup();
16531            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16532        })
16533    }
16534
16535    pub fn expand_excerpt(
16536        &mut self,
16537        excerpt: ExcerptId,
16538        direction: ExpandExcerptDirection,
16539        window: &mut Window,
16540        cx: &mut Context<Self>,
16541    ) {
16542        let current_scroll_position = self.scroll_position(cx);
16543        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16544        let mut scroll = None;
16545
16546        if direction == ExpandExcerptDirection::Down {
16547            let multi_buffer = self.buffer.read(cx);
16548            let snapshot = multi_buffer.snapshot(cx);
16549            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16550                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16551                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16552            {
16553                let buffer_snapshot = buffer.read(cx).snapshot();
16554                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16555                let last_row = buffer_snapshot.max_point().row;
16556                let lines_below = last_row.saturating_sub(excerpt_end_row);
16557                if lines_below >= lines_to_expand {
16558                    scroll = Some(
16559                        current_scroll_position
16560                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16561                    );
16562                }
16563            }
16564        }
16565        if direction == ExpandExcerptDirection::Up
16566            && self
16567                .buffer
16568                .read(cx)
16569                .snapshot(cx)
16570                .excerpt_before(excerpt)
16571                .is_none()
16572        {
16573            scroll = Some(current_scroll_position);
16574        }
16575
16576        self.buffer.update(cx, |buffer, cx| {
16577            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16578        });
16579
16580        if let Some(new_scroll_position) = scroll {
16581            self.set_scroll_position(new_scroll_position, window, cx);
16582        }
16583    }
16584
16585    pub fn go_to_singleton_buffer_point(
16586        &mut self,
16587        point: Point,
16588        window: &mut Window,
16589        cx: &mut Context<Self>,
16590    ) {
16591        self.go_to_singleton_buffer_range(point..point, window, cx);
16592    }
16593
16594    pub fn go_to_singleton_buffer_range(
16595        &mut self,
16596        range: Range<Point>,
16597        window: &mut Window,
16598        cx: &mut Context<Self>,
16599    ) {
16600        let multibuffer = self.buffer().read(cx);
16601        let Some(buffer) = multibuffer.as_singleton() else {
16602            return;
16603        };
16604        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16605            return;
16606        };
16607        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16608            return;
16609        };
16610        self.change_selections(
16611            SelectionEffects::default().nav_history(true),
16612            window,
16613            cx,
16614            |s| s.select_anchor_ranges([start..end]),
16615        );
16616    }
16617
16618    pub fn go_to_diagnostic(
16619        &mut self,
16620        action: &GoToDiagnostic,
16621        window: &mut Window,
16622        cx: &mut Context<Self>,
16623    ) {
16624        if !self.diagnostics_enabled() {
16625            return;
16626        }
16627        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16628        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16629    }
16630
16631    pub fn go_to_prev_diagnostic(
16632        &mut self,
16633        action: &GoToPreviousDiagnostic,
16634        window: &mut Window,
16635        cx: &mut Context<Self>,
16636    ) {
16637        if !self.diagnostics_enabled() {
16638            return;
16639        }
16640        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16641        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16642    }
16643
16644    pub fn go_to_diagnostic_impl(
16645        &mut self,
16646        direction: Direction,
16647        severity: GoToDiagnosticSeverityFilter,
16648        window: &mut Window,
16649        cx: &mut Context<Self>,
16650    ) {
16651        let buffer = self.buffer.read(cx).snapshot(cx);
16652        let selection = self
16653            .selections
16654            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16655
16656        let mut active_group_id = None;
16657        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16658            && active_group.active_range.start.to_offset(&buffer) == selection.start
16659        {
16660            active_group_id = Some(active_group.group_id);
16661        }
16662
16663        fn filtered<'a>(
16664            severity: GoToDiagnosticSeverityFilter,
16665            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16666        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16667            diagnostics
16668                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16669                .filter(|entry| entry.range.start != entry.range.end)
16670                .filter(|entry| !entry.diagnostic.is_unnecessary)
16671        }
16672
16673        let before = filtered(
16674            severity,
16675            buffer
16676                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16677                .filter(|entry| entry.range.start <= selection.start),
16678        );
16679        let after = filtered(
16680            severity,
16681            buffer
16682                .diagnostics_in_range(selection.start..buffer.len())
16683                .filter(|entry| entry.range.start >= selection.start),
16684        );
16685
16686        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16687        if direction == Direction::Prev {
16688            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16689            {
16690                for diagnostic in prev_diagnostics.into_iter().rev() {
16691                    if diagnostic.range.start != selection.start
16692                        || active_group_id
16693                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16694                    {
16695                        found = Some(diagnostic);
16696                        break 'outer;
16697                    }
16698                }
16699            }
16700        } else {
16701            for diagnostic in after.chain(before) {
16702                if diagnostic.range.start != selection.start
16703                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16704                {
16705                    found = Some(diagnostic);
16706                    break;
16707                }
16708            }
16709        }
16710        let Some(next_diagnostic) = found else {
16711            return;
16712        };
16713
16714        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16715        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16716            return;
16717        };
16718        let snapshot = self.snapshot(window, cx);
16719        if snapshot.intersects_fold(next_diagnostic.range.start) {
16720            self.unfold_ranges(
16721                std::slice::from_ref(&next_diagnostic.range),
16722                true,
16723                false,
16724                cx,
16725            );
16726        }
16727        self.change_selections(Default::default(), window, cx, |s| {
16728            s.select_ranges(vec![
16729                next_diagnostic.range.start..next_diagnostic.range.start,
16730            ])
16731        });
16732        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16733        self.refresh_edit_prediction(false, true, window, cx);
16734    }
16735
16736    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16737        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16738        let snapshot = self.snapshot(window, cx);
16739        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16740        self.go_to_hunk_before_or_after_position(
16741            &snapshot,
16742            selection.head(),
16743            Direction::Next,
16744            window,
16745            cx,
16746        );
16747    }
16748
16749    pub fn go_to_hunk_before_or_after_position(
16750        &mut self,
16751        snapshot: &EditorSnapshot,
16752        position: Point,
16753        direction: Direction,
16754        window: &mut Window,
16755        cx: &mut Context<Editor>,
16756    ) {
16757        let row = if direction == Direction::Next {
16758            self.hunk_after_position(snapshot, position)
16759                .map(|hunk| hunk.row_range.start)
16760        } else {
16761            self.hunk_before_position(snapshot, position)
16762        };
16763
16764        if let Some(row) = row {
16765            let destination = Point::new(row.0, 0);
16766            let autoscroll = Autoscroll::center();
16767
16768            self.unfold_ranges(&[destination..destination], false, false, cx);
16769            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16770                s.select_ranges([destination..destination]);
16771            });
16772        }
16773    }
16774
16775    fn hunk_after_position(
16776        &mut self,
16777        snapshot: &EditorSnapshot,
16778        position: Point,
16779    ) -> Option<MultiBufferDiffHunk> {
16780        snapshot
16781            .buffer_snapshot()
16782            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16783            .find(|hunk| hunk.row_range.start.0 > position.row)
16784            .or_else(|| {
16785                snapshot
16786                    .buffer_snapshot()
16787                    .diff_hunks_in_range(Point::zero()..position)
16788                    .find(|hunk| hunk.row_range.end.0 < position.row)
16789            })
16790    }
16791
16792    fn go_to_prev_hunk(
16793        &mut self,
16794        _: &GoToPreviousHunk,
16795        window: &mut Window,
16796        cx: &mut Context<Self>,
16797    ) {
16798        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16799        let snapshot = self.snapshot(window, cx);
16800        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16801        self.go_to_hunk_before_or_after_position(
16802            &snapshot,
16803            selection.head(),
16804            Direction::Prev,
16805            window,
16806            cx,
16807        );
16808    }
16809
16810    fn hunk_before_position(
16811        &mut self,
16812        snapshot: &EditorSnapshot,
16813        position: Point,
16814    ) -> Option<MultiBufferRow> {
16815        snapshot
16816            .buffer_snapshot()
16817            .diff_hunk_before(position)
16818            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16819    }
16820
16821    fn go_to_next_change(
16822        &mut self,
16823        _: &GoToNextChange,
16824        window: &mut Window,
16825        cx: &mut Context<Self>,
16826    ) {
16827        if let Some(selections) = self
16828            .change_list
16829            .next_change(1, Direction::Next)
16830            .map(|s| s.to_vec())
16831        {
16832            self.change_selections(Default::default(), window, cx, |s| {
16833                let map = s.display_snapshot();
16834                s.select_display_ranges(selections.iter().map(|a| {
16835                    let point = a.to_display_point(&map);
16836                    point..point
16837                }))
16838            })
16839        }
16840    }
16841
16842    fn go_to_previous_change(
16843        &mut self,
16844        _: &GoToPreviousChange,
16845        window: &mut Window,
16846        cx: &mut Context<Self>,
16847    ) {
16848        if let Some(selections) = self
16849            .change_list
16850            .next_change(1, Direction::Prev)
16851            .map(|s| s.to_vec())
16852        {
16853            self.change_selections(Default::default(), window, cx, |s| {
16854                let map = s.display_snapshot();
16855                s.select_display_ranges(selections.iter().map(|a| {
16856                    let point = a.to_display_point(&map);
16857                    point..point
16858                }))
16859            })
16860        }
16861    }
16862
16863    pub fn go_to_next_document_highlight(
16864        &mut self,
16865        _: &GoToNextDocumentHighlight,
16866        window: &mut Window,
16867        cx: &mut Context<Self>,
16868    ) {
16869        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16870    }
16871
16872    pub fn go_to_prev_document_highlight(
16873        &mut self,
16874        _: &GoToPreviousDocumentHighlight,
16875        window: &mut Window,
16876        cx: &mut Context<Self>,
16877    ) {
16878        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16879    }
16880
16881    pub fn go_to_document_highlight_before_or_after_position(
16882        &mut self,
16883        direction: Direction,
16884        window: &mut Window,
16885        cx: &mut Context<Editor>,
16886    ) {
16887        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16888        let snapshot = self.snapshot(window, cx);
16889        let buffer = &snapshot.buffer_snapshot();
16890        let position = self
16891            .selections
16892            .newest::<Point>(&snapshot.display_snapshot)
16893            .head();
16894        let anchor_position = buffer.anchor_after(position);
16895
16896        // Get all document highlights (both read and write)
16897        let mut all_highlights = Vec::new();
16898
16899        if let Some((_, read_highlights)) = self
16900            .background_highlights
16901            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16902        {
16903            all_highlights.extend(read_highlights.iter());
16904        }
16905
16906        if let Some((_, write_highlights)) = self
16907            .background_highlights
16908            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16909        {
16910            all_highlights.extend(write_highlights.iter());
16911        }
16912
16913        if all_highlights.is_empty() {
16914            return;
16915        }
16916
16917        // Sort highlights by position
16918        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16919
16920        let target_highlight = match direction {
16921            Direction::Next => {
16922                // Find the first highlight after the current position
16923                all_highlights
16924                    .iter()
16925                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16926            }
16927            Direction::Prev => {
16928                // Find the last highlight before the current position
16929                all_highlights
16930                    .iter()
16931                    .rev()
16932                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16933            }
16934        };
16935
16936        if let Some(highlight) = target_highlight {
16937            let destination = highlight.start.to_point(buffer);
16938            let autoscroll = Autoscroll::center();
16939
16940            self.unfold_ranges(&[destination..destination], false, false, cx);
16941            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16942                s.select_ranges([destination..destination]);
16943            });
16944        }
16945    }
16946
16947    fn go_to_line<T: 'static>(
16948        &mut self,
16949        position: Anchor,
16950        highlight_color: Option<Hsla>,
16951        window: &mut Window,
16952        cx: &mut Context<Self>,
16953    ) {
16954        let snapshot = self.snapshot(window, cx).display_snapshot;
16955        let position = position.to_point(&snapshot.buffer_snapshot());
16956        let start = snapshot
16957            .buffer_snapshot()
16958            .clip_point(Point::new(position.row, 0), Bias::Left);
16959        let end = start + Point::new(1, 0);
16960        let start = snapshot.buffer_snapshot().anchor_before(start);
16961        let end = snapshot.buffer_snapshot().anchor_before(end);
16962
16963        self.highlight_rows::<T>(
16964            start..end,
16965            highlight_color
16966                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16967            Default::default(),
16968            cx,
16969        );
16970
16971        if self.buffer.read(cx).is_singleton() {
16972            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16973        }
16974    }
16975
16976    pub fn go_to_definition(
16977        &mut self,
16978        _: &GoToDefinition,
16979        window: &mut Window,
16980        cx: &mut Context<Self>,
16981    ) -> Task<Result<Navigated>> {
16982        let definition =
16983            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16984        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16985        cx.spawn_in(window, async move |editor, cx| {
16986            if definition.await? == Navigated::Yes {
16987                return Ok(Navigated::Yes);
16988            }
16989            match fallback_strategy {
16990                GoToDefinitionFallback::None => Ok(Navigated::No),
16991                GoToDefinitionFallback::FindAllReferences => {
16992                    match editor.update_in(cx, |editor, window, cx| {
16993                        editor.find_all_references(&FindAllReferences::default(), window, cx)
16994                    })? {
16995                        Some(references) => references.await,
16996                        None => Ok(Navigated::No),
16997                    }
16998                }
16999            }
17000        })
17001    }
17002
17003    pub fn go_to_declaration(
17004        &mut self,
17005        _: &GoToDeclaration,
17006        window: &mut Window,
17007        cx: &mut Context<Self>,
17008    ) -> Task<Result<Navigated>> {
17009        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17010    }
17011
17012    pub fn go_to_declaration_split(
17013        &mut self,
17014        _: &GoToDeclaration,
17015        window: &mut Window,
17016        cx: &mut Context<Self>,
17017    ) -> Task<Result<Navigated>> {
17018        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17019    }
17020
17021    pub fn go_to_implementation(
17022        &mut self,
17023        _: &GoToImplementation,
17024        window: &mut Window,
17025        cx: &mut Context<Self>,
17026    ) -> Task<Result<Navigated>> {
17027        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17028    }
17029
17030    pub fn go_to_implementation_split(
17031        &mut self,
17032        _: &GoToImplementationSplit,
17033        window: &mut Window,
17034        cx: &mut Context<Self>,
17035    ) -> Task<Result<Navigated>> {
17036        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17037    }
17038
17039    pub fn go_to_type_definition(
17040        &mut self,
17041        _: &GoToTypeDefinition,
17042        window: &mut Window,
17043        cx: &mut Context<Self>,
17044    ) -> Task<Result<Navigated>> {
17045        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17046    }
17047
17048    pub fn go_to_definition_split(
17049        &mut self,
17050        _: &GoToDefinitionSplit,
17051        window: &mut Window,
17052        cx: &mut Context<Self>,
17053    ) -> Task<Result<Navigated>> {
17054        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17055    }
17056
17057    pub fn go_to_type_definition_split(
17058        &mut self,
17059        _: &GoToTypeDefinitionSplit,
17060        window: &mut Window,
17061        cx: &mut Context<Self>,
17062    ) -> Task<Result<Navigated>> {
17063        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17064    }
17065
17066    fn go_to_definition_of_kind(
17067        &mut self,
17068        kind: GotoDefinitionKind,
17069        split: bool,
17070        window: &mut Window,
17071        cx: &mut Context<Self>,
17072    ) -> Task<Result<Navigated>> {
17073        let Some(provider) = self.semantics_provider.clone() else {
17074            return Task::ready(Ok(Navigated::No));
17075        };
17076        let head = self
17077            .selections
17078            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17079            .head();
17080        let buffer = self.buffer.read(cx);
17081        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17082            return Task::ready(Ok(Navigated::No));
17083        };
17084        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17085            return Task::ready(Ok(Navigated::No));
17086        };
17087
17088        cx.spawn_in(window, async move |editor, cx| {
17089            let Some(definitions) = definitions.await? else {
17090                return Ok(Navigated::No);
17091            };
17092            let navigated = editor
17093                .update_in(cx, |editor, window, cx| {
17094                    editor.navigate_to_hover_links(
17095                        Some(kind),
17096                        definitions
17097                            .into_iter()
17098                            .filter(|location| {
17099                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17100                            })
17101                            .map(HoverLink::Text)
17102                            .collect::<Vec<_>>(),
17103                        split,
17104                        window,
17105                        cx,
17106                    )
17107                })?
17108                .await?;
17109            anyhow::Ok(navigated)
17110        })
17111    }
17112
17113    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17114        let selection = self.selections.newest_anchor();
17115        let head = selection.head();
17116        let tail = selection.tail();
17117
17118        let Some((buffer, start_position)) =
17119            self.buffer.read(cx).text_anchor_for_position(head, cx)
17120        else {
17121            return;
17122        };
17123
17124        let end_position = if head != tail {
17125            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17126                return;
17127            };
17128            Some(pos)
17129        } else {
17130            None
17131        };
17132
17133        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17134            let url = if let Some(end_pos) = end_position {
17135                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17136            } else {
17137                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17138            };
17139
17140            if let Some(url) = url {
17141                cx.update(|window, cx| {
17142                    if parse_zed_link(&url, cx).is_some() {
17143                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17144                    } else {
17145                        cx.open_url(&url);
17146                    }
17147                })?;
17148            }
17149
17150            anyhow::Ok(())
17151        });
17152
17153        url_finder.detach();
17154    }
17155
17156    pub fn open_selected_filename(
17157        &mut self,
17158        _: &OpenSelectedFilename,
17159        window: &mut Window,
17160        cx: &mut Context<Self>,
17161    ) {
17162        let Some(workspace) = self.workspace() else {
17163            return;
17164        };
17165
17166        let position = self.selections.newest_anchor().head();
17167
17168        let Some((buffer, buffer_position)) =
17169            self.buffer.read(cx).text_anchor_for_position(position, cx)
17170        else {
17171            return;
17172        };
17173
17174        let project = self.project.clone();
17175
17176        cx.spawn_in(window, async move |_, cx| {
17177            let result = find_file(&buffer, project, buffer_position, cx).await;
17178
17179            if let Some((_, path)) = result {
17180                workspace
17181                    .update_in(cx, |workspace, window, cx| {
17182                        workspace.open_resolved_path(path, window, cx)
17183                    })?
17184                    .await?;
17185            }
17186            anyhow::Ok(())
17187        })
17188        .detach();
17189    }
17190
17191    pub(crate) fn navigate_to_hover_links(
17192        &mut self,
17193        kind: Option<GotoDefinitionKind>,
17194        definitions: Vec<HoverLink>,
17195        split: bool,
17196        window: &mut Window,
17197        cx: &mut Context<Editor>,
17198    ) -> Task<Result<Navigated>> {
17199        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17200        let mut first_url_or_file = None;
17201        let definitions: Vec<_> = definitions
17202            .into_iter()
17203            .filter_map(|def| match def {
17204                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17205                HoverLink::InlayHint(lsp_location, server_id) => {
17206                    let computation =
17207                        self.compute_target_location(lsp_location, server_id, window, cx);
17208                    Some(cx.background_spawn(computation))
17209                }
17210                HoverLink::Url(url) => {
17211                    first_url_or_file = Some(Either::Left(url));
17212                    None
17213                }
17214                HoverLink::File(path) => {
17215                    first_url_or_file = Some(Either::Right(path));
17216                    None
17217                }
17218            })
17219            .collect();
17220
17221        let workspace = self.workspace();
17222
17223        cx.spawn_in(window, async move |editor, cx| {
17224            let locations: Vec<Location> = future::join_all(definitions)
17225                .await
17226                .into_iter()
17227                .filter_map(|location| location.transpose())
17228                .collect::<Result<_>>()
17229                .context("location tasks")?;
17230            let mut locations = cx.update(|_, cx| {
17231                locations
17232                    .into_iter()
17233                    .map(|location| {
17234                        let buffer = location.buffer.read(cx);
17235                        (location.buffer, location.range.to_point(buffer))
17236                    })
17237                    .into_group_map()
17238            })?;
17239            let mut num_locations = 0;
17240            for ranges in locations.values_mut() {
17241                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17242                ranges.dedup();
17243                num_locations += ranges.len();
17244            }
17245
17246            if num_locations > 1 {
17247                let tab_kind = match kind {
17248                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17249                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17250                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17251                    Some(GotoDefinitionKind::Type) => "Types",
17252                };
17253                let title = editor
17254                    .update_in(cx, |_, _, cx| {
17255                        let target = locations
17256                            .iter()
17257                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17258                            .map(|(buffer, location)| {
17259                                buffer
17260                                    .read(cx)
17261                                    .text_for_range(location.clone())
17262                                    .collect::<String>()
17263                            })
17264                            .filter(|text| !text.contains('\n'))
17265                            .unique()
17266                            .take(3)
17267                            .join(", ");
17268                        if target.is_empty() {
17269                            tab_kind.to_owned()
17270                        } else {
17271                            format!("{tab_kind} for {target}")
17272                        }
17273                    })
17274                    .context("buffer title")?;
17275
17276                let Some(workspace) = workspace else {
17277                    return Ok(Navigated::No);
17278                };
17279
17280                let opened = workspace
17281                    .update_in(cx, |workspace, window, cx| {
17282                        let allow_preview = PreviewTabsSettings::get_global(cx)
17283                            .enable_preview_multibuffer_from_code_navigation;
17284                        Self::open_locations_in_multibuffer(
17285                            workspace,
17286                            locations,
17287                            title,
17288                            split,
17289                            allow_preview,
17290                            MultibufferSelectionMode::First,
17291                            window,
17292                            cx,
17293                        )
17294                    })
17295                    .is_ok();
17296
17297                anyhow::Ok(Navigated::from_bool(opened))
17298            } else if num_locations == 0 {
17299                // If there is one url or file, open it directly
17300                match first_url_or_file {
17301                    Some(Either::Left(url)) => {
17302                        cx.update(|window, cx| {
17303                            if parse_zed_link(&url, cx).is_some() {
17304                                window
17305                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17306                            } else {
17307                                cx.open_url(&url);
17308                            }
17309                        })?;
17310                        Ok(Navigated::Yes)
17311                    }
17312                    Some(Either::Right(path)) => {
17313                        // TODO(andrew): respect preview tab settings
17314                        //               `enable_keep_preview_on_code_navigation` and
17315                        //               `enable_preview_file_from_code_navigation`
17316                        let Some(workspace) = workspace else {
17317                            return Ok(Navigated::No);
17318                        };
17319                        workspace
17320                            .update_in(cx, |workspace, window, cx| {
17321                                workspace.open_resolved_path(path, window, cx)
17322                            })?
17323                            .await?;
17324                        Ok(Navigated::Yes)
17325                    }
17326                    None => Ok(Navigated::No),
17327                }
17328            } else {
17329                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17330                let target_range = target_ranges.first().unwrap().clone();
17331
17332                editor.update_in(cx, |editor, window, cx| {
17333                    let range = target_range.to_point(target_buffer.read(cx));
17334                    let range = editor.range_for_match(&range);
17335                    let range = collapse_multiline_range(range);
17336
17337                    if !split
17338                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17339                    {
17340                        editor.go_to_singleton_buffer_range(range, window, cx);
17341                    } else {
17342                        let Some(workspace) = workspace else {
17343                            return Navigated::No;
17344                        };
17345                        let pane = workspace.read(cx).active_pane().clone();
17346                        window.defer(cx, move |window, cx| {
17347                            let target_editor: Entity<Self> =
17348                                workspace.update(cx, |workspace, cx| {
17349                                    let pane = if split {
17350                                        workspace.adjacent_pane(window, cx)
17351                                    } else {
17352                                        workspace.active_pane().clone()
17353                                    };
17354
17355                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17356                                    let keep_old_preview = preview_tabs_settings
17357                                        .enable_keep_preview_on_code_navigation;
17358                                    let allow_new_preview = preview_tabs_settings
17359                                        .enable_preview_file_from_code_navigation;
17360
17361                                    workspace.open_project_item(
17362                                        pane,
17363                                        target_buffer.clone(),
17364                                        true,
17365                                        true,
17366                                        keep_old_preview,
17367                                        allow_new_preview,
17368                                        window,
17369                                        cx,
17370                                    )
17371                                });
17372                            target_editor.update(cx, |target_editor, cx| {
17373                                // When selecting a definition in a different buffer, disable the nav history
17374                                // to avoid creating a history entry at the previous cursor location.
17375                                pane.update(cx, |pane, _| pane.disable_history());
17376                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17377                                pane.update(cx, |pane, _| pane.enable_history());
17378                            });
17379                        });
17380                    }
17381                    Navigated::Yes
17382                })
17383            }
17384        })
17385    }
17386
17387    fn compute_target_location(
17388        &self,
17389        lsp_location: lsp::Location,
17390        server_id: LanguageServerId,
17391        window: &mut Window,
17392        cx: &mut Context<Self>,
17393    ) -> Task<anyhow::Result<Option<Location>>> {
17394        let Some(project) = self.project.clone() else {
17395            return Task::ready(Ok(None));
17396        };
17397
17398        cx.spawn_in(window, async move |editor, cx| {
17399            let location_task = editor.update(cx, |_, cx| {
17400                project.update(cx, |project, cx| {
17401                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17402                })
17403            })?;
17404            let location = Some({
17405                let target_buffer_handle = location_task.await.context("open local buffer")?;
17406                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17407                    let target_start = target_buffer
17408                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17409                    let target_end = target_buffer
17410                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17411                    target_buffer.anchor_after(target_start)
17412                        ..target_buffer.anchor_before(target_end)
17413                })?;
17414                Location {
17415                    buffer: target_buffer_handle,
17416                    range,
17417                }
17418            });
17419            Ok(location)
17420        })
17421    }
17422
17423    fn go_to_next_reference(
17424        &mut self,
17425        _: &GoToNextReference,
17426        window: &mut Window,
17427        cx: &mut Context<Self>,
17428    ) {
17429        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17430        if let Some(task) = task {
17431            task.detach();
17432        };
17433    }
17434
17435    fn go_to_prev_reference(
17436        &mut self,
17437        _: &GoToPreviousReference,
17438        window: &mut Window,
17439        cx: &mut Context<Self>,
17440    ) {
17441        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17442        if let Some(task) = task {
17443            task.detach();
17444        };
17445    }
17446
17447    pub fn go_to_reference_before_or_after_position(
17448        &mut self,
17449        direction: Direction,
17450        count: usize,
17451        window: &mut Window,
17452        cx: &mut Context<Self>,
17453    ) -> Option<Task<Result<()>>> {
17454        let selection = self.selections.newest_anchor();
17455        let head = selection.head();
17456
17457        let multi_buffer = self.buffer.read(cx);
17458
17459        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17460        let workspace = self.workspace()?;
17461        let project = workspace.read(cx).project().clone();
17462        let references =
17463            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17464        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17465            let Some(locations) = references.await? else {
17466                return Ok(());
17467            };
17468
17469            if locations.is_empty() {
17470                // totally normal - the cursor may be on something which is not
17471                // a symbol (e.g. a keyword)
17472                log::info!("no references found under cursor");
17473                return Ok(());
17474            }
17475
17476            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17477
17478            let (locations, current_location_index) =
17479                multi_buffer.update(cx, |multi_buffer, cx| {
17480                    let mut locations = locations
17481                        .into_iter()
17482                        .filter_map(|loc| {
17483                            let start = multi_buffer.buffer_anchor_to_anchor(
17484                                &loc.buffer,
17485                                loc.range.start,
17486                                cx,
17487                            )?;
17488                            let end = multi_buffer.buffer_anchor_to_anchor(
17489                                &loc.buffer,
17490                                loc.range.end,
17491                                cx,
17492                            )?;
17493                            Some(start..end)
17494                        })
17495                        .collect::<Vec<_>>();
17496
17497                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17498                    // There is an O(n) implementation, but given this list will be
17499                    // small (usually <100 items), the extra O(log(n)) factor isn't
17500                    // worth the (surprisingly large amount of) extra complexity.
17501                    locations
17502                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17503
17504                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17505
17506                    let current_location_index = locations.iter().position(|loc| {
17507                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17508                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17509                    });
17510
17511                    (locations, current_location_index)
17512                })?;
17513
17514            let Some(current_location_index) = current_location_index else {
17515                // This indicates something has gone wrong, because we already
17516                // handle the "no references" case above
17517                log::error!(
17518                    "failed to find current reference under cursor. Total references: {}",
17519                    locations.len()
17520                );
17521                return Ok(());
17522            };
17523
17524            let destination_location_index = match direction {
17525                Direction::Next => (current_location_index + count) % locations.len(),
17526                Direction::Prev => {
17527                    (current_location_index + locations.len() - count % locations.len())
17528                        % locations.len()
17529                }
17530            };
17531
17532            // TODO(cameron): is this needed?
17533            // the thinking is to avoid "jumping to the current location" (avoid
17534            // polluting "jumplist" in vim terms)
17535            if current_location_index == destination_location_index {
17536                return Ok(());
17537            }
17538
17539            let Range { start, end } = locations[destination_location_index];
17540
17541            editor.update_in(cx, |editor, window, cx| {
17542                let effects = SelectionEffects::default();
17543
17544                editor.unfold_ranges(&[start..end], false, false, cx);
17545                editor.change_selections(effects, window, cx, |s| {
17546                    s.select_ranges([start..start]);
17547                });
17548            })?;
17549
17550            Ok(())
17551        }))
17552    }
17553
17554    pub fn find_all_references(
17555        &mut self,
17556        action: &FindAllReferences,
17557        window: &mut Window,
17558        cx: &mut Context<Self>,
17559    ) -> Option<Task<Result<Navigated>>> {
17560        let always_open_multibuffer = action.always_open_multibuffer;
17561        let selection = self.selections.newest_anchor();
17562        let multi_buffer = self.buffer.read(cx);
17563        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17564        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
17565        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
17566        let head = selection_offset.head();
17567
17568        let head_anchor = multi_buffer_snapshot.anchor_at(
17569            head,
17570            if head < selection_offset.tail() {
17571                Bias::Right
17572            } else {
17573                Bias::Left
17574            },
17575        );
17576
17577        match self
17578            .find_all_references_task_sources
17579            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17580        {
17581            Ok(_) => {
17582                log::info!(
17583                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17584                );
17585                return None;
17586            }
17587            Err(i) => {
17588                self.find_all_references_task_sources.insert(i, head_anchor);
17589            }
17590        }
17591
17592        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17593        let workspace = self.workspace()?;
17594        let project = workspace.read(cx).project().clone();
17595        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17596        Some(cx.spawn_in(window, async move |editor, cx| {
17597            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17598                if let Ok(i) = editor
17599                    .find_all_references_task_sources
17600                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17601                {
17602                    editor.find_all_references_task_sources.remove(i);
17603                }
17604            });
17605
17606            let Some(locations) = references.await? else {
17607                return anyhow::Ok(Navigated::No);
17608            };
17609            let mut locations = cx.update(|_, cx| {
17610                locations
17611                    .into_iter()
17612                    .map(|location| {
17613                        let buffer = location.buffer.read(cx);
17614                        (location.buffer, location.range.to_point(buffer))
17615                    })
17616                    // if special-casing the single-match case, remove ranges
17617                    // that intersect current selection
17618                    .filter(|(location_buffer, location)| {
17619                        if always_open_multibuffer || &buffer != location_buffer {
17620                            return true;
17621                        }
17622
17623                        !location.contains_inclusive(&selection_point.range())
17624                    })
17625                    .into_group_map()
17626            })?;
17627            if locations.is_empty() {
17628                return anyhow::Ok(Navigated::No);
17629            }
17630            for ranges in locations.values_mut() {
17631                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17632                ranges.dedup();
17633            }
17634            let mut num_locations = 0;
17635            for ranges in locations.values_mut() {
17636                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17637                ranges.dedup();
17638                num_locations += ranges.len();
17639            }
17640
17641            if num_locations == 1 && !always_open_multibuffer {
17642                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17643                let target_range = target_ranges.first().unwrap().clone();
17644
17645                return editor.update_in(cx, |editor, window, cx| {
17646                    let range = target_range.to_point(target_buffer.read(cx));
17647                    let range = editor.range_for_match(&range);
17648                    let range = range.start..range.start;
17649
17650                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
17651                        editor.go_to_singleton_buffer_range(range, window, cx);
17652                    } else {
17653                        let pane = workspace.read(cx).active_pane().clone();
17654                        window.defer(cx, move |window, cx| {
17655                            let target_editor: Entity<Self> =
17656                                workspace.update(cx, |workspace, cx| {
17657                                    let pane = workspace.active_pane().clone();
17658
17659                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17660                                    let keep_old_preview = preview_tabs_settings
17661                                        .enable_keep_preview_on_code_navigation;
17662                                    let allow_new_preview = preview_tabs_settings
17663                                        .enable_preview_file_from_code_navigation;
17664
17665                                    workspace.open_project_item(
17666                                        pane,
17667                                        target_buffer.clone(),
17668                                        true,
17669                                        true,
17670                                        keep_old_preview,
17671                                        allow_new_preview,
17672                                        window,
17673                                        cx,
17674                                    )
17675                                });
17676                            target_editor.update(cx, |target_editor, cx| {
17677                                // When selecting a definition in a different buffer, disable the nav history
17678                                // to avoid creating a history entry at the previous cursor location.
17679                                pane.update(cx, |pane, _| pane.disable_history());
17680                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17681                                pane.update(cx, |pane, _| pane.enable_history());
17682                            });
17683                        });
17684                    }
17685                    Navigated::No
17686                });
17687            }
17688
17689            workspace.update_in(cx, |workspace, window, cx| {
17690                let target = locations
17691                    .iter()
17692                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17693                    .map(|(buffer, location)| {
17694                        buffer
17695                            .read(cx)
17696                            .text_for_range(location.clone())
17697                            .collect::<String>()
17698                    })
17699                    .filter(|text| !text.contains('\n'))
17700                    .unique()
17701                    .take(3)
17702                    .join(", ");
17703                let title = if target.is_empty() {
17704                    "References".to_owned()
17705                } else {
17706                    format!("References to {target}")
17707                };
17708                let allow_preview = PreviewTabsSettings::get_global(cx)
17709                    .enable_preview_multibuffer_from_code_navigation;
17710                Self::open_locations_in_multibuffer(
17711                    workspace,
17712                    locations,
17713                    title,
17714                    false,
17715                    allow_preview,
17716                    MultibufferSelectionMode::First,
17717                    window,
17718                    cx,
17719                );
17720                Navigated::Yes
17721            })
17722        }))
17723    }
17724
17725    /// Opens a multibuffer with the given project locations in it.
17726    pub fn open_locations_in_multibuffer(
17727        workspace: &mut Workspace,
17728        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17729        title: String,
17730        split: bool,
17731        allow_preview: bool,
17732        multibuffer_selection_mode: MultibufferSelectionMode,
17733        window: &mut Window,
17734        cx: &mut Context<Workspace>,
17735    ) {
17736        if locations.is_empty() {
17737            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17738            return;
17739        }
17740
17741        let capability = workspace.project().read(cx).capability();
17742        let mut ranges = <Vec<Range<Anchor>>>::new();
17743
17744        // a key to find existing multibuffer editors with the same set of locations
17745        // to prevent us from opening more and more multibuffer tabs for searches and the like
17746        let mut key = (title.clone(), vec![]);
17747        let excerpt_buffer = cx.new(|cx| {
17748            let key = &mut key.1;
17749            let mut multibuffer = MultiBuffer::new(capability);
17750            for (buffer, mut ranges_for_buffer) in locations {
17751                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17752                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17753                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17754                    PathKey::for_buffer(&buffer, cx),
17755                    buffer.clone(),
17756                    ranges_for_buffer,
17757                    multibuffer_context_lines(cx),
17758                    cx,
17759                );
17760                ranges.extend(new_ranges)
17761            }
17762
17763            multibuffer.with_title(title)
17764        });
17765        let existing = workspace.active_pane().update(cx, |pane, cx| {
17766            pane.items()
17767                .filter_map(|item| item.downcast::<Editor>())
17768                .find(|editor| {
17769                    editor
17770                        .read(cx)
17771                        .lookup_key
17772                        .as_ref()
17773                        .and_then(|it| {
17774                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17775                        })
17776                        .is_some_and(|it| *it == key)
17777                })
17778        });
17779        let was_existing = existing.is_some();
17780        let editor = existing.unwrap_or_else(|| {
17781            cx.new(|cx| {
17782                let mut editor = Editor::for_multibuffer(
17783                    excerpt_buffer,
17784                    Some(workspace.project().clone()),
17785                    window,
17786                    cx,
17787                );
17788                editor.lookup_key = Some(Box::new(key));
17789                editor
17790            })
17791        });
17792        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17793            MultibufferSelectionMode::First => {
17794                if let Some(first_range) = ranges.first() {
17795                    editor.change_selections(
17796                        SelectionEffects::no_scroll(),
17797                        window,
17798                        cx,
17799                        |selections| {
17800                            selections.clear_disjoint();
17801                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17802                        },
17803                    );
17804                }
17805                editor.highlight_background::<Self>(
17806                    &ranges,
17807                    |_, theme| theme.colors().editor_highlighted_line_background,
17808                    cx,
17809                );
17810            }
17811            MultibufferSelectionMode::All => {
17812                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17813                    selections.clear_disjoint();
17814                    selections.select_anchor_ranges(ranges);
17815                });
17816            }
17817        });
17818
17819        let item = Box::new(editor);
17820
17821        let pane = if split {
17822            workspace.adjacent_pane(window, cx)
17823        } else {
17824            workspace.active_pane().clone()
17825        };
17826        let activate_pane = split;
17827
17828        let mut destination_index = None;
17829        pane.update(cx, |pane, cx| {
17830            if allow_preview && !was_existing {
17831                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
17832            }
17833            if was_existing && !allow_preview {
17834                pane.unpreview_item_if_preview(item.item_id());
17835            }
17836            pane.add_item(item, activate_pane, true, destination_index, window, cx);
17837        });
17838    }
17839
17840    pub fn rename(
17841        &mut self,
17842        _: &Rename,
17843        window: &mut Window,
17844        cx: &mut Context<Self>,
17845    ) -> Option<Task<Result<()>>> {
17846        use language::ToOffset as _;
17847
17848        let provider = self.semantics_provider.clone()?;
17849        let selection = self.selections.newest_anchor().clone();
17850        let (cursor_buffer, cursor_buffer_position) = self
17851            .buffer
17852            .read(cx)
17853            .text_anchor_for_position(selection.head(), cx)?;
17854        let (tail_buffer, cursor_buffer_position_end) = self
17855            .buffer
17856            .read(cx)
17857            .text_anchor_for_position(selection.tail(), cx)?;
17858        if tail_buffer != cursor_buffer {
17859            return None;
17860        }
17861
17862        let snapshot = cursor_buffer.read(cx).snapshot();
17863        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17864        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17865        let prepare_rename = provider
17866            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17867            .unwrap_or_else(|| Task::ready(Ok(None)));
17868        drop(snapshot);
17869
17870        Some(cx.spawn_in(window, async move |this, cx| {
17871            let rename_range = if let Some(range) = prepare_rename.await? {
17872                Some(range)
17873            } else {
17874                this.update(cx, |this, cx| {
17875                    let buffer = this.buffer.read(cx).snapshot(cx);
17876                    let mut buffer_highlights = this
17877                        .document_highlights_for_position(selection.head(), &buffer)
17878                        .filter(|highlight| {
17879                            highlight.start.excerpt_id == selection.head().excerpt_id
17880                                && highlight.end.excerpt_id == selection.head().excerpt_id
17881                        });
17882                    buffer_highlights
17883                        .next()
17884                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17885                })?
17886            };
17887            if let Some(rename_range) = rename_range {
17888                this.update_in(cx, |this, window, cx| {
17889                    let snapshot = cursor_buffer.read(cx).snapshot();
17890                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17891                    let cursor_offset_in_rename_range =
17892                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17893                    let cursor_offset_in_rename_range_end =
17894                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17895
17896                    this.take_rename(false, window, cx);
17897                    let buffer = this.buffer.read(cx).read(cx);
17898                    let cursor_offset = selection.head().to_offset(&buffer);
17899                    let rename_start =
17900                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17901                    let rename_end = rename_start + rename_buffer_range.len();
17902                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17903                    let mut old_highlight_id = None;
17904                    let old_name: Arc<str> = buffer
17905                        .chunks(rename_start..rename_end, true)
17906                        .map(|chunk| {
17907                            if old_highlight_id.is_none() {
17908                                old_highlight_id = chunk.syntax_highlight_id;
17909                            }
17910                            chunk.text
17911                        })
17912                        .collect::<String>()
17913                        .into();
17914
17915                    drop(buffer);
17916
17917                    // Position the selection in the rename editor so that it matches the current selection.
17918                    this.show_local_selections = false;
17919                    let rename_editor = cx.new(|cx| {
17920                        let mut editor = Editor::single_line(window, cx);
17921                        editor.buffer.update(cx, |buffer, cx| {
17922                            buffer.edit(
17923                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
17924                                None,
17925                                cx,
17926                            )
17927                        });
17928                        let cursor_offset_in_rename_range =
17929                            MultiBufferOffset(cursor_offset_in_rename_range);
17930                        let cursor_offset_in_rename_range_end =
17931                            MultiBufferOffset(cursor_offset_in_rename_range_end);
17932                        let rename_selection_range = match cursor_offset_in_rename_range
17933                            .cmp(&cursor_offset_in_rename_range_end)
17934                        {
17935                            Ordering::Equal => {
17936                                editor.select_all(&SelectAll, window, cx);
17937                                return editor;
17938                            }
17939                            Ordering::Less => {
17940                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17941                            }
17942                            Ordering::Greater => {
17943                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17944                            }
17945                        };
17946                        if rename_selection_range.end.0 > old_name.len() {
17947                            editor.select_all(&SelectAll, window, cx);
17948                        } else {
17949                            editor.change_selections(Default::default(), window, cx, |s| {
17950                                s.select_ranges([rename_selection_range]);
17951                            });
17952                        }
17953                        editor
17954                    });
17955                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17956                        if e == &EditorEvent::Focused {
17957                            cx.emit(EditorEvent::FocusedIn)
17958                        }
17959                    })
17960                    .detach();
17961
17962                    let write_highlights =
17963                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17964                    let read_highlights =
17965                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17966                    let ranges = write_highlights
17967                        .iter()
17968                        .flat_map(|(_, ranges)| ranges.iter())
17969                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17970                        .cloned()
17971                        .collect();
17972
17973                    this.highlight_text::<Rename>(
17974                        ranges,
17975                        HighlightStyle {
17976                            fade_out: Some(0.6),
17977                            ..Default::default()
17978                        },
17979                        cx,
17980                    );
17981                    let rename_focus_handle = rename_editor.focus_handle(cx);
17982                    window.focus(&rename_focus_handle, cx);
17983                    let block_id = this.insert_blocks(
17984                        [BlockProperties {
17985                            style: BlockStyle::Flex,
17986                            placement: BlockPlacement::Below(range.start),
17987                            height: Some(1),
17988                            render: Arc::new({
17989                                let rename_editor = rename_editor.clone();
17990                                move |cx: &mut BlockContext| {
17991                                    let mut text_style = cx.editor_style.text.clone();
17992                                    if let Some(highlight_style) = old_highlight_id
17993                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17994                                    {
17995                                        text_style = text_style.highlight(highlight_style);
17996                                    }
17997                                    div()
17998                                        .block_mouse_except_scroll()
17999                                        .pl(cx.anchor_x)
18000                                        .child(EditorElement::new(
18001                                            &rename_editor,
18002                                            EditorStyle {
18003                                                background: cx.theme().system().transparent,
18004                                                local_player: cx.editor_style.local_player,
18005                                                text: text_style,
18006                                                scrollbar_width: cx.editor_style.scrollbar_width,
18007                                                syntax: cx.editor_style.syntax.clone(),
18008                                                status: cx.editor_style.status.clone(),
18009                                                inlay_hints_style: HighlightStyle {
18010                                                    font_weight: Some(FontWeight::BOLD),
18011                                                    ..make_inlay_hints_style(cx.app)
18012                                                },
18013                                                edit_prediction_styles: make_suggestion_styles(
18014                                                    cx.app,
18015                                                ),
18016                                                ..EditorStyle::default()
18017                                            },
18018                                        ))
18019                                        .into_any_element()
18020                                }
18021                            }),
18022                            priority: 0,
18023                        }],
18024                        Some(Autoscroll::fit()),
18025                        cx,
18026                    )[0];
18027                    this.pending_rename = Some(RenameState {
18028                        range,
18029                        old_name,
18030                        editor: rename_editor,
18031                        block_id,
18032                    });
18033                })?;
18034            }
18035
18036            Ok(())
18037        }))
18038    }
18039
18040    pub fn confirm_rename(
18041        &mut self,
18042        _: &ConfirmRename,
18043        window: &mut Window,
18044        cx: &mut Context<Self>,
18045    ) -> Option<Task<Result<()>>> {
18046        let rename = self.take_rename(false, window, cx)?;
18047        let workspace = self.workspace()?.downgrade();
18048        let (buffer, start) = self
18049            .buffer
18050            .read(cx)
18051            .text_anchor_for_position(rename.range.start, cx)?;
18052        let (end_buffer, _) = self
18053            .buffer
18054            .read(cx)
18055            .text_anchor_for_position(rename.range.end, cx)?;
18056        if buffer != end_buffer {
18057            return None;
18058        }
18059
18060        let old_name = rename.old_name;
18061        let new_name = rename.editor.read(cx).text(cx);
18062
18063        let rename = self.semantics_provider.as_ref()?.perform_rename(
18064            &buffer,
18065            start,
18066            new_name.clone(),
18067            cx,
18068        )?;
18069
18070        Some(cx.spawn_in(window, async move |editor, cx| {
18071            let project_transaction = rename.await?;
18072            Self::open_project_transaction(
18073                &editor,
18074                workspace,
18075                project_transaction,
18076                format!("Rename: {}{}", old_name, new_name),
18077                cx,
18078            )
18079            .await?;
18080
18081            editor.update(cx, |editor, cx| {
18082                editor.refresh_document_highlights(cx);
18083            })?;
18084            Ok(())
18085        }))
18086    }
18087
18088    fn take_rename(
18089        &mut self,
18090        moving_cursor: bool,
18091        window: &mut Window,
18092        cx: &mut Context<Self>,
18093    ) -> Option<RenameState> {
18094        let rename = self.pending_rename.take()?;
18095        if rename.editor.focus_handle(cx).is_focused(window) {
18096            window.focus(&self.focus_handle, cx);
18097        }
18098
18099        self.remove_blocks(
18100            [rename.block_id].into_iter().collect(),
18101            Some(Autoscroll::fit()),
18102            cx,
18103        );
18104        self.clear_highlights::<Rename>(cx);
18105        self.show_local_selections = true;
18106
18107        if moving_cursor {
18108            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18109                editor
18110                    .selections
18111                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18112                    .head()
18113            });
18114
18115            // Update the selection to match the position of the selection inside
18116            // the rename editor.
18117            let snapshot = self.buffer.read(cx).read(cx);
18118            let rename_range = rename.range.to_offset(&snapshot);
18119            let cursor_in_editor = snapshot
18120                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18121                .min(rename_range.end);
18122            drop(snapshot);
18123
18124            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18125                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18126            });
18127        } else {
18128            self.refresh_document_highlights(cx);
18129        }
18130
18131        Some(rename)
18132    }
18133
18134    pub fn pending_rename(&self) -> Option<&RenameState> {
18135        self.pending_rename.as_ref()
18136    }
18137
18138    fn format(
18139        &mut self,
18140        _: &Format,
18141        window: &mut Window,
18142        cx: &mut Context<Self>,
18143    ) -> Option<Task<Result<()>>> {
18144        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18145
18146        let project = match &self.project {
18147            Some(project) => project.clone(),
18148            None => return None,
18149        };
18150
18151        Some(self.perform_format(
18152            project,
18153            FormatTrigger::Manual,
18154            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18155            window,
18156            cx,
18157        ))
18158    }
18159
18160    fn format_selections(
18161        &mut self,
18162        _: &FormatSelections,
18163        window: &mut Window,
18164        cx: &mut Context<Self>,
18165    ) -> Option<Task<Result<()>>> {
18166        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18167
18168        let project = match &self.project {
18169            Some(project) => project.clone(),
18170            None => return None,
18171        };
18172
18173        let ranges = self
18174            .selections
18175            .all_adjusted(&self.display_snapshot(cx))
18176            .into_iter()
18177            .map(|selection| selection.range())
18178            .collect_vec();
18179
18180        Some(self.perform_format(
18181            project,
18182            FormatTrigger::Manual,
18183            FormatTarget::Ranges(ranges),
18184            window,
18185            cx,
18186        ))
18187    }
18188
18189    fn perform_format(
18190        &mut self,
18191        project: Entity<Project>,
18192        trigger: FormatTrigger,
18193        target: FormatTarget,
18194        window: &mut Window,
18195        cx: &mut Context<Self>,
18196    ) -> Task<Result<()>> {
18197        let buffer = self.buffer.clone();
18198        let (buffers, target) = match target {
18199            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18200            FormatTarget::Ranges(selection_ranges) => {
18201                let multi_buffer = buffer.read(cx);
18202                let snapshot = multi_buffer.read(cx);
18203                let mut buffers = HashSet::default();
18204                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18205                    BTreeMap::new();
18206                for selection_range in selection_ranges {
18207                    for (buffer, buffer_range, _) in
18208                        snapshot.range_to_buffer_ranges(selection_range)
18209                    {
18210                        let buffer_id = buffer.remote_id();
18211                        let start = buffer.anchor_before(buffer_range.start);
18212                        let end = buffer.anchor_after(buffer_range.end);
18213                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18214                        buffer_id_to_ranges
18215                            .entry(buffer_id)
18216                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18217                            .or_insert_with(|| vec![start..end]);
18218                    }
18219                }
18220                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18221            }
18222        };
18223
18224        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18225        let selections_prev = transaction_id_prev
18226            .and_then(|transaction_id_prev| {
18227                // default to selections as they were after the last edit, if we have them,
18228                // instead of how they are now.
18229                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18230                // will take you back to where you made the last edit, instead of staying where you scrolled
18231                self.selection_history
18232                    .transaction(transaction_id_prev)
18233                    .map(|t| t.0.clone())
18234            })
18235            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18236
18237        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18238        let format = project.update(cx, |project, cx| {
18239            project.format(buffers, target, true, trigger, cx)
18240        });
18241
18242        cx.spawn_in(window, async move |editor, cx| {
18243            let transaction = futures::select_biased! {
18244                transaction = format.log_err().fuse() => transaction,
18245                () = timeout => {
18246                    log::warn!("timed out waiting for formatting");
18247                    None
18248                }
18249            };
18250
18251            buffer
18252                .update(cx, |buffer, cx| {
18253                    if let Some(transaction) = transaction
18254                        && !buffer.is_singleton()
18255                    {
18256                        buffer.push_transaction(&transaction.0, cx);
18257                    }
18258                    cx.notify();
18259                })
18260                .ok();
18261
18262            if let Some(transaction_id_now) =
18263                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
18264            {
18265                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18266                if has_new_transaction {
18267                    _ = editor.update(cx, |editor, _| {
18268                        editor
18269                            .selection_history
18270                            .insert_transaction(transaction_id_now, selections_prev);
18271                    });
18272                }
18273            }
18274
18275            Ok(())
18276        })
18277    }
18278
18279    fn organize_imports(
18280        &mut self,
18281        _: &OrganizeImports,
18282        window: &mut Window,
18283        cx: &mut Context<Self>,
18284    ) -> Option<Task<Result<()>>> {
18285        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18286        let project = match &self.project {
18287            Some(project) => project.clone(),
18288            None => return None,
18289        };
18290        Some(self.perform_code_action_kind(
18291            project,
18292            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18293            window,
18294            cx,
18295        ))
18296    }
18297
18298    fn perform_code_action_kind(
18299        &mut self,
18300        project: Entity<Project>,
18301        kind: CodeActionKind,
18302        window: &mut Window,
18303        cx: &mut Context<Self>,
18304    ) -> Task<Result<()>> {
18305        let buffer = self.buffer.clone();
18306        let buffers = buffer.read(cx).all_buffers();
18307        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18308        let apply_action = project.update(cx, |project, cx| {
18309            project.apply_code_action_kind(buffers, kind, true, cx)
18310        });
18311        cx.spawn_in(window, async move |_, cx| {
18312            let transaction = futures::select_biased! {
18313                () = timeout => {
18314                    log::warn!("timed out waiting for executing code action");
18315                    None
18316                }
18317                transaction = apply_action.log_err().fuse() => transaction,
18318            };
18319            buffer
18320                .update(cx, |buffer, cx| {
18321                    // check if we need this
18322                    if let Some(transaction) = transaction
18323                        && !buffer.is_singleton()
18324                    {
18325                        buffer.push_transaction(&transaction.0, cx);
18326                    }
18327                    cx.notify();
18328                })
18329                .ok();
18330            Ok(())
18331        })
18332    }
18333
18334    pub fn restart_language_server(
18335        &mut self,
18336        _: &RestartLanguageServer,
18337        _: &mut Window,
18338        cx: &mut Context<Self>,
18339    ) {
18340        if let Some(project) = self.project.clone() {
18341            self.buffer.update(cx, |multi_buffer, cx| {
18342                project.update(cx, |project, cx| {
18343                    project.restart_language_servers_for_buffers(
18344                        multi_buffer.all_buffers().into_iter().collect(),
18345                        HashSet::default(),
18346                        cx,
18347                    );
18348                });
18349            })
18350        }
18351    }
18352
18353    pub fn stop_language_server(
18354        &mut self,
18355        _: &StopLanguageServer,
18356        _: &mut Window,
18357        cx: &mut Context<Self>,
18358    ) {
18359        if let Some(project) = self.project.clone() {
18360            self.buffer.update(cx, |multi_buffer, cx| {
18361                project.update(cx, |project, cx| {
18362                    project.stop_language_servers_for_buffers(
18363                        multi_buffer.all_buffers().into_iter().collect(),
18364                        HashSet::default(),
18365                        cx,
18366                    );
18367                });
18368            });
18369            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18370        }
18371    }
18372
18373    fn cancel_language_server_work(
18374        workspace: &mut Workspace,
18375        _: &actions::CancelLanguageServerWork,
18376        _: &mut Window,
18377        cx: &mut Context<Workspace>,
18378    ) {
18379        let project = workspace.project();
18380        let buffers = workspace
18381            .active_item(cx)
18382            .and_then(|item| item.act_as::<Editor>(cx))
18383            .map_or(HashSet::default(), |editor| {
18384                editor.read(cx).buffer.read(cx).all_buffers()
18385            });
18386        project.update(cx, |project, cx| {
18387            project.cancel_language_server_work_for_buffers(buffers, cx);
18388        });
18389    }
18390
18391    fn show_character_palette(
18392        &mut self,
18393        _: &ShowCharacterPalette,
18394        window: &mut Window,
18395        _: &mut Context<Self>,
18396    ) {
18397        window.show_character_palette();
18398    }
18399
18400    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18401        if !self.diagnostics_enabled() {
18402            return;
18403        }
18404
18405        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18406            let buffer = self.buffer.read(cx).snapshot(cx);
18407            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18408            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18409            let is_valid = buffer
18410                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18411                .any(|entry| {
18412                    entry.diagnostic.is_primary
18413                        && !entry.range.is_empty()
18414                        && entry.range.start == primary_range_start
18415                        && entry.diagnostic.message == active_diagnostics.active_message
18416                });
18417
18418            if !is_valid {
18419                self.dismiss_diagnostics(cx);
18420            }
18421        }
18422    }
18423
18424    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18425        match &self.active_diagnostics {
18426            ActiveDiagnostic::Group(group) => Some(group),
18427            _ => None,
18428        }
18429    }
18430
18431    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18432        if !self.diagnostics_enabled() {
18433            return;
18434        }
18435        self.dismiss_diagnostics(cx);
18436        self.active_diagnostics = ActiveDiagnostic::All;
18437    }
18438
18439    fn activate_diagnostics(
18440        &mut self,
18441        buffer_id: BufferId,
18442        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18443        window: &mut Window,
18444        cx: &mut Context<Self>,
18445    ) {
18446        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18447            return;
18448        }
18449        self.dismiss_diagnostics(cx);
18450        let snapshot = self.snapshot(window, cx);
18451        let buffer = self.buffer.read(cx).snapshot(cx);
18452        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18453            return;
18454        };
18455
18456        let diagnostic_group = buffer
18457            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18458            .collect::<Vec<_>>();
18459
18460        let language_registry = self
18461            .project()
18462            .map(|project| project.read(cx).languages().clone());
18463
18464        let blocks = renderer.render_group(
18465            diagnostic_group,
18466            buffer_id,
18467            snapshot,
18468            cx.weak_entity(),
18469            language_registry,
18470            cx,
18471        );
18472
18473        let blocks = self.display_map.update(cx, |display_map, cx| {
18474            display_map.insert_blocks(blocks, cx).into_iter().collect()
18475        });
18476        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18477            active_range: buffer.anchor_before(diagnostic.range.start)
18478                ..buffer.anchor_after(diagnostic.range.end),
18479            active_message: diagnostic.diagnostic.message.clone(),
18480            group_id: diagnostic.diagnostic.group_id,
18481            blocks,
18482        });
18483        cx.notify();
18484    }
18485
18486    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18487        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18488            return;
18489        };
18490
18491        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18492        if let ActiveDiagnostic::Group(group) = prev {
18493            self.display_map.update(cx, |display_map, cx| {
18494                display_map.remove_blocks(group.blocks, cx);
18495            });
18496            cx.notify();
18497        }
18498    }
18499
18500    /// Disable inline diagnostics rendering for this editor.
18501    pub fn disable_inline_diagnostics(&mut self) {
18502        self.inline_diagnostics_enabled = false;
18503        self.inline_diagnostics_update = Task::ready(());
18504        self.inline_diagnostics.clear();
18505    }
18506
18507    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18508        self.diagnostics_enabled = false;
18509        self.dismiss_diagnostics(cx);
18510        self.inline_diagnostics_update = Task::ready(());
18511        self.inline_diagnostics.clear();
18512    }
18513
18514    pub fn disable_word_completions(&mut self) {
18515        self.word_completions_enabled = false;
18516    }
18517
18518    pub fn diagnostics_enabled(&self) -> bool {
18519        self.diagnostics_enabled && self.mode.is_full()
18520    }
18521
18522    pub fn inline_diagnostics_enabled(&self) -> bool {
18523        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18524    }
18525
18526    pub fn show_inline_diagnostics(&self) -> bool {
18527        self.show_inline_diagnostics
18528    }
18529
18530    pub fn toggle_inline_diagnostics(
18531        &mut self,
18532        _: &ToggleInlineDiagnostics,
18533        window: &mut Window,
18534        cx: &mut Context<Editor>,
18535    ) {
18536        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18537        self.refresh_inline_diagnostics(false, window, cx);
18538    }
18539
18540    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18541        self.diagnostics_max_severity = severity;
18542        self.display_map.update(cx, |display_map, _| {
18543            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18544        });
18545    }
18546
18547    pub fn toggle_diagnostics(
18548        &mut self,
18549        _: &ToggleDiagnostics,
18550        window: &mut Window,
18551        cx: &mut Context<Editor>,
18552    ) {
18553        if !self.diagnostics_enabled() {
18554            return;
18555        }
18556
18557        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18558            EditorSettings::get_global(cx)
18559                .diagnostics_max_severity
18560                .filter(|severity| severity != &DiagnosticSeverity::Off)
18561                .unwrap_or(DiagnosticSeverity::Hint)
18562        } else {
18563            DiagnosticSeverity::Off
18564        };
18565        self.set_max_diagnostics_severity(new_severity, cx);
18566        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18567            self.active_diagnostics = ActiveDiagnostic::None;
18568            self.inline_diagnostics_update = Task::ready(());
18569            self.inline_diagnostics.clear();
18570        } else {
18571            self.refresh_inline_diagnostics(false, window, cx);
18572        }
18573
18574        cx.notify();
18575    }
18576
18577    pub fn toggle_minimap(
18578        &mut self,
18579        _: &ToggleMinimap,
18580        window: &mut Window,
18581        cx: &mut Context<Editor>,
18582    ) {
18583        if self.supports_minimap(cx) {
18584            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18585        }
18586    }
18587
18588    fn refresh_inline_diagnostics(
18589        &mut self,
18590        debounce: bool,
18591        window: &mut Window,
18592        cx: &mut Context<Self>,
18593    ) {
18594        let max_severity = ProjectSettings::get_global(cx)
18595            .diagnostics
18596            .inline
18597            .max_severity
18598            .unwrap_or(self.diagnostics_max_severity);
18599
18600        if !self.inline_diagnostics_enabled()
18601            || !self.diagnostics_enabled()
18602            || !self.show_inline_diagnostics
18603            || max_severity == DiagnosticSeverity::Off
18604        {
18605            self.inline_diagnostics_update = Task::ready(());
18606            self.inline_diagnostics.clear();
18607            return;
18608        }
18609
18610        let debounce_ms = ProjectSettings::get_global(cx)
18611            .diagnostics
18612            .inline
18613            .update_debounce_ms;
18614        let debounce = if debounce && debounce_ms > 0 {
18615            Some(Duration::from_millis(debounce_ms))
18616        } else {
18617            None
18618        };
18619        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18620            if let Some(debounce) = debounce {
18621                cx.background_executor().timer(debounce).await;
18622            }
18623            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18624                editor
18625                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18626                    .ok()
18627            }) else {
18628                return;
18629            };
18630
18631            let new_inline_diagnostics = cx
18632                .background_spawn(async move {
18633                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18634                    for diagnostic_entry in
18635                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18636                    {
18637                        let message = diagnostic_entry
18638                            .diagnostic
18639                            .message
18640                            .split_once('\n')
18641                            .map(|(line, _)| line)
18642                            .map(SharedString::new)
18643                            .unwrap_or_else(|| {
18644                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18645                            });
18646                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18647                        let (Ok(i) | Err(i)) = inline_diagnostics
18648                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18649                        inline_diagnostics.insert(
18650                            i,
18651                            (
18652                                start_anchor,
18653                                InlineDiagnostic {
18654                                    message,
18655                                    group_id: diagnostic_entry.diagnostic.group_id,
18656                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18657                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18658                                    severity: diagnostic_entry.diagnostic.severity,
18659                                },
18660                            ),
18661                        );
18662                    }
18663                    inline_diagnostics
18664                })
18665                .await;
18666
18667            editor
18668                .update(cx, |editor, cx| {
18669                    editor.inline_diagnostics = new_inline_diagnostics;
18670                    cx.notify();
18671                })
18672                .ok();
18673        });
18674    }
18675
18676    fn pull_diagnostics(
18677        &mut self,
18678        buffer_id: Option<BufferId>,
18679        window: &Window,
18680        cx: &mut Context<Self>,
18681    ) -> Option<()> {
18682        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18683            return None;
18684        }
18685        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18686            .diagnostics
18687            .lsp_pull_diagnostics;
18688        if !pull_diagnostics_settings.enabled {
18689            return None;
18690        }
18691        let project = self.project()?.downgrade();
18692
18693        let mut edited_buffer_ids = HashSet::default();
18694        let mut edited_worktree_ids = HashSet::default();
18695        let edited_buffers = match buffer_id {
18696            Some(buffer_id) => {
18697                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
18698                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
18699                edited_buffer_ids.insert(buffer.read(cx).remote_id());
18700                edited_worktree_ids.insert(worktree_id);
18701                vec![buffer]
18702            }
18703            None => self
18704                .buffer()
18705                .read(cx)
18706                .all_buffers()
18707                .into_iter()
18708                .filter(|buffer| {
18709                    let buffer = buffer.read(cx);
18710                    match buffer.file().map(|f| f.worktree_id(cx)) {
18711                        Some(worktree_id) => {
18712                            edited_buffer_ids.insert(buffer.remote_id());
18713                            edited_worktree_ids.insert(worktree_id);
18714                            true
18715                        }
18716                        None => false,
18717                    }
18718                })
18719                .collect::<Vec<_>>(),
18720        };
18721
18722        if edited_buffers.is_empty() {
18723            self.pull_diagnostics_task = Task::ready(());
18724            self.pull_diagnostics_background_task = Task::ready(());
18725            return None;
18726        }
18727
18728        let mut already_used_buffers = HashSet::default();
18729        let related_open_buffers = self
18730            .workspace
18731            .as_ref()
18732            .and_then(|(workspace, _)| workspace.upgrade())
18733            .into_iter()
18734            .flat_map(|workspace| workspace.read(cx).panes())
18735            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
18736            .filter(|editor| editor != &cx.entity())
18737            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
18738            .filter(|buffer| {
18739                let buffer = buffer.read(cx);
18740                let buffer_id = buffer.remote_id();
18741                if already_used_buffers.insert(buffer_id) {
18742                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
18743                        return !edited_buffer_ids.contains(&buffer_id)
18744                            && !edited_worktree_ids.contains(&worktree_id);
18745                    }
18746                }
18747                false
18748            })
18749            .collect::<Vec<_>>();
18750
18751        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18752        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
18753            if buffers.is_empty() {
18754                return Task::ready(());
18755            }
18756            let project_weak = project.clone();
18757            cx.spawn_in(window, async move |_, cx| {
18758                cx.background_executor().timer(delay).await;
18759
18760                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18761                    buffers
18762                        .into_iter()
18763                        .filter_map(|buffer| {
18764                            project_weak
18765                                .update(cx, |project, cx| {
18766                                    project.lsp_store().update(cx, |lsp_store, cx| {
18767                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18768                                    })
18769                                })
18770                                .ok()
18771                        })
18772                        .collect::<FuturesUnordered<_>>()
18773                }) else {
18774                    return;
18775                };
18776
18777                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18778                    if let Err(e) = pull_task {
18779                        log::error!("Failed to update project diagnostics: {e:#}");
18780                    }
18781                }
18782            })
18783        };
18784
18785        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
18786        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
18787
18788        Some(())
18789    }
18790
18791    pub fn set_selections_from_remote(
18792        &mut self,
18793        selections: Vec<Selection<Anchor>>,
18794        pending_selection: Option<Selection<Anchor>>,
18795        window: &mut Window,
18796        cx: &mut Context<Self>,
18797    ) {
18798        let old_cursor_position = self.selections.newest_anchor().head();
18799        self.selections
18800            .change_with(&self.display_snapshot(cx), |s| {
18801                s.select_anchors(selections);
18802                if let Some(pending_selection) = pending_selection {
18803                    s.set_pending(pending_selection, SelectMode::Character);
18804                } else {
18805                    s.clear_pending();
18806                }
18807            });
18808        self.selections_did_change(
18809            false,
18810            &old_cursor_position,
18811            SelectionEffects::default(),
18812            window,
18813            cx,
18814        );
18815    }
18816
18817    pub fn transact(
18818        &mut self,
18819        window: &mut Window,
18820        cx: &mut Context<Self>,
18821        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18822    ) -> Option<TransactionId> {
18823        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18824            this.start_transaction_at(Instant::now(), window, cx);
18825            update(this, window, cx);
18826            this.end_transaction_at(Instant::now(), cx)
18827        })
18828    }
18829
18830    pub fn start_transaction_at(
18831        &mut self,
18832        now: Instant,
18833        window: &mut Window,
18834        cx: &mut Context<Self>,
18835    ) -> Option<TransactionId> {
18836        self.end_selection(window, cx);
18837        if let Some(tx_id) = self
18838            .buffer
18839            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18840        {
18841            self.selection_history
18842                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18843            cx.emit(EditorEvent::TransactionBegun {
18844                transaction_id: tx_id,
18845            });
18846            Some(tx_id)
18847        } else {
18848            None
18849        }
18850    }
18851
18852    pub fn end_transaction_at(
18853        &mut self,
18854        now: Instant,
18855        cx: &mut Context<Self>,
18856    ) -> Option<TransactionId> {
18857        if let Some(transaction_id) = self
18858            .buffer
18859            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18860        {
18861            if let Some((_, end_selections)) =
18862                self.selection_history.transaction_mut(transaction_id)
18863            {
18864                *end_selections = Some(self.selections.disjoint_anchors_arc());
18865            } else {
18866                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18867            }
18868
18869            cx.emit(EditorEvent::Edited { transaction_id });
18870            Some(transaction_id)
18871        } else {
18872            None
18873        }
18874    }
18875
18876    pub fn modify_transaction_selection_history(
18877        &mut self,
18878        transaction_id: TransactionId,
18879        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18880    ) -> bool {
18881        self.selection_history
18882            .transaction_mut(transaction_id)
18883            .map(modify)
18884            .is_some()
18885    }
18886
18887    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18888        if self.selection_mark_mode {
18889            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18890                s.move_with(|_, sel| {
18891                    sel.collapse_to(sel.head(), SelectionGoal::None);
18892                });
18893            })
18894        }
18895        self.selection_mark_mode = true;
18896        cx.notify();
18897    }
18898
18899    pub fn swap_selection_ends(
18900        &mut self,
18901        _: &actions::SwapSelectionEnds,
18902        window: &mut Window,
18903        cx: &mut Context<Self>,
18904    ) {
18905        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18906            s.move_with(|_, sel| {
18907                if sel.start != sel.end {
18908                    sel.reversed = !sel.reversed
18909                }
18910            });
18911        });
18912        self.request_autoscroll(Autoscroll::newest(), cx);
18913        cx.notify();
18914    }
18915
18916    pub fn toggle_focus(
18917        workspace: &mut Workspace,
18918        _: &actions::ToggleFocus,
18919        window: &mut Window,
18920        cx: &mut Context<Workspace>,
18921    ) {
18922        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18923            return;
18924        };
18925        workspace.activate_item(&item, true, true, window, cx);
18926    }
18927
18928    pub fn toggle_fold(
18929        &mut self,
18930        _: &actions::ToggleFold,
18931        window: &mut Window,
18932        cx: &mut Context<Self>,
18933    ) {
18934        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18935            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18936            let selection = self.selections.newest::<Point>(&display_map);
18937
18938            let range = if selection.is_empty() {
18939                let point = selection.head().to_display_point(&display_map);
18940                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18941                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18942                    .to_point(&display_map);
18943                start..end
18944            } else {
18945                selection.range()
18946            };
18947            if display_map.folds_in_range(range).next().is_some() {
18948                self.unfold_lines(&Default::default(), window, cx)
18949            } else {
18950                self.fold(&Default::default(), window, cx)
18951            }
18952        } else {
18953            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18954            let buffer_ids: HashSet<_> = self
18955                .selections
18956                .disjoint_anchor_ranges()
18957                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18958                .collect();
18959
18960            let should_unfold = buffer_ids
18961                .iter()
18962                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18963
18964            for buffer_id in buffer_ids {
18965                if should_unfold {
18966                    self.unfold_buffer(buffer_id, cx);
18967                } else {
18968                    self.fold_buffer(buffer_id, cx);
18969                }
18970            }
18971        }
18972    }
18973
18974    pub fn toggle_fold_recursive(
18975        &mut self,
18976        _: &actions::ToggleFoldRecursive,
18977        window: &mut Window,
18978        cx: &mut Context<Self>,
18979    ) {
18980        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18981
18982        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18983        let range = if selection.is_empty() {
18984            let point = selection.head().to_display_point(&display_map);
18985            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18986            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18987                .to_point(&display_map);
18988            start..end
18989        } else {
18990            selection.range()
18991        };
18992        if display_map.folds_in_range(range).next().is_some() {
18993            self.unfold_recursive(&Default::default(), window, cx)
18994        } else {
18995            self.fold_recursive(&Default::default(), window, cx)
18996        }
18997    }
18998
18999    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19000        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19001            let mut to_fold = Vec::new();
19002            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19003            let selections = self.selections.all_adjusted(&display_map);
19004
19005            for selection in selections {
19006                let range = selection.range().sorted();
19007                let buffer_start_row = range.start.row;
19008
19009                if range.start.row != range.end.row {
19010                    let mut found = false;
19011                    let mut row = range.start.row;
19012                    while row <= range.end.row {
19013                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19014                        {
19015                            found = true;
19016                            row = crease.range().end.row + 1;
19017                            to_fold.push(crease);
19018                        } else {
19019                            row += 1
19020                        }
19021                    }
19022                    if found {
19023                        continue;
19024                    }
19025                }
19026
19027                for row in (0..=range.start.row).rev() {
19028                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19029                        && crease.range().end.row >= buffer_start_row
19030                    {
19031                        to_fold.push(crease);
19032                        if row <= range.start.row {
19033                            break;
19034                        }
19035                    }
19036                }
19037            }
19038
19039            self.fold_creases(to_fold, true, window, cx);
19040        } else {
19041            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19042            let buffer_ids = self
19043                .selections
19044                .disjoint_anchor_ranges()
19045                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19046                .collect::<HashSet<_>>();
19047            for buffer_id in buffer_ids {
19048                self.fold_buffer(buffer_id, cx);
19049            }
19050        }
19051    }
19052
19053    pub fn toggle_fold_all(
19054        &mut self,
19055        _: &actions::ToggleFoldAll,
19056        window: &mut Window,
19057        cx: &mut Context<Self>,
19058    ) {
19059        if self.buffer.read(cx).is_singleton() {
19060            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19061            let has_folds = display_map
19062                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19063                .next()
19064                .is_some();
19065
19066            if has_folds {
19067                self.unfold_all(&actions::UnfoldAll, window, cx);
19068            } else {
19069                self.fold_all(&actions::FoldAll, window, cx);
19070            }
19071        } else {
19072            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19073            let should_unfold = buffer_ids
19074                .iter()
19075                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19076
19077            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19078                editor
19079                    .update_in(cx, |editor, _, cx| {
19080                        for buffer_id in buffer_ids {
19081                            if should_unfold {
19082                                editor.unfold_buffer(buffer_id, cx);
19083                            } else {
19084                                editor.fold_buffer(buffer_id, cx);
19085                            }
19086                        }
19087                    })
19088                    .ok();
19089            });
19090        }
19091    }
19092
19093    fn fold_at_level(
19094        &mut self,
19095        fold_at: &FoldAtLevel,
19096        window: &mut Window,
19097        cx: &mut Context<Self>,
19098    ) {
19099        if !self.buffer.read(cx).is_singleton() {
19100            return;
19101        }
19102
19103        let fold_at_level = fold_at.0;
19104        let snapshot = self.buffer.read(cx).snapshot(cx);
19105        let mut to_fold = Vec::new();
19106        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19107
19108        let row_ranges_to_keep: Vec<Range<u32>> = self
19109            .selections
19110            .all::<Point>(&self.display_snapshot(cx))
19111            .into_iter()
19112            .map(|sel| sel.start.row..sel.end.row)
19113            .collect();
19114
19115        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19116            while start_row < end_row {
19117                match self
19118                    .snapshot(window, cx)
19119                    .crease_for_buffer_row(MultiBufferRow(start_row))
19120                {
19121                    Some(crease) => {
19122                        let nested_start_row = crease.range().start.row + 1;
19123                        let nested_end_row = crease.range().end.row;
19124
19125                        if current_level < fold_at_level {
19126                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19127                        } else if current_level == fold_at_level {
19128                            // Fold iff there is no selection completely contained within the fold region
19129                            if !row_ranges_to_keep.iter().any(|selection| {
19130                                selection.end >= nested_start_row
19131                                    && selection.start <= nested_end_row
19132                            }) {
19133                                to_fold.push(crease);
19134                            }
19135                        }
19136
19137                        start_row = nested_end_row + 1;
19138                    }
19139                    None => start_row += 1,
19140                }
19141            }
19142        }
19143
19144        self.fold_creases(to_fold, true, window, cx);
19145    }
19146
19147    pub fn fold_at_level_1(
19148        &mut self,
19149        _: &actions::FoldAtLevel1,
19150        window: &mut Window,
19151        cx: &mut Context<Self>,
19152    ) {
19153        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19154    }
19155
19156    pub fn fold_at_level_2(
19157        &mut self,
19158        _: &actions::FoldAtLevel2,
19159        window: &mut Window,
19160        cx: &mut Context<Self>,
19161    ) {
19162        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19163    }
19164
19165    pub fn fold_at_level_3(
19166        &mut self,
19167        _: &actions::FoldAtLevel3,
19168        window: &mut Window,
19169        cx: &mut Context<Self>,
19170    ) {
19171        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19172    }
19173
19174    pub fn fold_at_level_4(
19175        &mut self,
19176        _: &actions::FoldAtLevel4,
19177        window: &mut Window,
19178        cx: &mut Context<Self>,
19179    ) {
19180        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19181    }
19182
19183    pub fn fold_at_level_5(
19184        &mut self,
19185        _: &actions::FoldAtLevel5,
19186        window: &mut Window,
19187        cx: &mut Context<Self>,
19188    ) {
19189        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19190    }
19191
19192    pub fn fold_at_level_6(
19193        &mut self,
19194        _: &actions::FoldAtLevel6,
19195        window: &mut Window,
19196        cx: &mut Context<Self>,
19197    ) {
19198        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19199    }
19200
19201    pub fn fold_at_level_7(
19202        &mut self,
19203        _: &actions::FoldAtLevel7,
19204        window: &mut Window,
19205        cx: &mut Context<Self>,
19206    ) {
19207        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19208    }
19209
19210    pub fn fold_at_level_8(
19211        &mut self,
19212        _: &actions::FoldAtLevel8,
19213        window: &mut Window,
19214        cx: &mut Context<Self>,
19215    ) {
19216        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19217    }
19218
19219    pub fn fold_at_level_9(
19220        &mut self,
19221        _: &actions::FoldAtLevel9,
19222        window: &mut Window,
19223        cx: &mut Context<Self>,
19224    ) {
19225        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19226    }
19227
19228    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19229        if self.buffer.read(cx).is_singleton() {
19230            let mut fold_ranges = Vec::new();
19231            let snapshot = self.buffer.read(cx).snapshot(cx);
19232
19233            for row in 0..snapshot.max_row().0 {
19234                if let Some(foldable_range) = self
19235                    .snapshot(window, cx)
19236                    .crease_for_buffer_row(MultiBufferRow(row))
19237                {
19238                    fold_ranges.push(foldable_range);
19239                }
19240            }
19241
19242            self.fold_creases(fold_ranges, true, window, cx);
19243        } else {
19244            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19245                editor
19246                    .update_in(cx, |editor, _, cx| {
19247                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19248                            editor.fold_buffer(buffer_id, cx);
19249                        }
19250                    })
19251                    .ok();
19252            });
19253        }
19254    }
19255
19256    pub fn fold_function_bodies(
19257        &mut self,
19258        _: &actions::FoldFunctionBodies,
19259        window: &mut Window,
19260        cx: &mut Context<Self>,
19261    ) {
19262        let snapshot = self.buffer.read(cx).snapshot(cx);
19263
19264        let ranges = snapshot
19265            .text_object_ranges(
19266                MultiBufferOffset(0)..snapshot.len(),
19267                TreeSitterOptions::default(),
19268            )
19269            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19270            .collect::<Vec<_>>();
19271
19272        let creases = ranges
19273            .into_iter()
19274            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19275            .collect();
19276
19277        self.fold_creases(creases, true, window, cx);
19278    }
19279
19280    pub fn fold_recursive(
19281        &mut self,
19282        _: &actions::FoldRecursive,
19283        window: &mut Window,
19284        cx: &mut Context<Self>,
19285    ) {
19286        let mut to_fold = Vec::new();
19287        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19288        let selections = self.selections.all_adjusted(&display_map);
19289
19290        for selection in selections {
19291            let range = selection.range().sorted();
19292            let buffer_start_row = range.start.row;
19293
19294            if range.start.row != range.end.row {
19295                let mut found = false;
19296                for row in range.start.row..=range.end.row {
19297                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19298                        found = true;
19299                        to_fold.push(crease);
19300                    }
19301                }
19302                if found {
19303                    continue;
19304                }
19305            }
19306
19307            for row in (0..=range.start.row).rev() {
19308                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19309                    if crease.range().end.row >= buffer_start_row {
19310                        to_fold.push(crease);
19311                    } else {
19312                        break;
19313                    }
19314                }
19315            }
19316        }
19317
19318        self.fold_creases(to_fold, true, window, cx);
19319    }
19320
19321    pub fn fold_at(
19322        &mut self,
19323        buffer_row: MultiBufferRow,
19324        window: &mut Window,
19325        cx: &mut Context<Self>,
19326    ) {
19327        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19328
19329        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19330            let autoscroll = self
19331                .selections
19332                .all::<Point>(&display_map)
19333                .iter()
19334                .any(|selection| crease.range().overlaps(&selection.range()));
19335
19336            self.fold_creases(vec![crease], autoscroll, window, cx);
19337        }
19338    }
19339
19340    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19341        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19342            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19343            let buffer = display_map.buffer_snapshot();
19344            let selections = self.selections.all::<Point>(&display_map);
19345            let ranges = selections
19346                .iter()
19347                .map(|s| {
19348                    let range = s.display_range(&display_map).sorted();
19349                    let mut start = range.start.to_point(&display_map);
19350                    let mut end = range.end.to_point(&display_map);
19351                    start.column = 0;
19352                    end.column = buffer.line_len(MultiBufferRow(end.row));
19353                    start..end
19354                })
19355                .collect::<Vec<_>>();
19356
19357            self.unfold_ranges(&ranges, true, true, cx);
19358        } else {
19359            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19360            let buffer_ids = self
19361                .selections
19362                .disjoint_anchor_ranges()
19363                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19364                .collect::<HashSet<_>>();
19365            for buffer_id in buffer_ids {
19366                self.unfold_buffer(buffer_id, cx);
19367            }
19368        }
19369    }
19370
19371    pub fn unfold_recursive(
19372        &mut self,
19373        _: &UnfoldRecursive,
19374        _window: &mut Window,
19375        cx: &mut Context<Self>,
19376    ) {
19377        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19378        let selections = self.selections.all::<Point>(&display_map);
19379        let ranges = selections
19380            .iter()
19381            .map(|s| {
19382                let mut range = s.display_range(&display_map).sorted();
19383                *range.start.column_mut() = 0;
19384                *range.end.column_mut() = display_map.line_len(range.end.row());
19385                let start = range.start.to_point(&display_map);
19386                let end = range.end.to_point(&display_map);
19387                start..end
19388            })
19389            .collect::<Vec<_>>();
19390
19391        self.unfold_ranges(&ranges, true, true, cx);
19392    }
19393
19394    pub fn unfold_at(
19395        &mut self,
19396        buffer_row: MultiBufferRow,
19397        _window: &mut Window,
19398        cx: &mut Context<Self>,
19399    ) {
19400        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19401
19402        let intersection_range = Point::new(buffer_row.0, 0)
19403            ..Point::new(
19404                buffer_row.0,
19405                display_map.buffer_snapshot().line_len(buffer_row),
19406            );
19407
19408        let autoscroll = self
19409            .selections
19410            .all::<Point>(&display_map)
19411            .iter()
19412            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19413
19414        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19415    }
19416
19417    pub fn unfold_all(
19418        &mut self,
19419        _: &actions::UnfoldAll,
19420        _window: &mut Window,
19421        cx: &mut Context<Self>,
19422    ) {
19423        if self.buffer.read(cx).is_singleton() {
19424            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19425            self.unfold_ranges(
19426                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19427                true,
19428                true,
19429                cx,
19430            );
19431        } else {
19432            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19433                editor
19434                    .update(cx, |editor, cx| {
19435                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19436                            editor.unfold_buffer(buffer_id, cx);
19437                        }
19438                    })
19439                    .ok();
19440            });
19441        }
19442    }
19443
19444    pub fn fold_selected_ranges(
19445        &mut self,
19446        _: &FoldSelectedRanges,
19447        window: &mut Window,
19448        cx: &mut Context<Self>,
19449    ) {
19450        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19451        let selections = self.selections.all_adjusted(&display_map);
19452        let ranges = selections
19453            .into_iter()
19454            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19455            .collect::<Vec<_>>();
19456        self.fold_creases(ranges, true, window, cx);
19457    }
19458
19459    pub fn fold_ranges<T: ToOffset + Clone>(
19460        &mut self,
19461        ranges: Vec<Range<T>>,
19462        auto_scroll: bool,
19463        window: &mut Window,
19464        cx: &mut Context<Self>,
19465    ) {
19466        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19467        let ranges = ranges
19468            .into_iter()
19469            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19470            .collect::<Vec<_>>();
19471        self.fold_creases(ranges, auto_scroll, window, cx);
19472    }
19473
19474    pub fn fold_creases<T: ToOffset + Clone>(
19475        &mut self,
19476        creases: Vec<Crease<T>>,
19477        auto_scroll: bool,
19478        _window: &mut Window,
19479        cx: &mut Context<Self>,
19480    ) {
19481        if creases.is_empty() {
19482            return;
19483        }
19484
19485        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19486
19487        if auto_scroll {
19488            self.request_autoscroll(Autoscroll::fit(), cx);
19489        }
19490
19491        cx.notify();
19492
19493        self.scrollbar_marker_state.dirty = true;
19494        self.folds_did_change(cx);
19495    }
19496
19497    /// Removes any folds whose ranges intersect any of the given ranges.
19498    pub fn unfold_ranges<T: ToOffset + Clone>(
19499        &mut self,
19500        ranges: &[Range<T>],
19501        inclusive: bool,
19502        auto_scroll: bool,
19503        cx: &mut Context<Self>,
19504    ) {
19505        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19506            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19507        });
19508        self.folds_did_change(cx);
19509    }
19510
19511    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19512        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19513            return;
19514        }
19515
19516        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19517        self.display_map.update(cx, |display_map, cx| {
19518            display_map.fold_buffers([buffer_id], cx)
19519        });
19520
19521        let snapshot = self.display_snapshot(cx);
19522        self.selections.change_with(&snapshot, |selections| {
19523            selections.remove_selections_from_buffer(buffer_id);
19524        });
19525
19526        cx.emit(EditorEvent::BufferFoldToggled {
19527            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19528            folded: true,
19529        });
19530        cx.notify();
19531    }
19532
19533    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19534        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19535            return;
19536        }
19537        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19538        self.display_map.update(cx, |display_map, cx| {
19539            display_map.unfold_buffers([buffer_id], cx);
19540        });
19541        cx.emit(EditorEvent::BufferFoldToggled {
19542            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19543            folded: false,
19544        });
19545        cx.notify();
19546    }
19547
19548    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19549        self.display_map.read(cx).is_buffer_folded(buffer)
19550    }
19551
19552    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19553        self.display_map.read(cx).folded_buffers()
19554    }
19555
19556    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19557        self.display_map.update(cx, |display_map, cx| {
19558            display_map.disable_header_for_buffer(buffer_id, cx);
19559        });
19560        cx.notify();
19561    }
19562
19563    /// Removes any folds with the given ranges.
19564    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19565        &mut self,
19566        ranges: &[Range<T>],
19567        type_id: TypeId,
19568        auto_scroll: bool,
19569        cx: &mut Context<Self>,
19570    ) {
19571        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19572            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19573        });
19574        self.folds_did_change(cx);
19575    }
19576
19577    fn remove_folds_with<T: ToOffset + Clone>(
19578        &mut self,
19579        ranges: &[Range<T>],
19580        auto_scroll: bool,
19581        cx: &mut Context<Self>,
19582        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19583    ) {
19584        if ranges.is_empty() {
19585            return;
19586        }
19587
19588        let mut buffers_affected = HashSet::default();
19589        let multi_buffer = self.buffer().read(cx);
19590        for range in ranges {
19591            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19592                buffers_affected.insert(buffer.read(cx).remote_id());
19593            };
19594        }
19595
19596        self.display_map.update(cx, update);
19597
19598        if auto_scroll {
19599            self.request_autoscroll(Autoscroll::fit(), cx);
19600        }
19601
19602        cx.notify();
19603        self.scrollbar_marker_state.dirty = true;
19604        self.active_indent_guides_state.dirty = true;
19605    }
19606
19607    pub fn update_renderer_widths(
19608        &mut self,
19609        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19610        cx: &mut Context<Self>,
19611    ) -> bool {
19612        self.display_map
19613            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19614    }
19615
19616    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19617        self.display_map.read(cx).fold_placeholder.clone()
19618    }
19619
19620    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19621        self.use_base_text_line_numbers = show;
19622    }
19623
19624    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19625        self.buffer.update(cx, |buffer, cx| {
19626            buffer.set_all_diff_hunks_expanded(cx);
19627        });
19628    }
19629
19630    pub fn expand_all_diff_hunks(
19631        &mut self,
19632        _: &ExpandAllDiffHunks,
19633        _window: &mut Window,
19634        cx: &mut Context<Self>,
19635    ) {
19636        self.buffer.update(cx, |buffer, cx| {
19637            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19638        });
19639    }
19640
19641    pub fn collapse_all_diff_hunks(
19642        &mut self,
19643        _: &CollapseAllDiffHunks,
19644        _window: &mut Window,
19645        cx: &mut Context<Self>,
19646    ) {
19647        self.buffer.update(cx, |buffer, cx| {
19648            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19649        });
19650    }
19651
19652    pub fn toggle_selected_diff_hunks(
19653        &mut self,
19654        _: &ToggleSelectedDiffHunks,
19655        _window: &mut Window,
19656        cx: &mut Context<Self>,
19657    ) {
19658        let ranges: Vec<_> = self
19659            .selections
19660            .disjoint_anchors()
19661            .iter()
19662            .map(|s| s.range())
19663            .collect();
19664        self.toggle_diff_hunks_in_ranges(ranges, cx);
19665    }
19666
19667    pub fn diff_hunks_in_ranges<'a>(
19668        &'a self,
19669        ranges: &'a [Range<Anchor>],
19670        buffer: &'a MultiBufferSnapshot,
19671    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19672        ranges.iter().flat_map(move |range| {
19673            let end_excerpt_id = range.end.excerpt_id;
19674            let range = range.to_point(buffer);
19675            let mut peek_end = range.end;
19676            if range.end.row < buffer.max_row().0 {
19677                peek_end = Point::new(range.end.row + 1, 0);
19678            }
19679            buffer
19680                .diff_hunks_in_range(range.start..peek_end)
19681                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19682        })
19683    }
19684
19685    pub fn has_stageable_diff_hunks_in_ranges(
19686        &self,
19687        ranges: &[Range<Anchor>],
19688        snapshot: &MultiBufferSnapshot,
19689    ) -> bool {
19690        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19691        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19692    }
19693
19694    pub fn toggle_staged_selected_diff_hunks(
19695        &mut self,
19696        _: &::git::ToggleStaged,
19697        _: &mut Window,
19698        cx: &mut Context<Self>,
19699    ) {
19700        let snapshot = self.buffer.read(cx).snapshot(cx);
19701        let ranges: Vec<_> = self
19702            .selections
19703            .disjoint_anchors()
19704            .iter()
19705            .map(|s| s.range())
19706            .collect();
19707        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19708        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19709    }
19710
19711    pub fn set_render_diff_hunk_controls(
19712        &mut self,
19713        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19714        cx: &mut Context<Self>,
19715    ) {
19716        self.render_diff_hunk_controls = render_diff_hunk_controls;
19717        cx.notify();
19718    }
19719
19720    pub fn stage_and_next(
19721        &mut self,
19722        _: &::git::StageAndNext,
19723        window: &mut Window,
19724        cx: &mut Context<Self>,
19725    ) {
19726        self.do_stage_or_unstage_and_next(true, window, cx);
19727    }
19728
19729    pub fn unstage_and_next(
19730        &mut self,
19731        _: &::git::UnstageAndNext,
19732        window: &mut Window,
19733        cx: &mut Context<Self>,
19734    ) {
19735        self.do_stage_or_unstage_and_next(false, window, cx);
19736    }
19737
19738    pub fn stage_or_unstage_diff_hunks(
19739        &mut self,
19740        stage: bool,
19741        ranges: Vec<Range<Anchor>>,
19742        cx: &mut Context<Self>,
19743    ) {
19744        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19745        cx.spawn(async move |this, cx| {
19746            task.await?;
19747            this.update(cx, |this, cx| {
19748                let snapshot = this.buffer.read(cx).snapshot(cx);
19749                let chunk_by = this
19750                    .diff_hunks_in_ranges(&ranges, &snapshot)
19751                    .chunk_by(|hunk| hunk.buffer_id);
19752                for (buffer_id, hunks) in &chunk_by {
19753                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19754                }
19755            })
19756        })
19757        .detach_and_log_err(cx);
19758    }
19759
19760    fn save_buffers_for_ranges_if_needed(
19761        &mut self,
19762        ranges: &[Range<Anchor>],
19763        cx: &mut Context<Editor>,
19764    ) -> Task<Result<()>> {
19765        let multibuffer = self.buffer.read(cx);
19766        let snapshot = multibuffer.read(cx);
19767        let buffer_ids: HashSet<_> = ranges
19768            .iter()
19769            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19770            .collect();
19771        drop(snapshot);
19772
19773        let mut buffers = HashSet::default();
19774        for buffer_id in buffer_ids {
19775            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19776                let buffer = buffer_entity.read(cx);
19777                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19778                {
19779                    buffers.insert(buffer_entity);
19780                }
19781            }
19782        }
19783
19784        if let Some(project) = &self.project {
19785            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19786        } else {
19787            Task::ready(Ok(()))
19788        }
19789    }
19790
19791    fn do_stage_or_unstage_and_next(
19792        &mut self,
19793        stage: bool,
19794        window: &mut Window,
19795        cx: &mut Context<Self>,
19796    ) {
19797        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19798
19799        if ranges.iter().any(|range| range.start != range.end) {
19800            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19801            return;
19802        }
19803
19804        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19805        let snapshot = self.snapshot(window, cx);
19806        let position = self
19807            .selections
19808            .newest::<Point>(&snapshot.display_snapshot)
19809            .head();
19810        let mut row = snapshot
19811            .buffer_snapshot()
19812            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19813            .find(|hunk| hunk.row_range.start.0 > position.row)
19814            .map(|hunk| hunk.row_range.start);
19815
19816        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19817        // Outside of the project diff editor, wrap around to the beginning.
19818        if !all_diff_hunks_expanded {
19819            row = row.or_else(|| {
19820                snapshot
19821                    .buffer_snapshot()
19822                    .diff_hunks_in_range(Point::zero()..position)
19823                    .find(|hunk| hunk.row_range.end.0 < position.row)
19824                    .map(|hunk| hunk.row_range.start)
19825            });
19826        }
19827
19828        if let Some(row) = row {
19829            let destination = Point::new(row.0, 0);
19830            let autoscroll = Autoscroll::center();
19831
19832            self.unfold_ranges(&[destination..destination], false, false, cx);
19833            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19834                s.select_ranges([destination..destination]);
19835            });
19836        }
19837    }
19838
19839    fn do_stage_or_unstage(
19840        &self,
19841        stage: bool,
19842        buffer_id: BufferId,
19843        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19844        cx: &mut App,
19845    ) -> Option<()> {
19846        let project = self.project()?;
19847        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19848        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19849        let buffer_snapshot = buffer.read(cx).snapshot();
19850        let file_exists = buffer_snapshot
19851            .file()
19852            .is_some_and(|file| file.disk_state().exists());
19853        diff.update(cx, |diff, cx| {
19854            diff.stage_or_unstage_hunks(
19855                stage,
19856                &hunks
19857                    .map(|hunk| buffer_diff::DiffHunk {
19858                        buffer_range: hunk.buffer_range,
19859                        // We don't need to pass in word diffs here because they're only used for rendering and
19860                        // this function changes internal state
19861                        base_word_diffs: Vec::default(),
19862                        buffer_word_diffs: Vec::default(),
19863                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19864                            ..hunk.diff_base_byte_range.end.0,
19865                        secondary_status: hunk.secondary_status,
19866                        range: Point::zero()..Point::zero(), // unused
19867                    })
19868                    .collect::<Vec<_>>(),
19869                &buffer_snapshot,
19870                file_exists,
19871                cx,
19872            )
19873        });
19874        None
19875    }
19876
19877    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19878        let ranges: Vec<_> = self
19879            .selections
19880            .disjoint_anchors()
19881            .iter()
19882            .map(|s| s.range())
19883            .collect();
19884        self.buffer
19885            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19886    }
19887
19888    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19889        self.buffer.update(cx, |buffer, cx| {
19890            let ranges = vec![Anchor::min()..Anchor::max()];
19891            if !buffer.all_diff_hunks_expanded()
19892                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19893            {
19894                buffer.collapse_diff_hunks(ranges, cx);
19895                true
19896            } else {
19897                false
19898            }
19899        })
19900    }
19901
19902    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19903        if self.buffer.read(cx).all_diff_hunks_expanded() {
19904            return true;
19905        }
19906        let ranges = vec![Anchor::min()..Anchor::max()];
19907        self.buffer
19908            .read(cx)
19909            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19910    }
19911
19912    fn toggle_diff_hunks_in_ranges(
19913        &mut self,
19914        ranges: Vec<Range<Anchor>>,
19915        cx: &mut Context<Editor>,
19916    ) {
19917        self.buffer.update(cx, |buffer, cx| {
19918            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19919            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19920        })
19921    }
19922
19923    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19924        self.buffer.update(cx, |buffer, cx| {
19925            let snapshot = buffer.snapshot(cx);
19926            let excerpt_id = range.end.excerpt_id;
19927            let point_range = range.to_point(&snapshot);
19928            let expand = !buffer.single_hunk_is_expanded(range, cx);
19929            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19930        })
19931    }
19932
19933    pub(crate) fn apply_all_diff_hunks(
19934        &mut self,
19935        _: &ApplyAllDiffHunks,
19936        window: &mut Window,
19937        cx: &mut Context<Self>,
19938    ) {
19939        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19940
19941        let buffers = self.buffer.read(cx).all_buffers();
19942        for branch_buffer in buffers {
19943            branch_buffer.update(cx, |branch_buffer, cx| {
19944                branch_buffer.merge_into_base(Vec::new(), cx);
19945            });
19946        }
19947
19948        if let Some(project) = self.project.clone() {
19949            self.save(
19950                SaveOptions {
19951                    format: true,
19952                    autosave: false,
19953                },
19954                project,
19955                window,
19956                cx,
19957            )
19958            .detach_and_log_err(cx);
19959        }
19960    }
19961
19962    pub(crate) fn apply_selected_diff_hunks(
19963        &mut self,
19964        _: &ApplyDiffHunk,
19965        window: &mut Window,
19966        cx: &mut Context<Self>,
19967    ) {
19968        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19969        let snapshot = self.snapshot(window, cx);
19970        let hunks = snapshot.hunks_for_ranges(
19971            self.selections
19972                .all(&snapshot.display_snapshot)
19973                .into_iter()
19974                .map(|selection| selection.range()),
19975        );
19976        let mut ranges_by_buffer = HashMap::default();
19977        self.transact(window, cx, |editor, _window, cx| {
19978            for hunk in hunks {
19979                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19980                    ranges_by_buffer
19981                        .entry(buffer.clone())
19982                        .or_insert_with(Vec::new)
19983                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19984                }
19985            }
19986
19987            for (buffer, ranges) in ranges_by_buffer {
19988                buffer.update(cx, |buffer, cx| {
19989                    buffer.merge_into_base(ranges, cx);
19990                });
19991            }
19992        });
19993
19994        if let Some(project) = self.project.clone() {
19995            self.save(
19996                SaveOptions {
19997                    format: true,
19998                    autosave: false,
19999                },
20000                project,
20001                window,
20002                cx,
20003            )
20004            .detach_and_log_err(cx);
20005        }
20006    }
20007
20008    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20009        if hovered != self.gutter_hovered {
20010            self.gutter_hovered = hovered;
20011            cx.notify();
20012        }
20013    }
20014
20015    pub fn insert_blocks(
20016        &mut self,
20017        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20018        autoscroll: Option<Autoscroll>,
20019        cx: &mut Context<Self>,
20020    ) -> Vec<CustomBlockId> {
20021        let blocks = self
20022            .display_map
20023            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20024        if let Some(autoscroll) = autoscroll {
20025            self.request_autoscroll(autoscroll, cx);
20026        }
20027        cx.notify();
20028        blocks
20029    }
20030
20031    pub fn resize_blocks(
20032        &mut self,
20033        heights: HashMap<CustomBlockId, u32>,
20034        autoscroll: Option<Autoscroll>,
20035        cx: &mut Context<Self>,
20036    ) {
20037        self.display_map
20038            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20039        if let Some(autoscroll) = autoscroll {
20040            self.request_autoscroll(autoscroll, cx);
20041        }
20042        cx.notify();
20043    }
20044
20045    pub fn replace_blocks(
20046        &mut self,
20047        renderers: HashMap<CustomBlockId, RenderBlock>,
20048        autoscroll: Option<Autoscroll>,
20049        cx: &mut Context<Self>,
20050    ) {
20051        self.display_map
20052            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20053        if let Some(autoscroll) = autoscroll {
20054            self.request_autoscroll(autoscroll, cx);
20055        }
20056        cx.notify();
20057    }
20058
20059    pub fn remove_blocks(
20060        &mut self,
20061        block_ids: HashSet<CustomBlockId>,
20062        autoscroll: Option<Autoscroll>,
20063        cx: &mut Context<Self>,
20064    ) {
20065        self.display_map.update(cx, |display_map, cx| {
20066            display_map.remove_blocks(block_ids, cx)
20067        });
20068        if let Some(autoscroll) = autoscroll {
20069            self.request_autoscroll(autoscroll, cx);
20070        }
20071        cx.notify();
20072    }
20073
20074    pub fn row_for_block(
20075        &self,
20076        block_id: CustomBlockId,
20077        cx: &mut Context<Self>,
20078    ) -> Option<DisplayRow> {
20079        self.display_map
20080            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20081    }
20082
20083    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20084        self.focused_block = Some(focused_block);
20085    }
20086
20087    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20088        self.focused_block.take()
20089    }
20090
20091    pub fn insert_creases(
20092        &mut self,
20093        creases: impl IntoIterator<Item = Crease<Anchor>>,
20094        cx: &mut Context<Self>,
20095    ) -> Vec<CreaseId> {
20096        self.display_map
20097            .update(cx, |map, cx| map.insert_creases(creases, cx))
20098    }
20099
20100    pub fn remove_creases(
20101        &mut self,
20102        ids: impl IntoIterator<Item = CreaseId>,
20103        cx: &mut Context<Self>,
20104    ) -> Vec<(CreaseId, Range<Anchor>)> {
20105        self.display_map
20106            .update(cx, |map, cx| map.remove_creases(ids, cx))
20107    }
20108
20109    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20110        self.display_map
20111            .update(cx, |map, cx| map.snapshot(cx))
20112            .longest_row()
20113    }
20114
20115    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20116        self.display_map
20117            .update(cx, |map, cx| map.snapshot(cx))
20118            .max_point()
20119    }
20120
20121    pub fn text(&self, cx: &App) -> String {
20122        self.buffer.read(cx).read(cx).text()
20123    }
20124
20125    pub fn is_empty(&self, cx: &App) -> bool {
20126        self.buffer.read(cx).read(cx).is_empty()
20127    }
20128
20129    pub fn text_option(&self, cx: &App) -> Option<String> {
20130        let text = self.text(cx);
20131        let text = text.trim();
20132
20133        if text.is_empty() {
20134            return None;
20135        }
20136
20137        Some(text.to_string())
20138    }
20139
20140    pub fn set_text(
20141        &mut self,
20142        text: impl Into<Arc<str>>,
20143        window: &mut Window,
20144        cx: &mut Context<Self>,
20145    ) {
20146        self.transact(window, cx, |this, _, cx| {
20147            this.buffer
20148                .read(cx)
20149                .as_singleton()
20150                .expect("you can only call set_text on editors for singleton buffers")
20151                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20152        });
20153    }
20154
20155    pub fn display_text(&self, cx: &mut App) -> String {
20156        self.display_map
20157            .update(cx, |map, cx| map.snapshot(cx))
20158            .text()
20159    }
20160
20161    fn create_minimap(
20162        &self,
20163        minimap_settings: MinimapSettings,
20164        window: &mut Window,
20165        cx: &mut Context<Self>,
20166    ) -> Option<Entity<Self>> {
20167        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20168            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20169    }
20170
20171    fn initialize_new_minimap(
20172        &self,
20173        minimap_settings: MinimapSettings,
20174        window: &mut Window,
20175        cx: &mut Context<Self>,
20176    ) -> Entity<Self> {
20177        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20178
20179        let mut minimap = Editor::new_internal(
20180            EditorMode::Minimap {
20181                parent: cx.weak_entity(),
20182            },
20183            self.buffer.clone(),
20184            None,
20185            Some(self.display_map.clone()),
20186            window,
20187            cx,
20188        );
20189        minimap.scroll_manager.clone_state(&self.scroll_manager);
20190        minimap.set_text_style_refinement(TextStyleRefinement {
20191            font_size: Some(MINIMAP_FONT_SIZE),
20192            font_weight: Some(MINIMAP_FONT_WEIGHT),
20193            ..Default::default()
20194        });
20195        minimap.update_minimap_configuration(minimap_settings, cx);
20196        cx.new(|_| minimap)
20197    }
20198
20199    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20200        let current_line_highlight = minimap_settings
20201            .current_line_highlight
20202            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20203        self.set_current_line_highlight(Some(current_line_highlight));
20204    }
20205
20206    pub fn minimap(&self) -> Option<&Entity<Self>> {
20207        self.minimap
20208            .as_ref()
20209            .filter(|_| self.minimap_visibility.visible())
20210    }
20211
20212    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20213        let mut wrap_guides = smallvec![];
20214
20215        if self.show_wrap_guides == Some(false) {
20216            return wrap_guides;
20217        }
20218
20219        let settings = self.buffer.read(cx).language_settings(cx);
20220        if settings.show_wrap_guides {
20221            match self.soft_wrap_mode(cx) {
20222                SoftWrap::Column(soft_wrap) => {
20223                    wrap_guides.push((soft_wrap as usize, true));
20224                }
20225                SoftWrap::Bounded(soft_wrap) => {
20226                    wrap_guides.push((soft_wrap as usize, true));
20227                }
20228                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20229            }
20230            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20231        }
20232
20233        wrap_guides
20234    }
20235
20236    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20237        let settings = self.buffer.read(cx).language_settings(cx);
20238        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20239        match mode {
20240            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20241                SoftWrap::None
20242            }
20243            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20244            language_settings::SoftWrap::PreferredLineLength => {
20245                SoftWrap::Column(settings.preferred_line_length)
20246            }
20247            language_settings::SoftWrap::Bounded => {
20248                SoftWrap::Bounded(settings.preferred_line_length)
20249            }
20250        }
20251    }
20252
20253    pub fn set_soft_wrap_mode(
20254        &mut self,
20255        mode: language_settings::SoftWrap,
20256
20257        cx: &mut Context<Self>,
20258    ) {
20259        self.soft_wrap_mode_override = Some(mode);
20260        cx.notify();
20261    }
20262
20263    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20264        self.hard_wrap = hard_wrap;
20265        cx.notify();
20266    }
20267
20268    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20269        self.text_style_refinement = Some(style);
20270    }
20271
20272    /// called by the Element so we know what style we were most recently rendered with.
20273    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20274        // We intentionally do not inform the display map about the minimap style
20275        // so that wrapping is not recalculated and stays consistent for the editor
20276        // and its linked minimap.
20277        if !self.mode.is_minimap() {
20278            let font = style.text.font();
20279            let font_size = style.text.font_size.to_pixels(window.rem_size());
20280            let display_map = self
20281                .placeholder_display_map
20282                .as_ref()
20283                .filter(|_| self.is_empty(cx))
20284                .unwrap_or(&self.display_map);
20285
20286            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20287        }
20288        self.style = Some(style);
20289    }
20290
20291    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20292        if self.style.is_none() {
20293            self.style = Some(self.create_style(cx));
20294        }
20295        self.style.as_ref().unwrap()
20296    }
20297
20298    // Called by the element. This method is not designed to be called outside of the editor
20299    // element's layout code because it does not notify when rewrapping is computed synchronously.
20300    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20301        if self.is_empty(cx) {
20302            self.placeholder_display_map
20303                .as_ref()
20304                .map_or(false, |display_map| {
20305                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20306                })
20307        } else {
20308            self.display_map
20309                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20310        }
20311    }
20312
20313    pub fn set_soft_wrap(&mut self) {
20314        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20315    }
20316
20317    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20318        if self.soft_wrap_mode_override.is_some() {
20319            self.soft_wrap_mode_override.take();
20320        } else {
20321            let soft_wrap = match self.soft_wrap_mode(cx) {
20322                SoftWrap::GitDiff => return,
20323                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20324                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20325                    language_settings::SoftWrap::None
20326                }
20327            };
20328            self.soft_wrap_mode_override = Some(soft_wrap);
20329        }
20330        cx.notify();
20331    }
20332
20333    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20334        let Some(workspace) = self.workspace() else {
20335            return;
20336        };
20337        let fs = workspace.read(cx).app_state().fs.clone();
20338        let current_show = TabBarSettings::get_global(cx).show;
20339        update_settings_file(fs, cx, move |setting, _| {
20340            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20341        });
20342    }
20343
20344    pub fn toggle_indent_guides(
20345        &mut self,
20346        _: &ToggleIndentGuides,
20347        _: &mut Window,
20348        cx: &mut Context<Self>,
20349    ) {
20350        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20351            self.buffer
20352                .read(cx)
20353                .language_settings(cx)
20354                .indent_guides
20355                .enabled
20356        });
20357        self.show_indent_guides = Some(!currently_enabled);
20358        cx.notify();
20359    }
20360
20361    fn should_show_indent_guides(&self) -> Option<bool> {
20362        self.show_indent_guides
20363    }
20364
20365    pub fn disable_indent_guides_for_buffer(
20366        &mut self,
20367        buffer_id: BufferId,
20368        cx: &mut Context<Self>,
20369    ) {
20370        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20371        cx.notify();
20372    }
20373
20374    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20375        self.buffers_with_disabled_indent_guides
20376            .contains(&buffer_id)
20377    }
20378
20379    pub fn toggle_line_numbers(
20380        &mut self,
20381        _: &ToggleLineNumbers,
20382        _: &mut Window,
20383        cx: &mut Context<Self>,
20384    ) {
20385        let mut editor_settings = EditorSettings::get_global(cx).clone();
20386        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20387        EditorSettings::override_global(editor_settings, cx);
20388    }
20389
20390    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20391        if let Some(show_line_numbers) = self.show_line_numbers {
20392            return show_line_numbers;
20393        }
20394        EditorSettings::get_global(cx).gutter.line_numbers
20395    }
20396
20397    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
20398        match (
20399            self.use_relative_line_numbers,
20400            EditorSettings::get_global(cx).relative_line_numbers,
20401        ) {
20402            (None, setting) => setting,
20403            (Some(false), _) => RelativeLineNumbers::Disabled,
20404            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20405            (Some(true), _) => RelativeLineNumbers::Enabled,
20406        }
20407    }
20408
20409    pub fn toggle_relative_line_numbers(
20410        &mut self,
20411        _: &ToggleRelativeLineNumbers,
20412        _: &mut Window,
20413        cx: &mut Context<Self>,
20414    ) {
20415        let is_relative = self.relative_line_numbers(cx);
20416        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20417    }
20418
20419    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20420        self.use_relative_line_numbers = is_relative;
20421        cx.notify();
20422    }
20423
20424    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20425        self.show_gutter = show_gutter;
20426        cx.notify();
20427    }
20428
20429    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20430        self.show_scrollbars = ScrollbarAxes {
20431            horizontal: show,
20432            vertical: show,
20433        };
20434        cx.notify();
20435    }
20436
20437    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20438        self.show_scrollbars.vertical = show;
20439        cx.notify();
20440    }
20441
20442    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20443        self.show_scrollbars.horizontal = show;
20444        cx.notify();
20445    }
20446
20447    pub fn set_minimap_visibility(
20448        &mut self,
20449        minimap_visibility: MinimapVisibility,
20450        window: &mut Window,
20451        cx: &mut Context<Self>,
20452    ) {
20453        if self.minimap_visibility != minimap_visibility {
20454            if minimap_visibility.visible() && self.minimap.is_none() {
20455                let minimap_settings = EditorSettings::get_global(cx).minimap;
20456                self.minimap =
20457                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20458            }
20459            self.minimap_visibility = minimap_visibility;
20460            cx.notify();
20461        }
20462    }
20463
20464    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20465        self.set_show_scrollbars(false, cx);
20466        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20467    }
20468
20469    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20470        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20471    }
20472
20473    /// Normally the text in full mode and auto height editors is padded on the
20474    /// left side by roughly half a character width for improved hit testing.
20475    ///
20476    /// Use this method to disable this for cases where this is not wanted (e.g.
20477    /// if you want to align the editor text with some other text above or below)
20478    /// or if you want to add this padding to single-line editors.
20479    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20480        self.offset_content = offset_content;
20481        cx.notify();
20482    }
20483
20484    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20485        self.show_line_numbers = Some(show_line_numbers);
20486        cx.notify();
20487    }
20488
20489    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20490        self.disable_expand_excerpt_buttons = true;
20491        cx.notify();
20492    }
20493
20494    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20495        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20496        cx.notify();
20497    }
20498
20499    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20500        self.show_code_actions = Some(show_code_actions);
20501        cx.notify();
20502    }
20503
20504    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20505        self.show_runnables = Some(show_runnables);
20506        cx.notify();
20507    }
20508
20509    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20510        self.show_breakpoints = Some(show_breakpoints);
20511        cx.notify();
20512    }
20513
20514    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20515        if self.display_map.read(cx).masked != masked {
20516            self.display_map.update(cx, |map, _| map.masked = masked);
20517        }
20518        cx.notify()
20519    }
20520
20521    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20522        self.show_wrap_guides = Some(show_wrap_guides);
20523        cx.notify();
20524    }
20525
20526    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20527        self.show_indent_guides = Some(show_indent_guides);
20528        cx.notify();
20529    }
20530
20531    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20532        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20533            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20534                && let Some(dir) = file.abs_path(cx).parent()
20535            {
20536                return Some(dir.to_owned());
20537            }
20538        }
20539
20540        None
20541    }
20542
20543    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20544        self.active_excerpt(cx)?
20545            .1
20546            .read(cx)
20547            .file()
20548            .and_then(|f| f.as_local())
20549    }
20550
20551    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20552        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20553            let buffer = buffer.read(cx);
20554            if let Some(project_path) = buffer.project_path(cx) {
20555                let project = self.project()?.read(cx);
20556                project.absolute_path(&project_path, cx)
20557            } else {
20558                buffer
20559                    .file()
20560                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20561            }
20562        })
20563    }
20564
20565    pub fn reveal_in_finder(
20566        &mut self,
20567        _: &RevealInFileManager,
20568        _window: &mut Window,
20569        cx: &mut Context<Self>,
20570    ) {
20571        if let Some(target) = self.target_file(cx) {
20572            cx.reveal_path(&target.abs_path(cx));
20573        }
20574    }
20575
20576    pub fn copy_path(
20577        &mut self,
20578        _: &zed_actions::workspace::CopyPath,
20579        _window: &mut Window,
20580        cx: &mut Context<Self>,
20581    ) {
20582        if let Some(path) = self.target_file_abs_path(cx)
20583            && let Some(path) = path.to_str()
20584        {
20585            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20586        } else {
20587            cx.propagate();
20588        }
20589    }
20590
20591    pub fn copy_relative_path(
20592        &mut self,
20593        _: &zed_actions::workspace::CopyRelativePath,
20594        _window: &mut Window,
20595        cx: &mut Context<Self>,
20596    ) {
20597        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20598            let project = self.project()?.read(cx);
20599            let path = buffer.read(cx).file()?.path();
20600            let path = path.display(project.path_style(cx));
20601            Some(path)
20602        }) {
20603            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20604        } else {
20605            cx.propagate();
20606        }
20607    }
20608
20609    /// Returns the project path for the editor's buffer, if any buffer is
20610    /// opened in the editor.
20611    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20612        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20613            buffer.read(cx).project_path(cx)
20614        } else {
20615            None
20616        }
20617    }
20618
20619    // Returns true if the editor handled a go-to-line request
20620    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20621        maybe!({
20622            let breakpoint_store = self.breakpoint_store.as_ref()?;
20623
20624            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20625            else {
20626                self.clear_row_highlights::<ActiveDebugLine>();
20627                return None;
20628            };
20629
20630            let position = active_stack_frame.position;
20631            let buffer_id = position.buffer_id?;
20632            let snapshot = self
20633                .project
20634                .as_ref()?
20635                .read(cx)
20636                .buffer_for_id(buffer_id, cx)?
20637                .read(cx)
20638                .snapshot();
20639
20640            let mut handled = false;
20641            for (id, ExcerptRange { context, .. }) in
20642                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20643            {
20644                if context.start.cmp(&position, &snapshot).is_ge()
20645                    || context.end.cmp(&position, &snapshot).is_lt()
20646                {
20647                    continue;
20648                }
20649                let snapshot = self.buffer.read(cx).snapshot(cx);
20650                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20651
20652                handled = true;
20653                self.clear_row_highlights::<ActiveDebugLine>();
20654
20655                self.go_to_line::<ActiveDebugLine>(
20656                    multibuffer_anchor,
20657                    Some(cx.theme().colors().editor_debugger_active_line_background),
20658                    window,
20659                    cx,
20660                );
20661
20662                cx.notify();
20663            }
20664
20665            handled.then_some(())
20666        })
20667        .is_some()
20668    }
20669
20670    pub fn copy_file_name_without_extension(
20671        &mut self,
20672        _: &CopyFileNameWithoutExtension,
20673        _: &mut Window,
20674        cx: &mut Context<Self>,
20675    ) {
20676        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20677            let file = buffer.read(cx).file()?;
20678            file.path().file_stem()
20679        }) {
20680            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20681        }
20682    }
20683
20684    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20685        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20686            let file = buffer.read(cx).file()?;
20687            Some(file.file_name(cx))
20688        }) {
20689            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20690        }
20691    }
20692
20693    pub fn toggle_git_blame(
20694        &mut self,
20695        _: &::git::Blame,
20696        window: &mut Window,
20697        cx: &mut Context<Self>,
20698    ) {
20699        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20700
20701        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20702            self.start_git_blame(true, window, cx);
20703        }
20704
20705        cx.notify();
20706    }
20707
20708    pub fn toggle_git_blame_inline(
20709        &mut self,
20710        _: &ToggleGitBlameInline,
20711        window: &mut Window,
20712        cx: &mut Context<Self>,
20713    ) {
20714        self.toggle_git_blame_inline_internal(true, window, cx);
20715        cx.notify();
20716    }
20717
20718    pub fn open_git_blame_commit(
20719        &mut self,
20720        _: &OpenGitBlameCommit,
20721        window: &mut Window,
20722        cx: &mut Context<Self>,
20723    ) {
20724        self.open_git_blame_commit_internal(window, cx);
20725    }
20726
20727    fn open_git_blame_commit_internal(
20728        &mut self,
20729        window: &mut Window,
20730        cx: &mut Context<Self>,
20731    ) -> Option<()> {
20732        let blame = self.blame.as_ref()?;
20733        let snapshot = self.snapshot(window, cx);
20734        let cursor = self
20735            .selections
20736            .newest::<Point>(&snapshot.display_snapshot)
20737            .head();
20738        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20739        let (_, blame_entry) = blame
20740            .update(cx, |blame, cx| {
20741                blame
20742                    .blame_for_rows(
20743                        &[RowInfo {
20744                            buffer_id: Some(buffer.remote_id()),
20745                            buffer_row: Some(point.row),
20746                            ..Default::default()
20747                        }],
20748                        cx,
20749                    )
20750                    .next()
20751            })
20752            .flatten()?;
20753        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20754        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20755        let workspace = self.workspace()?.downgrade();
20756        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20757        None
20758    }
20759
20760    pub fn git_blame_inline_enabled(&self) -> bool {
20761        self.git_blame_inline_enabled
20762    }
20763
20764    pub fn toggle_selection_menu(
20765        &mut self,
20766        _: &ToggleSelectionMenu,
20767        _: &mut Window,
20768        cx: &mut Context<Self>,
20769    ) {
20770        self.show_selection_menu = self
20771            .show_selection_menu
20772            .map(|show_selections_menu| !show_selections_menu)
20773            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20774
20775        cx.notify();
20776    }
20777
20778    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20779        self.show_selection_menu
20780            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20781    }
20782
20783    fn start_git_blame(
20784        &mut self,
20785        user_triggered: bool,
20786        window: &mut Window,
20787        cx: &mut Context<Self>,
20788    ) {
20789        if let Some(project) = self.project() {
20790            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20791                && buffer.read(cx).file().is_none()
20792            {
20793                return;
20794            }
20795
20796            let focused = self.focus_handle(cx).contains_focused(window, cx);
20797
20798            let project = project.clone();
20799            let blame = cx
20800                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20801            self.blame_subscription =
20802                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20803            self.blame = Some(blame);
20804        }
20805    }
20806
20807    fn toggle_git_blame_inline_internal(
20808        &mut self,
20809        user_triggered: bool,
20810        window: &mut Window,
20811        cx: &mut Context<Self>,
20812    ) {
20813        if self.git_blame_inline_enabled {
20814            self.git_blame_inline_enabled = false;
20815            self.show_git_blame_inline = false;
20816            self.show_git_blame_inline_delay_task.take();
20817        } else {
20818            self.git_blame_inline_enabled = true;
20819            self.start_git_blame_inline(user_triggered, window, cx);
20820        }
20821
20822        cx.notify();
20823    }
20824
20825    fn start_git_blame_inline(
20826        &mut self,
20827        user_triggered: bool,
20828        window: &mut Window,
20829        cx: &mut Context<Self>,
20830    ) {
20831        self.start_git_blame(user_triggered, window, cx);
20832
20833        if ProjectSettings::get_global(cx)
20834            .git
20835            .inline_blame_delay()
20836            .is_some()
20837        {
20838            self.start_inline_blame_timer(window, cx);
20839        } else {
20840            self.show_git_blame_inline = true
20841        }
20842    }
20843
20844    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20845        self.blame.as_ref()
20846    }
20847
20848    pub fn show_git_blame_gutter(&self) -> bool {
20849        self.show_git_blame_gutter
20850    }
20851
20852    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20853        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20854    }
20855
20856    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20857        self.show_git_blame_inline
20858            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20859            && !self.newest_selection_head_on_empty_line(cx)
20860            && self.has_blame_entries(cx)
20861    }
20862
20863    fn has_blame_entries(&self, cx: &App) -> bool {
20864        self.blame()
20865            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20866    }
20867
20868    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20869        let cursor_anchor = self.selections.newest_anchor().head();
20870
20871        let snapshot = self.buffer.read(cx).snapshot(cx);
20872        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20873
20874        snapshot.line_len(buffer_row) == 0
20875    }
20876
20877    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20878        let buffer_and_selection = maybe!({
20879            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20880            let selection_range = selection.range();
20881
20882            let multi_buffer = self.buffer().read(cx);
20883            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20884            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20885
20886            let (buffer, range, _) = if selection.reversed {
20887                buffer_ranges.first()
20888            } else {
20889                buffer_ranges.last()
20890            }?;
20891
20892            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
20893            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
20894
20895            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
20896                let selection = start_row_in_buffer..end_row_in_buffer;
20897
20898                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
20899            };
20900
20901            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
20902
20903            Some((
20904                multi_buffer.buffer(buffer.remote_id()).unwrap(),
20905                buffer_diff_snapshot.row_to_base_text_row(start_row_in_buffer, buffer)
20906                    ..buffer_diff_snapshot.row_to_base_text_row(end_row_in_buffer, buffer),
20907            ))
20908        });
20909
20910        let Some((buffer, selection)) = buffer_and_selection else {
20911            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20912        };
20913
20914        let Some(project) = self.project() else {
20915            return Task::ready(Err(anyhow!("editor does not have project")));
20916        };
20917
20918        project.update(cx, |project, cx| {
20919            project.get_permalink_to_line(&buffer, selection, cx)
20920        })
20921    }
20922
20923    pub fn copy_permalink_to_line(
20924        &mut self,
20925        _: &CopyPermalinkToLine,
20926        window: &mut Window,
20927        cx: &mut Context<Self>,
20928    ) {
20929        let permalink_task = self.get_permalink_to_line(cx);
20930        let workspace = self.workspace();
20931
20932        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20933            Ok(permalink) => {
20934                cx.update(|_, cx| {
20935                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20936                })
20937                .ok();
20938            }
20939            Err(err) => {
20940                let message = format!("Failed to copy permalink: {err}");
20941
20942                anyhow::Result::<()>::Err(err).log_err();
20943
20944                if let Some(workspace) = workspace {
20945                    workspace
20946                        .update_in(cx, |workspace, _, cx| {
20947                            struct CopyPermalinkToLine;
20948
20949                            workspace.show_toast(
20950                                Toast::new(
20951                                    NotificationId::unique::<CopyPermalinkToLine>(),
20952                                    message,
20953                                ),
20954                                cx,
20955                            )
20956                        })
20957                        .ok();
20958                }
20959            }
20960        })
20961        .detach();
20962    }
20963
20964    pub fn copy_file_location(
20965        &mut self,
20966        _: &CopyFileLocation,
20967        _: &mut Window,
20968        cx: &mut Context<Self>,
20969    ) {
20970        let selection = self
20971            .selections
20972            .newest::<Point>(&self.display_snapshot(cx))
20973            .start
20974            .row
20975            + 1;
20976        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20977            let project = self.project()?.read(cx);
20978            let file = buffer.read(cx).file()?;
20979            let path = file.path().display(project.path_style(cx));
20980
20981            Some(format!("{path}:{selection}"))
20982        }) {
20983            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
20984        }
20985    }
20986
20987    pub fn open_permalink_to_line(
20988        &mut self,
20989        _: &OpenPermalinkToLine,
20990        window: &mut Window,
20991        cx: &mut Context<Self>,
20992    ) {
20993        let permalink_task = self.get_permalink_to_line(cx);
20994        let workspace = self.workspace();
20995
20996        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20997            Ok(permalink) => {
20998                cx.update(|_, cx| {
20999                    cx.open_url(permalink.as_ref());
21000                })
21001                .ok();
21002            }
21003            Err(err) => {
21004                let message = format!("Failed to open permalink: {err}");
21005
21006                anyhow::Result::<()>::Err(err).log_err();
21007
21008                if let Some(workspace) = workspace {
21009                    workspace
21010                        .update(cx, |workspace, cx| {
21011                            struct OpenPermalinkToLine;
21012
21013                            workspace.show_toast(
21014                                Toast::new(
21015                                    NotificationId::unique::<OpenPermalinkToLine>(),
21016                                    message,
21017                                ),
21018                                cx,
21019                            )
21020                        })
21021                        .ok();
21022                }
21023            }
21024        })
21025        .detach();
21026    }
21027
21028    pub fn insert_uuid_v4(
21029        &mut self,
21030        _: &InsertUuidV4,
21031        window: &mut Window,
21032        cx: &mut Context<Self>,
21033    ) {
21034        self.insert_uuid(UuidVersion::V4, window, cx);
21035    }
21036
21037    pub fn insert_uuid_v7(
21038        &mut self,
21039        _: &InsertUuidV7,
21040        window: &mut Window,
21041        cx: &mut Context<Self>,
21042    ) {
21043        self.insert_uuid(UuidVersion::V7, window, cx);
21044    }
21045
21046    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
21047        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21048        self.transact(window, cx, |this, window, cx| {
21049            let edits = this
21050                .selections
21051                .all::<Point>(&this.display_snapshot(cx))
21052                .into_iter()
21053                .map(|selection| {
21054                    let uuid = match version {
21055                        UuidVersion::V4 => uuid::Uuid::new_v4(),
21056                        UuidVersion::V7 => uuid::Uuid::now_v7(),
21057                    };
21058
21059                    (selection.range(), uuid.to_string())
21060                });
21061            this.edit(edits, cx);
21062            this.refresh_edit_prediction(true, false, window, cx);
21063        });
21064    }
21065
21066    pub fn open_selections_in_multibuffer(
21067        &mut self,
21068        _: &OpenSelectionsInMultibuffer,
21069        window: &mut Window,
21070        cx: &mut Context<Self>,
21071    ) {
21072        let multibuffer = self.buffer.read(cx);
21073
21074        let Some(buffer) = multibuffer.as_singleton() else {
21075            return;
21076        };
21077
21078        let Some(workspace) = self.workspace() else {
21079            return;
21080        };
21081
21082        let title = multibuffer.title(cx).to_string();
21083
21084        let locations = self
21085            .selections
21086            .all_anchors(&self.display_snapshot(cx))
21087            .iter()
21088            .map(|selection| {
21089                (
21090                    buffer.clone(),
21091                    (selection.start.text_anchor..selection.end.text_anchor)
21092                        .to_point(buffer.read(cx)),
21093                )
21094            })
21095            .into_group_map();
21096
21097        cx.spawn_in(window, async move |_, cx| {
21098            workspace.update_in(cx, |workspace, window, cx| {
21099                Self::open_locations_in_multibuffer(
21100                    workspace,
21101                    locations,
21102                    format!("Selections for '{title}'"),
21103                    false,
21104                    false,
21105                    MultibufferSelectionMode::All,
21106                    window,
21107                    cx,
21108                );
21109            })
21110        })
21111        .detach();
21112    }
21113
21114    /// Adds a row highlight for the given range. If a row has multiple highlights, the
21115    /// last highlight added will be used.
21116    ///
21117    /// If the range ends at the beginning of a line, then that line will not be highlighted.
21118    pub fn highlight_rows<T: 'static>(
21119        &mut self,
21120        range: Range<Anchor>,
21121        color: Hsla,
21122        options: RowHighlightOptions,
21123        cx: &mut Context<Self>,
21124    ) {
21125        let snapshot = self.buffer().read(cx).snapshot(cx);
21126        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21127        let ix = row_highlights.binary_search_by(|highlight| {
21128            Ordering::Equal
21129                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
21130                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
21131        });
21132
21133        if let Err(mut ix) = ix {
21134            let index = post_inc(&mut self.highlight_order);
21135
21136            // If this range intersects with the preceding highlight, then merge it with
21137            // the preceding highlight. Otherwise insert a new highlight.
21138            let mut merged = false;
21139            if ix > 0 {
21140                let prev_highlight = &mut row_highlights[ix - 1];
21141                if prev_highlight
21142                    .range
21143                    .end
21144                    .cmp(&range.start, &snapshot)
21145                    .is_ge()
21146                {
21147                    ix -= 1;
21148                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
21149                        prev_highlight.range.end = range.end;
21150                    }
21151                    merged = true;
21152                    prev_highlight.index = index;
21153                    prev_highlight.color = color;
21154                    prev_highlight.options = options;
21155                }
21156            }
21157
21158            if !merged {
21159                row_highlights.insert(
21160                    ix,
21161                    RowHighlight {
21162                        range,
21163                        index,
21164                        color,
21165                        options,
21166                        type_id: TypeId::of::<T>(),
21167                    },
21168                );
21169            }
21170
21171            // If any of the following highlights intersect with this one, merge them.
21172            while let Some(next_highlight) = row_highlights.get(ix + 1) {
21173                let highlight = &row_highlights[ix];
21174                if next_highlight
21175                    .range
21176                    .start
21177                    .cmp(&highlight.range.end, &snapshot)
21178                    .is_le()
21179                {
21180                    if next_highlight
21181                        .range
21182                        .end
21183                        .cmp(&highlight.range.end, &snapshot)
21184                        .is_gt()
21185                    {
21186                        row_highlights[ix].range.end = next_highlight.range.end;
21187                    }
21188                    row_highlights.remove(ix + 1);
21189                } else {
21190                    break;
21191                }
21192            }
21193        }
21194    }
21195
21196    /// Remove any highlighted row ranges of the given type that intersect the
21197    /// given ranges.
21198    pub fn remove_highlighted_rows<T: 'static>(
21199        &mut self,
21200        ranges_to_remove: Vec<Range<Anchor>>,
21201        cx: &mut Context<Self>,
21202    ) {
21203        let snapshot = self.buffer().read(cx).snapshot(cx);
21204        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21205        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21206        row_highlights.retain(|highlight| {
21207            while let Some(range_to_remove) = ranges_to_remove.peek() {
21208                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
21209                    Ordering::Less | Ordering::Equal => {
21210                        ranges_to_remove.next();
21211                    }
21212                    Ordering::Greater => {
21213                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
21214                            Ordering::Less | Ordering::Equal => {
21215                                return false;
21216                            }
21217                            Ordering::Greater => break,
21218                        }
21219                    }
21220                }
21221            }
21222
21223            true
21224        })
21225    }
21226
21227    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
21228    pub fn clear_row_highlights<T: 'static>(&mut self) {
21229        self.highlighted_rows.remove(&TypeId::of::<T>());
21230    }
21231
21232    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
21233    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
21234        self.highlighted_rows
21235            .get(&TypeId::of::<T>())
21236            .map_or(&[] as &[_], |vec| vec.as_slice())
21237            .iter()
21238            .map(|highlight| (highlight.range.clone(), highlight.color))
21239    }
21240
21241    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
21242    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
21243    /// Allows to ignore certain kinds of highlights.
21244    pub fn highlighted_display_rows(
21245        &self,
21246        window: &mut Window,
21247        cx: &mut App,
21248    ) -> BTreeMap<DisplayRow, LineHighlight> {
21249        let snapshot = self.snapshot(window, cx);
21250        let mut used_highlight_orders = HashMap::default();
21251        self.highlighted_rows
21252            .iter()
21253            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
21254            .fold(
21255                BTreeMap::<DisplayRow, LineHighlight>::new(),
21256                |mut unique_rows, highlight| {
21257                    let start = highlight.range.start.to_display_point(&snapshot);
21258                    let end = highlight.range.end.to_display_point(&snapshot);
21259                    let start_row = start.row().0;
21260                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
21261                    {
21262                        end.row().0.saturating_sub(1)
21263                    } else {
21264                        end.row().0
21265                    };
21266                    for row in start_row..=end_row {
21267                        let used_index =
21268                            used_highlight_orders.entry(row).or_insert(highlight.index);
21269                        if highlight.index >= *used_index {
21270                            *used_index = highlight.index;
21271                            unique_rows.insert(
21272                                DisplayRow(row),
21273                                LineHighlight {
21274                                    include_gutter: highlight.options.include_gutter,
21275                                    border: None,
21276                                    background: highlight.color.into(),
21277                                    type_id: Some(highlight.type_id),
21278                                },
21279                            );
21280                        }
21281                    }
21282                    unique_rows
21283                },
21284            )
21285    }
21286
21287    pub fn highlighted_display_row_for_autoscroll(
21288        &self,
21289        snapshot: &DisplaySnapshot,
21290    ) -> Option<DisplayRow> {
21291        self.highlighted_rows
21292            .values()
21293            .flat_map(|highlighted_rows| highlighted_rows.iter())
21294            .filter_map(|highlight| {
21295                if highlight.options.autoscroll {
21296                    Some(highlight.range.start.to_display_point(snapshot).row())
21297                } else {
21298                    None
21299                }
21300            })
21301            .min()
21302    }
21303
21304    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21305        self.highlight_background::<SearchWithinRange>(
21306            ranges,
21307            |_, colors| colors.colors().editor_document_highlight_read_background,
21308            cx,
21309        )
21310    }
21311
21312    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21313        self.breadcrumb_header = Some(new_header);
21314    }
21315
21316    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21317        self.clear_background_highlights::<SearchWithinRange>(cx);
21318    }
21319
21320    pub fn highlight_background<T: 'static>(
21321        &mut self,
21322        ranges: &[Range<Anchor>],
21323        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21324        cx: &mut Context<Self>,
21325    ) {
21326        self.background_highlights.insert(
21327            HighlightKey::Type(TypeId::of::<T>()),
21328            (Arc::new(color_fetcher), Arc::from(ranges)),
21329        );
21330        self.scrollbar_marker_state.dirty = true;
21331        cx.notify();
21332    }
21333
21334    pub fn highlight_background_key<T: 'static>(
21335        &mut self,
21336        key: usize,
21337        ranges: &[Range<Anchor>],
21338        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21339        cx: &mut Context<Self>,
21340    ) {
21341        self.background_highlights.insert(
21342            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21343            (Arc::new(color_fetcher), Arc::from(ranges)),
21344        );
21345        self.scrollbar_marker_state.dirty = true;
21346        cx.notify();
21347    }
21348
21349    pub fn clear_background_highlights<T: 'static>(
21350        &mut self,
21351        cx: &mut Context<Self>,
21352    ) -> Option<BackgroundHighlight> {
21353        let text_highlights = self
21354            .background_highlights
21355            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21356        if !text_highlights.1.is_empty() {
21357            self.scrollbar_marker_state.dirty = true;
21358            cx.notify();
21359        }
21360        Some(text_highlights)
21361    }
21362
21363    pub fn highlight_gutter<T: 'static>(
21364        &mut self,
21365        ranges: impl Into<Vec<Range<Anchor>>>,
21366        color_fetcher: fn(&App) -> Hsla,
21367        cx: &mut Context<Self>,
21368    ) {
21369        self.gutter_highlights
21370            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21371        cx.notify();
21372    }
21373
21374    pub fn clear_gutter_highlights<T: 'static>(
21375        &mut self,
21376        cx: &mut Context<Self>,
21377    ) -> Option<GutterHighlight> {
21378        cx.notify();
21379        self.gutter_highlights.remove(&TypeId::of::<T>())
21380    }
21381
21382    pub fn insert_gutter_highlight<T: 'static>(
21383        &mut self,
21384        range: Range<Anchor>,
21385        color_fetcher: fn(&App) -> Hsla,
21386        cx: &mut Context<Self>,
21387    ) {
21388        let snapshot = self.buffer().read(cx).snapshot(cx);
21389        let mut highlights = self
21390            .gutter_highlights
21391            .remove(&TypeId::of::<T>())
21392            .map(|(_, highlights)| highlights)
21393            .unwrap_or_default();
21394        let ix = highlights.binary_search_by(|highlight| {
21395            Ordering::Equal
21396                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21397                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21398        });
21399        if let Err(ix) = ix {
21400            highlights.insert(ix, range);
21401        }
21402        self.gutter_highlights
21403            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21404    }
21405
21406    pub fn remove_gutter_highlights<T: 'static>(
21407        &mut self,
21408        ranges_to_remove: Vec<Range<Anchor>>,
21409        cx: &mut Context<Self>,
21410    ) {
21411        let snapshot = self.buffer().read(cx).snapshot(cx);
21412        let Some((color_fetcher, mut gutter_highlights)) =
21413            self.gutter_highlights.remove(&TypeId::of::<T>())
21414        else {
21415            return;
21416        };
21417        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21418        gutter_highlights.retain(|highlight| {
21419            while let Some(range_to_remove) = ranges_to_remove.peek() {
21420                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21421                    Ordering::Less | Ordering::Equal => {
21422                        ranges_to_remove.next();
21423                    }
21424                    Ordering::Greater => {
21425                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21426                            Ordering::Less | Ordering::Equal => {
21427                                return false;
21428                            }
21429                            Ordering::Greater => break,
21430                        }
21431                    }
21432                }
21433            }
21434
21435            true
21436        });
21437        self.gutter_highlights
21438            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21439    }
21440
21441    #[cfg(feature = "test-support")]
21442    pub fn all_text_highlights(
21443        &self,
21444        window: &mut Window,
21445        cx: &mut Context<Self>,
21446    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21447        let snapshot = self.snapshot(window, cx);
21448        self.display_map.update(cx, |display_map, _| {
21449            display_map
21450                .all_text_highlights()
21451                .map(|highlight| {
21452                    let (style, ranges) = highlight.as_ref();
21453                    (
21454                        *style,
21455                        ranges
21456                            .iter()
21457                            .map(|range| range.clone().to_display_points(&snapshot))
21458                            .collect(),
21459                    )
21460                })
21461                .collect()
21462        })
21463    }
21464
21465    #[cfg(feature = "test-support")]
21466    pub fn all_text_background_highlights(
21467        &self,
21468        window: &mut Window,
21469        cx: &mut Context<Self>,
21470    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21471        let snapshot = self.snapshot(window, cx);
21472        let buffer = &snapshot.buffer_snapshot();
21473        let start = buffer.anchor_before(MultiBufferOffset(0));
21474        let end = buffer.anchor_after(buffer.len());
21475        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21476    }
21477
21478    #[cfg(any(test, feature = "test-support"))]
21479    pub fn sorted_background_highlights_in_range(
21480        &self,
21481        search_range: Range<Anchor>,
21482        display_snapshot: &DisplaySnapshot,
21483        theme: &Theme,
21484    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21485        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21486        res.sort_by(|a, b| {
21487            a.0.start
21488                .cmp(&b.0.start)
21489                .then_with(|| a.0.end.cmp(&b.0.end))
21490                .then_with(|| a.1.cmp(&b.1))
21491        });
21492        res
21493    }
21494
21495    #[cfg(feature = "test-support")]
21496    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21497        let snapshot = self.buffer().read(cx).snapshot(cx);
21498
21499        let highlights = self
21500            .background_highlights
21501            .get(&HighlightKey::Type(TypeId::of::<
21502                items::BufferSearchHighlights,
21503            >()));
21504
21505        if let Some((_color, ranges)) = highlights {
21506            ranges
21507                .iter()
21508                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21509                .collect_vec()
21510        } else {
21511            vec![]
21512        }
21513    }
21514
21515    fn document_highlights_for_position<'a>(
21516        &'a self,
21517        position: Anchor,
21518        buffer: &'a MultiBufferSnapshot,
21519    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21520        let read_highlights = self
21521            .background_highlights
21522            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21523            .map(|h| &h.1);
21524        let write_highlights = self
21525            .background_highlights
21526            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21527            .map(|h| &h.1);
21528        let left_position = position.bias_left(buffer);
21529        let right_position = position.bias_right(buffer);
21530        read_highlights
21531            .into_iter()
21532            .chain(write_highlights)
21533            .flat_map(move |ranges| {
21534                let start_ix = match ranges.binary_search_by(|probe| {
21535                    let cmp = probe.end.cmp(&left_position, buffer);
21536                    if cmp.is_ge() {
21537                        Ordering::Greater
21538                    } else {
21539                        Ordering::Less
21540                    }
21541                }) {
21542                    Ok(i) | Err(i) => i,
21543                };
21544
21545                ranges[start_ix..]
21546                    .iter()
21547                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21548            })
21549    }
21550
21551    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21552        self.background_highlights
21553            .get(&HighlightKey::Type(TypeId::of::<T>()))
21554            .is_some_and(|(_, highlights)| !highlights.is_empty())
21555    }
21556
21557    /// Returns all background highlights for a given range.
21558    ///
21559    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21560    pub fn 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 results = Vec::new();
21567        for (color_fetcher, ranges) in self.background_highlights.values() {
21568            let start_ix = match ranges.binary_search_by(|probe| {
21569                let cmp = probe
21570                    .end
21571                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21572                if cmp.is_gt() {
21573                    Ordering::Greater
21574                } else {
21575                    Ordering::Less
21576                }
21577            }) {
21578                Ok(i) | Err(i) => i,
21579            };
21580            for (index, range) in ranges[start_ix..].iter().enumerate() {
21581                if range
21582                    .start
21583                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21584                    .is_ge()
21585                {
21586                    break;
21587                }
21588
21589                let color = color_fetcher(&(start_ix + index), theme);
21590                let start = range.start.to_display_point(display_snapshot);
21591                let end = range.end.to_display_point(display_snapshot);
21592                results.push((start..end, color))
21593            }
21594        }
21595        results
21596    }
21597
21598    pub fn gutter_highlights_in_range(
21599        &self,
21600        search_range: Range<Anchor>,
21601        display_snapshot: &DisplaySnapshot,
21602        cx: &App,
21603    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21604        let mut results = Vec::new();
21605        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21606            let color = color_fetcher(cx);
21607            let start_ix = match ranges.binary_search_by(|probe| {
21608                let cmp = probe
21609                    .end
21610                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21611                if cmp.is_gt() {
21612                    Ordering::Greater
21613                } else {
21614                    Ordering::Less
21615                }
21616            }) {
21617                Ok(i) | Err(i) => i,
21618            };
21619            for range in &ranges[start_ix..] {
21620                if range
21621                    .start
21622                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21623                    .is_ge()
21624                {
21625                    break;
21626                }
21627
21628                let start = range.start.to_display_point(display_snapshot);
21629                let end = range.end.to_display_point(display_snapshot);
21630                results.push((start..end, color))
21631            }
21632        }
21633        results
21634    }
21635
21636    /// Get the text ranges corresponding to the redaction query
21637    pub fn redacted_ranges(
21638        &self,
21639        search_range: Range<Anchor>,
21640        display_snapshot: &DisplaySnapshot,
21641        cx: &App,
21642    ) -> Vec<Range<DisplayPoint>> {
21643        display_snapshot
21644            .buffer_snapshot()
21645            .redacted_ranges(search_range, |file| {
21646                if let Some(file) = file {
21647                    file.is_private()
21648                        && EditorSettings::get(
21649                            Some(SettingsLocation {
21650                                worktree_id: file.worktree_id(cx),
21651                                path: file.path().as_ref(),
21652                            }),
21653                            cx,
21654                        )
21655                        .redact_private_values
21656                } else {
21657                    false
21658                }
21659            })
21660            .map(|range| {
21661                range.start.to_display_point(display_snapshot)
21662                    ..range.end.to_display_point(display_snapshot)
21663            })
21664            .collect()
21665    }
21666
21667    pub fn highlight_text_key<T: 'static>(
21668        &mut self,
21669        key: usize,
21670        ranges: Vec<Range<Anchor>>,
21671        style: HighlightStyle,
21672        merge: bool,
21673        cx: &mut Context<Self>,
21674    ) {
21675        self.display_map.update(cx, |map, cx| {
21676            map.highlight_text(
21677                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21678                ranges,
21679                style,
21680                merge,
21681                cx,
21682            );
21683        });
21684        cx.notify();
21685    }
21686
21687    pub fn highlight_text<T: 'static>(
21688        &mut self,
21689        ranges: Vec<Range<Anchor>>,
21690        style: HighlightStyle,
21691        cx: &mut Context<Self>,
21692    ) {
21693        self.display_map.update(cx, |map, cx| {
21694            map.highlight_text(
21695                HighlightKey::Type(TypeId::of::<T>()),
21696                ranges,
21697                style,
21698                false,
21699                cx,
21700            )
21701        });
21702        cx.notify();
21703    }
21704
21705    pub fn text_highlights<'a, T: 'static>(
21706        &'a self,
21707        cx: &'a App,
21708    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21709        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21710    }
21711
21712    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21713        let cleared = self
21714            .display_map
21715            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21716        if cleared {
21717            cx.notify();
21718        }
21719    }
21720
21721    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21722        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21723            && self.focus_handle.is_focused(window)
21724    }
21725
21726    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21727        self.show_cursor_when_unfocused = is_enabled;
21728        cx.notify();
21729    }
21730
21731    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21732        cx.notify();
21733    }
21734
21735    fn on_debug_session_event(
21736        &mut self,
21737        _session: Entity<Session>,
21738        event: &SessionEvent,
21739        cx: &mut Context<Self>,
21740    ) {
21741        if let SessionEvent::InvalidateInlineValue = event {
21742            self.refresh_inline_values(cx);
21743        }
21744    }
21745
21746    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21747        let Some(project) = self.project.clone() else {
21748            return;
21749        };
21750
21751        if !self.inline_value_cache.enabled {
21752            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21753            self.splice_inlays(&inlays, Vec::new(), cx);
21754            return;
21755        }
21756
21757        let current_execution_position = self
21758            .highlighted_rows
21759            .get(&TypeId::of::<ActiveDebugLine>())
21760            .and_then(|lines| lines.last().map(|line| line.range.end));
21761
21762        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21763            let inline_values = editor
21764                .update(cx, |editor, cx| {
21765                    let Some(current_execution_position) = current_execution_position else {
21766                        return Some(Task::ready(Ok(Vec::new())));
21767                    };
21768
21769                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21770                        let snapshot = buffer.snapshot(cx);
21771
21772                        let excerpt = snapshot.excerpt_containing(
21773                            current_execution_position..current_execution_position,
21774                        )?;
21775
21776                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21777                    })?;
21778
21779                    let range =
21780                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21781
21782                    project.inline_values(buffer, range, cx)
21783                })
21784                .ok()
21785                .flatten()?
21786                .await
21787                .context("refreshing debugger inlays")
21788                .log_err()?;
21789
21790            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21791
21792            for (buffer_id, inline_value) in inline_values
21793                .into_iter()
21794                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21795            {
21796                buffer_inline_values
21797                    .entry(buffer_id)
21798                    .or_default()
21799                    .push(inline_value);
21800            }
21801
21802            editor
21803                .update(cx, |editor, cx| {
21804                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21805                    let mut new_inlays = Vec::default();
21806
21807                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21808                        let buffer_id = buffer_snapshot.remote_id();
21809                        buffer_inline_values
21810                            .get(&buffer_id)
21811                            .into_iter()
21812                            .flatten()
21813                            .for_each(|hint| {
21814                                let inlay = Inlay::debugger(
21815                                    post_inc(&mut editor.next_inlay_id),
21816                                    Anchor::in_buffer(excerpt_id, hint.position),
21817                                    hint.text(),
21818                                );
21819                                if !inlay.text().chars().contains(&'\n') {
21820                                    new_inlays.push(inlay);
21821                                }
21822                            });
21823                    }
21824
21825                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21826                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21827
21828                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21829                })
21830                .ok()?;
21831            Some(())
21832        });
21833    }
21834
21835    fn on_buffer_event(
21836        &mut self,
21837        multibuffer: &Entity<MultiBuffer>,
21838        event: &multi_buffer::Event,
21839        window: &mut Window,
21840        cx: &mut Context<Self>,
21841    ) {
21842        match event {
21843            multi_buffer::Event::Edited { edited_buffer } => {
21844                self.scrollbar_marker_state.dirty = true;
21845                self.active_indent_guides_state.dirty = true;
21846                self.refresh_active_diagnostics(cx);
21847                self.refresh_code_actions(window, cx);
21848                self.refresh_single_line_folds(window, cx);
21849                self.refresh_matching_bracket_highlights(window, cx);
21850                if self.has_active_edit_prediction() {
21851                    self.update_visible_edit_prediction(window, cx);
21852                }
21853
21854                if let Some(buffer) = edited_buffer {
21855                    if buffer.read(cx).file().is_none() {
21856                        cx.emit(EditorEvent::TitleChanged);
21857                    }
21858
21859                    if self.project.is_some() {
21860                        let buffer_id = buffer.read(cx).remote_id();
21861                        self.register_buffer(buffer_id, cx);
21862                        self.update_lsp_data(Some(buffer_id), window, cx);
21863                        self.refresh_inlay_hints(
21864                            InlayHintRefreshReason::BufferEdited(buffer_id),
21865                            cx,
21866                        );
21867                    }
21868                }
21869
21870                cx.emit(EditorEvent::BufferEdited);
21871                cx.emit(SearchEvent::MatchesInvalidated);
21872
21873                let Some(project) = &self.project else { return };
21874                let (telemetry, is_via_ssh) = {
21875                    let project = project.read(cx);
21876                    let telemetry = project.client().telemetry().clone();
21877                    let is_via_ssh = project.is_via_remote_server();
21878                    (telemetry, is_via_ssh)
21879                };
21880                telemetry.log_edit_event("editor", is_via_ssh);
21881            }
21882            multi_buffer::Event::ExcerptsAdded {
21883                buffer,
21884                predecessor,
21885                excerpts,
21886            } => {
21887                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21888                let buffer_id = buffer.read(cx).remote_id();
21889                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21890                    && let Some(project) = &self.project
21891                {
21892                    update_uncommitted_diff_for_buffer(
21893                        cx.entity(),
21894                        project,
21895                        [buffer.clone()],
21896                        self.buffer.clone(),
21897                        cx,
21898                    )
21899                    .detach();
21900                }
21901                self.update_lsp_data(Some(buffer_id), window, cx);
21902                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21903                self.colorize_brackets(false, cx);
21904                cx.emit(EditorEvent::ExcerptsAdded {
21905                    buffer: buffer.clone(),
21906                    predecessor: *predecessor,
21907                    excerpts: excerpts.clone(),
21908                });
21909            }
21910            multi_buffer::Event::ExcerptsRemoved {
21911                ids,
21912                removed_buffer_ids,
21913            } => {
21914                if let Some(inlay_hints) = &mut self.inlay_hints {
21915                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21916                }
21917                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21918                for buffer_id in removed_buffer_ids {
21919                    self.registered_buffers.remove(buffer_id);
21920                }
21921                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21922                cx.emit(EditorEvent::ExcerptsRemoved {
21923                    ids: ids.clone(),
21924                    removed_buffer_ids: removed_buffer_ids.clone(),
21925                });
21926            }
21927            multi_buffer::Event::ExcerptsEdited {
21928                excerpt_ids,
21929                buffer_ids,
21930            } => {
21931                self.display_map.update(cx, |map, cx| {
21932                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21933                });
21934                cx.emit(EditorEvent::ExcerptsEdited {
21935                    ids: excerpt_ids.clone(),
21936                });
21937            }
21938            multi_buffer::Event::ExcerptsExpanded { ids } => {
21939                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21940                self.refresh_document_highlights(cx);
21941                for id in ids {
21942                    self.fetched_tree_sitter_chunks.remove(id);
21943                }
21944                self.colorize_brackets(false, cx);
21945                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21946            }
21947            multi_buffer::Event::Reparsed(buffer_id) => {
21948                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21949                self.refresh_selected_text_highlights(true, window, cx);
21950                self.colorize_brackets(true, cx);
21951                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21952
21953                cx.emit(EditorEvent::Reparsed(*buffer_id));
21954            }
21955            multi_buffer::Event::DiffHunksToggled => {
21956                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21957            }
21958            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
21959                if !is_fresh_language {
21960                    self.registered_buffers.remove(&buffer_id);
21961                }
21962                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21963                cx.emit(EditorEvent::Reparsed(*buffer_id));
21964                cx.notify();
21965            }
21966            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21967            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21968            multi_buffer::Event::FileHandleChanged
21969            | multi_buffer::Event::Reloaded
21970            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21971            multi_buffer::Event::DiagnosticsUpdated => {
21972                self.update_diagnostics_state(window, cx);
21973            }
21974            _ => {}
21975        };
21976    }
21977
21978    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21979        if !self.diagnostics_enabled() {
21980            return;
21981        }
21982        self.refresh_active_diagnostics(cx);
21983        self.refresh_inline_diagnostics(true, window, cx);
21984        self.scrollbar_marker_state.dirty = true;
21985        cx.notify();
21986    }
21987
21988    pub fn start_temporary_diff_override(&mut self) {
21989        self.load_diff_task.take();
21990        self.temporary_diff_override = true;
21991    }
21992
21993    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21994        self.temporary_diff_override = false;
21995        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21996        self.buffer.update(cx, |buffer, cx| {
21997            buffer.set_all_diff_hunks_collapsed(cx);
21998        });
21999
22000        if let Some(project) = self.project.clone() {
22001            self.load_diff_task = Some(
22002                update_uncommitted_diff_for_buffer(
22003                    cx.entity(),
22004                    &project,
22005                    self.buffer.read(cx).all_buffers(),
22006                    self.buffer.clone(),
22007                    cx,
22008                )
22009                .shared(),
22010            );
22011        }
22012    }
22013
22014    fn on_display_map_changed(
22015        &mut self,
22016        _: Entity<DisplayMap>,
22017        _: &mut Window,
22018        cx: &mut Context<Self>,
22019    ) {
22020        cx.notify();
22021    }
22022
22023    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
22024        if !self.mode.is_full() {
22025            return None;
22026        }
22027
22028        let theme_settings = theme::ThemeSettings::get_global(cx);
22029        let theme = cx.theme();
22030        let accent_colors = theme.accents().clone();
22031
22032        let accent_overrides = theme_settings
22033            .theme_overrides
22034            .get(theme.name.as_ref())
22035            .map(|theme_style| &theme_style.accents)
22036            .into_iter()
22037            .flatten()
22038            .chain(
22039                theme_settings
22040                    .experimental_theme_overrides
22041                    .as_ref()
22042                    .map(|overrides| &overrides.accents)
22043                    .into_iter()
22044                    .flatten(),
22045            )
22046            .flat_map(|accent| accent.0.clone())
22047            .collect();
22048
22049        Some(AccentData {
22050            colors: accent_colors,
22051            overrides: accent_overrides,
22052        })
22053    }
22054
22055    fn fetch_applicable_language_settings(
22056        &self,
22057        cx: &App,
22058    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
22059        if !self.mode.is_full() {
22060            return HashMap::default();
22061        }
22062
22063        self.buffer().read(cx).all_buffers().into_iter().fold(
22064            HashMap::default(),
22065            |mut acc, buffer| {
22066                let buffer = buffer.read(cx);
22067                let language = buffer.language().map(|language| language.name());
22068                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
22069                    let file = buffer.file();
22070                    v.insert(language_settings(language, file, cx).into_owned());
22071                }
22072                acc
22073            },
22074        )
22075    }
22076
22077    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22078        let new_language_settings = self.fetch_applicable_language_settings(cx);
22079        let language_settings_changed = new_language_settings != self.applicable_language_settings;
22080        self.applicable_language_settings = new_language_settings;
22081
22082        let new_accents = self.fetch_accent_data(cx);
22083        let accents_changed = new_accents != self.accent_data;
22084        self.accent_data = new_accents;
22085
22086        if self.diagnostics_enabled() {
22087            let new_severity = EditorSettings::get_global(cx)
22088                .diagnostics_max_severity
22089                .unwrap_or(DiagnosticSeverity::Hint);
22090            self.set_max_diagnostics_severity(new_severity, cx);
22091        }
22092        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22093        self.update_edit_prediction_settings(cx);
22094        self.refresh_edit_prediction(true, false, window, cx);
22095        self.refresh_inline_values(cx);
22096        self.refresh_inlay_hints(
22097            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
22098                self.selections.newest_anchor().head(),
22099                &self.buffer.read(cx).snapshot(cx),
22100                cx,
22101            )),
22102            cx,
22103        );
22104
22105        let old_cursor_shape = self.cursor_shape;
22106        let old_show_breadcrumbs = self.show_breadcrumbs;
22107
22108        {
22109            let editor_settings = EditorSettings::get_global(cx);
22110            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
22111            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
22112            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
22113            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
22114        }
22115
22116        if old_cursor_shape != self.cursor_shape {
22117            cx.emit(EditorEvent::CursorShapeChanged);
22118        }
22119
22120        if old_show_breadcrumbs != self.show_breadcrumbs {
22121            cx.emit(EditorEvent::BreadcrumbsChanged);
22122        }
22123
22124        let project_settings = ProjectSettings::get_global(cx);
22125        self.buffer_serialization = self
22126            .should_serialize_buffer()
22127            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
22128
22129        if self.mode.is_full() {
22130            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
22131            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
22132            if self.show_inline_diagnostics != show_inline_diagnostics {
22133                self.show_inline_diagnostics = show_inline_diagnostics;
22134                self.refresh_inline_diagnostics(false, window, cx);
22135            }
22136
22137            if self.git_blame_inline_enabled != inline_blame_enabled {
22138                self.toggle_git_blame_inline_internal(false, window, cx);
22139            }
22140
22141            let minimap_settings = EditorSettings::get_global(cx).minimap;
22142            if self.minimap_visibility != MinimapVisibility::Disabled {
22143                if self.minimap_visibility.settings_visibility()
22144                    != minimap_settings.minimap_enabled()
22145                {
22146                    self.set_minimap_visibility(
22147                        MinimapVisibility::for_mode(self.mode(), cx),
22148                        window,
22149                        cx,
22150                    );
22151                } else if let Some(minimap_entity) = self.minimap.as_ref() {
22152                    minimap_entity.update(cx, |minimap_editor, cx| {
22153                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
22154                    })
22155                }
22156            }
22157
22158            if language_settings_changed || accents_changed {
22159                self.colorize_brackets(true, cx);
22160            }
22161
22162            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
22163                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
22164            }) {
22165                if !inlay_splice.is_empty() {
22166                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
22167                }
22168                self.refresh_colors_for_visible_range(None, window, cx);
22169            }
22170        }
22171
22172        cx.notify();
22173    }
22174
22175    pub fn set_searchable(&mut self, searchable: bool) {
22176        self.searchable = searchable;
22177    }
22178
22179    pub fn searchable(&self) -> bool {
22180        self.searchable
22181    }
22182
22183    pub fn open_excerpts_in_split(
22184        &mut self,
22185        _: &OpenExcerptsSplit,
22186        window: &mut Window,
22187        cx: &mut Context<Self>,
22188    ) {
22189        self.open_excerpts_common(None, true, window, cx)
22190    }
22191
22192    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
22193        self.open_excerpts_common(None, false, window, cx)
22194    }
22195
22196    fn open_excerpts_common(
22197        &mut self,
22198        jump_data: Option<JumpData>,
22199        split: bool,
22200        window: &mut Window,
22201        cx: &mut Context<Self>,
22202    ) {
22203        let Some(workspace) = self.workspace() else {
22204            cx.propagate();
22205            return;
22206        };
22207
22208        if self.buffer.read(cx).is_singleton() {
22209            cx.propagate();
22210            return;
22211        }
22212
22213        let mut new_selections_by_buffer = HashMap::default();
22214        match &jump_data {
22215            Some(JumpData::MultiBufferPoint {
22216                excerpt_id,
22217                position,
22218                anchor,
22219                line_offset_from_top,
22220            }) => {
22221                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22222                if let Some(buffer) = multi_buffer_snapshot
22223                    .buffer_id_for_excerpt(*excerpt_id)
22224                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
22225                {
22226                    let buffer_snapshot = buffer.read(cx).snapshot();
22227                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
22228                        language::ToPoint::to_point(anchor, &buffer_snapshot)
22229                    } else {
22230                        buffer_snapshot.clip_point(*position, Bias::Left)
22231                    };
22232                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
22233                    new_selections_by_buffer.insert(
22234                        buffer,
22235                        (
22236                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
22237                            Some(*line_offset_from_top),
22238                        ),
22239                    );
22240                }
22241            }
22242            Some(JumpData::MultiBufferRow {
22243                row,
22244                line_offset_from_top,
22245            }) => {
22246                let point = MultiBufferPoint::new(row.0, 0);
22247                if let Some((buffer, buffer_point, _)) =
22248                    self.buffer.read(cx).point_to_buffer_point(point, cx)
22249                {
22250                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
22251                    new_selections_by_buffer
22252                        .entry(buffer)
22253                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
22254                        .0
22255                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
22256                }
22257            }
22258            None => {
22259                let selections = self
22260                    .selections
22261                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
22262                let multi_buffer = self.buffer.read(cx);
22263                for selection in selections {
22264                    for (snapshot, range, _, anchor) in multi_buffer
22265                        .snapshot(cx)
22266                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
22267                    {
22268                        if let Some(anchor) = anchor {
22269                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
22270                            else {
22271                                continue;
22272                            };
22273                            let offset = text::ToOffset::to_offset(
22274                                &anchor.text_anchor,
22275                                &buffer_handle.read(cx).snapshot(),
22276                            );
22277                            let range = BufferOffset(offset)..BufferOffset(offset);
22278                            new_selections_by_buffer
22279                                .entry(buffer_handle)
22280                                .or_insert((Vec::new(), None))
22281                                .0
22282                                .push(range)
22283                        } else {
22284                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22285                            else {
22286                                continue;
22287                            };
22288                            new_selections_by_buffer
22289                                .entry(buffer_handle)
22290                                .or_insert((Vec::new(), None))
22291                                .0
22292                                .push(range)
22293                        }
22294                    }
22295                }
22296            }
22297        }
22298
22299        new_selections_by_buffer
22300            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
22301
22302        if new_selections_by_buffer.is_empty() {
22303            return;
22304        }
22305
22306        // We defer the pane interaction because we ourselves are a workspace item
22307        // and activating a new item causes the pane to call a method on us reentrantly,
22308        // which panics if we're on the stack.
22309        window.defer(cx, move |window, cx| {
22310            workspace.update(cx, |workspace, cx| {
22311                let pane = if split {
22312                    workspace.adjacent_pane(window, cx)
22313                } else {
22314                    workspace.active_pane().clone()
22315                };
22316
22317                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22318                    let buffer_read = buffer.read(cx);
22319                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22320                        (true, project::File::from_dyn(Some(file)).is_some())
22321                    } else {
22322                        (false, false)
22323                    };
22324
22325                    // If project file is none workspace.open_project_item will fail to open the excerpt
22326                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22327                    // so we check if there's a tab match in that case first
22328                    let editor = (!has_file || !is_project_file)
22329                        .then(|| {
22330                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22331                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22332                            // Instead, we try to activate the existing editor in the pane first.
22333                            let (editor, pane_item_index, pane_item_id) =
22334                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22335                                    let editor = item.downcast::<Editor>()?;
22336                                    let singleton_buffer =
22337                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22338                                    if singleton_buffer == buffer {
22339                                        Some((editor, i, item.item_id()))
22340                                    } else {
22341                                        None
22342                                    }
22343                                })?;
22344                            pane.update(cx, |pane, cx| {
22345                                pane.activate_item(pane_item_index, true, true, window, cx);
22346                                if !PreviewTabsSettings::get_global(cx)
22347                                    .enable_preview_from_multibuffer
22348                                {
22349                                    pane.unpreview_item_if_preview(pane_item_id);
22350                                }
22351                            });
22352                            Some(editor)
22353                        })
22354                        .flatten()
22355                        .unwrap_or_else(|| {
22356                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22357                                .enable_keep_preview_on_code_navigation;
22358                            let allow_new_preview =
22359                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22360                            workspace.open_project_item::<Self>(
22361                                pane.clone(),
22362                                buffer,
22363                                true,
22364                                true,
22365                                keep_old_preview,
22366                                allow_new_preview,
22367                                window,
22368                                cx,
22369                            )
22370                        });
22371
22372                    editor.update(cx, |editor, cx| {
22373                        if has_file && !is_project_file {
22374                            editor.set_read_only(true);
22375                        }
22376                        let autoscroll = match scroll_offset {
22377                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22378                            None => Autoscroll::newest(),
22379                        };
22380                        let nav_history = editor.nav_history.take();
22381                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
22382                        let Some((&excerpt_id, _, buffer_snapshot)) =
22383                            multibuffer_snapshot.as_singleton()
22384                        else {
22385                            return;
22386                        };
22387                        editor.change_selections(
22388                            SelectionEffects::scroll(autoscroll),
22389                            window,
22390                            cx,
22391                            |s| {
22392                                s.select_ranges(ranges.into_iter().map(|range| {
22393                                    let range = buffer_snapshot.anchor_before(range.start)
22394                                        ..buffer_snapshot.anchor_after(range.end);
22395                                    multibuffer_snapshot
22396                                        .anchor_range_in_excerpt(excerpt_id, range)
22397                                        .unwrap()
22398                                }));
22399                            },
22400                        );
22401                        editor.nav_history = nav_history;
22402                    });
22403                }
22404            })
22405        });
22406    }
22407
22408    // Allow opening excerpts for buffers that either belong to the current project
22409    // or represent synthetic/non-local files (e.g., git blobs). File-less buffers
22410    // are also supported so tests and other in-memory views keep working.
22411    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
22412        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some() || !file.is_local())
22413    }
22414
22415    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22416        let snapshot = self.buffer.read(cx).read(cx);
22417        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22418        Some(
22419            ranges
22420                .iter()
22421                .map(move |range| {
22422                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22423                })
22424                .collect(),
22425        )
22426    }
22427
22428    fn selection_replacement_ranges(
22429        &self,
22430        range: Range<MultiBufferOffsetUtf16>,
22431        cx: &mut App,
22432    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22433        let selections = self
22434            .selections
22435            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22436        let newest_selection = selections
22437            .iter()
22438            .max_by_key(|selection| selection.id)
22439            .unwrap();
22440        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22441        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22442        let snapshot = self.buffer.read(cx).read(cx);
22443        selections
22444            .into_iter()
22445            .map(|mut selection| {
22446                selection.start.0.0 =
22447                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22448                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22449                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22450                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22451            })
22452            .collect()
22453    }
22454
22455    fn report_editor_event(
22456        &self,
22457        reported_event: ReportEditorEvent,
22458        file_extension: Option<String>,
22459        cx: &App,
22460    ) {
22461        if cfg!(any(test, feature = "test-support")) {
22462            return;
22463        }
22464
22465        let Some(project) = &self.project else { return };
22466
22467        // If None, we are in a file without an extension
22468        let file = self
22469            .buffer
22470            .read(cx)
22471            .as_singleton()
22472            .and_then(|b| b.read(cx).file());
22473        let file_extension = file_extension.or(file
22474            .as_ref()
22475            .and_then(|file| Path::new(file.file_name(cx)).extension())
22476            .and_then(|e| e.to_str())
22477            .map(|a| a.to_string()));
22478
22479        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22480            .map(|vim_mode| vim_mode.0)
22481            .unwrap_or(false);
22482
22483        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22484        let copilot_enabled = edit_predictions_provider
22485            == language::language_settings::EditPredictionProvider::Copilot;
22486        let copilot_enabled_for_language = self
22487            .buffer
22488            .read(cx)
22489            .language_settings(cx)
22490            .show_edit_predictions;
22491
22492        let project = project.read(cx);
22493        let event_type = reported_event.event_type();
22494
22495        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22496            telemetry::event!(
22497                event_type,
22498                type = if auto_saved {"autosave"} else {"manual"},
22499                file_extension,
22500                vim_mode,
22501                copilot_enabled,
22502                copilot_enabled_for_language,
22503                edit_predictions_provider,
22504                is_via_ssh = project.is_via_remote_server(),
22505            );
22506        } else {
22507            telemetry::event!(
22508                event_type,
22509                file_extension,
22510                vim_mode,
22511                copilot_enabled,
22512                copilot_enabled_for_language,
22513                edit_predictions_provider,
22514                is_via_ssh = project.is_via_remote_server(),
22515            );
22516        };
22517    }
22518
22519    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22520    /// with each line being an array of {text, highlight} objects.
22521    fn copy_highlight_json(
22522        &mut self,
22523        _: &CopyHighlightJson,
22524        window: &mut Window,
22525        cx: &mut Context<Self>,
22526    ) {
22527        #[derive(Serialize)]
22528        struct Chunk<'a> {
22529            text: String,
22530            highlight: Option<&'a str>,
22531        }
22532
22533        let snapshot = self.buffer.read(cx).snapshot(cx);
22534        let range = self
22535            .selected_text_range(false, window, cx)
22536            .and_then(|selection| {
22537                if selection.range.is_empty() {
22538                    None
22539                } else {
22540                    Some(
22541                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22542                            selection.range.start,
22543                        )))
22544                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22545                                selection.range.end,
22546                            ))),
22547                    )
22548                }
22549            })
22550            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22551
22552        let chunks = snapshot.chunks(range, true);
22553        let mut lines = Vec::new();
22554        let mut line: VecDeque<Chunk> = VecDeque::new();
22555
22556        let Some(style) = self.style.as_ref() else {
22557            return;
22558        };
22559
22560        for chunk in chunks {
22561            let highlight = chunk
22562                .syntax_highlight_id
22563                .and_then(|id| id.name(&style.syntax));
22564            let mut chunk_lines = chunk.text.split('\n').peekable();
22565            while let Some(text) = chunk_lines.next() {
22566                let mut merged_with_last_token = false;
22567                if let Some(last_token) = line.back_mut()
22568                    && last_token.highlight == highlight
22569                {
22570                    last_token.text.push_str(text);
22571                    merged_with_last_token = true;
22572                }
22573
22574                if !merged_with_last_token {
22575                    line.push_back(Chunk {
22576                        text: text.into(),
22577                        highlight,
22578                    });
22579                }
22580
22581                if chunk_lines.peek().is_some() {
22582                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22583                        line.pop_front();
22584                    }
22585                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22586                        line.pop_back();
22587                    }
22588
22589                    lines.push(mem::take(&mut line));
22590                }
22591            }
22592        }
22593
22594        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22595            return;
22596        };
22597        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22598    }
22599
22600    pub fn open_context_menu(
22601        &mut self,
22602        _: &OpenContextMenu,
22603        window: &mut Window,
22604        cx: &mut Context<Self>,
22605    ) {
22606        self.request_autoscroll(Autoscroll::newest(), cx);
22607        let position = self
22608            .selections
22609            .newest_display(&self.display_snapshot(cx))
22610            .start;
22611        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22612    }
22613
22614    pub fn replay_insert_event(
22615        &mut self,
22616        text: &str,
22617        relative_utf16_range: Option<Range<isize>>,
22618        window: &mut Window,
22619        cx: &mut Context<Self>,
22620    ) {
22621        if !self.input_enabled {
22622            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22623            return;
22624        }
22625        if let Some(relative_utf16_range) = relative_utf16_range {
22626            let selections = self
22627                .selections
22628                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22629            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22630                let new_ranges = selections.into_iter().map(|range| {
22631                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22632                        range
22633                            .head()
22634                            .0
22635                            .0
22636                            .saturating_add_signed(relative_utf16_range.start),
22637                    ));
22638                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22639                        range
22640                            .head()
22641                            .0
22642                            .0
22643                            .saturating_add_signed(relative_utf16_range.end),
22644                    ));
22645                    start..end
22646                });
22647                s.select_ranges(new_ranges);
22648            });
22649        }
22650
22651        self.handle_input(text, window, cx);
22652    }
22653
22654    pub fn is_focused(&self, window: &Window) -> bool {
22655        self.focus_handle.is_focused(window)
22656    }
22657
22658    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22659        cx.emit(EditorEvent::Focused);
22660
22661        if let Some(descendant) = self
22662            .last_focused_descendant
22663            .take()
22664            .and_then(|descendant| descendant.upgrade())
22665        {
22666            window.focus(&descendant, cx);
22667        } else {
22668            if let Some(blame) = self.blame.as_ref() {
22669                blame.update(cx, GitBlame::focus)
22670            }
22671
22672            self.blink_manager.update(cx, BlinkManager::enable);
22673            self.show_cursor_names(window, cx);
22674            self.buffer.update(cx, |buffer, cx| {
22675                buffer.finalize_last_transaction(cx);
22676                if self.leader_id.is_none() {
22677                    buffer.set_active_selections(
22678                        &self.selections.disjoint_anchors_arc(),
22679                        self.selections.line_mode(),
22680                        self.cursor_shape,
22681                        cx,
22682                    );
22683                }
22684            });
22685
22686            if let Some(position_map) = self.last_position_map.clone() {
22687                EditorElement::mouse_moved(
22688                    self,
22689                    &MouseMoveEvent {
22690                        position: window.mouse_position(),
22691                        pressed_button: None,
22692                        modifiers: window.modifiers(),
22693                    },
22694                    &position_map,
22695                    window,
22696                    cx,
22697                );
22698            }
22699        }
22700    }
22701
22702    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22703        cx.emit(EditorEvent::FocusedIn)
22704    }
22705
22706    fn handle_focus_out(
22707        &mut self,
22708        event: FocusOutEvent,
22709        _window: &mut Window,
22710        cx: &mut Context<Self>,
22711    ) {
22712        if event.blurred != self.focus_handle {
22713            self.last_focused_descendant = Some(event.blurred);
22714        }
22715        self.selection_drag_state = SelectionDragState::None;
22716        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22717    }
22718
22719    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22720        self.blink_manager.update(cx, BlinkManager::disable);
22721        self.buffer
22722            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22723
22724        if let Some(blame) = self.blame.as_ref() {
22725            blame.update(cx, GitBlame::blur)
22726        }
22727        if !self.hover_state.focused(window, cx) {
22728            hide_hover(self, cx);
22729        }
22730        if !self
22731            .context_menu
22732            .borrow()
22733            .as_ref()
22734            .is_some_and(|context_menu| context_menu.focused(window, cx))
22735        {
22736            self.hide_context_menu(window, cx);
22737        }
22738        self.take_active_edit_prediction(cx);
22739        cx.emit(EditorEvent::Blurred);
22740        cx.notify();
22741    }
22742
22743    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22744        let mut pending: String = window
22745            .pending_input_keystrokes()
22746            .into_iter()
22747            .flatten()
22748            .filter_map(|keystroke| keystroke.key_char.clone())
22749            .collect();
22750
22751        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22752            pending = "".to_string();
22753        }
22754
22755        let existing_pending = self
22756            .text_highlights::<PendingInput>(cx)
22757            .map(|(_, ranges)| ranges.to_vec());
22758        if existing_pending.is_none() && pending.is_empty() {
22759            return;
22760        }
22761        let transaction =
22762            self.transact(window, cx, |this, window, cx| {
22763                let selections = this
22764                    .selections
22765                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22766                let edits = selections
22767                    .iter()
22768                    .map(|selection| (selection.end..selection.end, pending.clone()));
22769                this.edit(edits, cx);
22770                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22771                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22772                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22773                    }));
22774                });
22775                if let Some(existing_ranges) = existing_pending {
22776                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22777                    this.edit(edits, cx);
22778                }
22779            });
22780
22781        let snapshot = self.snapshot(window, cx);
22782        let ranges = self
22783            .selections
22784            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22785            .into_iter()
22786            .map(|selection| {
22787                snapshot.buffer_snapshot().anchor_after(selection.end)
22788                    ..snapshot
22789                        .buffer_snapshot()
22790                        .anchor_before(selection.end + pending.len())
22791            })
22792            .collect();
22793
22794        if pending.is_empty() {
22795            self.clear_highlights::<PendingInput>(cx);
22796        } else {
22797            self.highlight_text::<PendingInput>(
22798                ranges,
22799                HighlightStyle {
22800                    underline: Some(UnderlineStyle {
22801                        thickness: px(1.),
22802                        color: None,
22803                        wavy: false,
22804                    }),
22805                    ..Default::default()
22806                },
22807                cx,
22808            );
22809        }
22810
22811        self.ime_transaction = self.ime_transaction.or(transaction);
22812        if let Some(transaction) = self.ime_transaction {
22813            self.buffer.update(cx, |buffer, cx| {
22814                buffer.group_until_transaction(transaction, cx);
22815            });
22816        }
22817
22818        if self.text_highlights::<PendingInput>(cx).is_none() {
22819            self.ime_transaction.take();
22820        }
22821    }
22822
22823    pub fn register_action_renderer(
22824        &mut self,
22825        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22826    ) -> Subscription {
22827        let id = self.next_editor_action_id.post_inc();
22828        self.editor_actions
22829            .borrow_mut()
22830            .insert(id, Box::new(listener));
22831
22832        let editor_actions = self.editor_actions.clone();
22833        Subscription::new(move || {
22834            editor_actions.borrow_mut().remove(&id);
22835        })
22836    }
22837
22838    pub fn register_action<A: Action>(
22839        &mut self,
22840        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22841    ) -> Subscription {
22842        let id = self.next_editor_action_id.post_inc();
22843        let listener = Arc::new(listener);
22844        self.editor_actions.borrow_mut().insert(
22845            id,
22846            Box::new(move |_, window, _| {
22847                let listener = listener.clone();
22848                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22849                    let action = action.downcast_ref().unwrap();
22850                    if phase == DispatchPhase::Bubble {
22851                        listener(action, window, cx)
22852                    }
22853                })
22854            }),
22855        );
22856
22857        let editor_actions = self.editor_actions.clone();
22858        Subscription::new(move || {
22859            editor_actions.borrow_mut().remove(&id);
22860        })
22861    }
22862
22863    pub fn file_header_size(&self) -> u32 {
22864        FILE_HEADER_HEIGHT
22865    }
22866
22867    pub fn restore(
22868        &mut self,
22869        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22870        window: &mut Window,
22871        cx: &mut Context<Self>,
22872    ) {
22873        self.buffer().update(cx, |multi_buffer, cx| {
22874            for (buffer_id, changes) in revert_changes {
22875                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22876                    buffer.update(cx, |buffer, cx| {
22877                        buffer.edit(
22878                            changes
22879                                .into_iter()
22880                                .map(|(range, text)| (range, text.to_string())),
22881                            None,
22882                            cx,
22883                        );
22884                    });
22885                }
22886            }
22887        });
22888        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22889            selections.refresh()
22890        });
22891    }
22892
22893    pub fn to_pixel_point(
22894        &mut self,
22895        source: multi_buffer::Anchor,
22896        editor_snapshot: &EditorSnapshot,
22897        window: &mut Window,
22898        cx: &App,
22899    ) -> Option<gpui::Point<Pixels>> {
22900        let source_point = source.to_display_point(editor_snapshot);
22901        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
22902    }
22903
22904    pub fn display_to_pixel_point(
22905        &mut self,
22906        source: DisplayPoint,
22907        editor_snapshot: &EditorSnapshot,
22908        window: &mut Window,
22909        cx: &App,
22910    ) -> Option<gpui::Point<Pixels>> {
22911        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
22912        let text_layout_details = self.text_layout_details(window);
22913        let scroll_top = text_layout_details
22914            .scroll_anchor
22915            .scroll_position(editor_snapshot)
22916            .y;
22917
22918        if source.row().as_f64() < scroll_top.floor() {
22919            return None;
22920        }
22921        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22922        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22923        Some(gpui::Point::new(source_x, source_y))
22924    }
22925
22926    pub fn has_visible_completions_menu(&self) -> bool {
22927        !self.edit_prediction_preview_is_active()
22928            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22929                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22930            })
22931    }
22932
22933    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22934        if self.mode.is_minimap() {
22935            return;
22936        }
22937        self.addons
22938            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22939    }
22940
22941    pub fn unregister_addon<T: Addon>(&mut self) {
22942        self.addons.remove(&std::any::TypeId::of::<T>());
22943    }
22944
22945    pub fn addon<T: Addon>(&self) -> Option<&T> {
22946        let type_id = std::any::TypeId::of::<T>();
22947        self.addons
22948            .get(&type_id)
22949            .and_then(|item| item.to_any().downcast_ref::<T>())
22950    }
22951
22952    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22953        let type_id = std::any::TypeId::of::<T>();
22954        self.addons
22955            .get_mut(&type_id)
22956            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22957    }
22958
22959    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22960        let text_layout_details = self.text_layout_details(window);
22961        let style = &text_layout_details.editor_style;
22962        let font_id = window.text_system().resolve_font(&style.text.font());
22963        let font_size = style.text.font_size.to_pixels(window.rem_size());
22964        let line_height = style.text.line_height_in_pixels(window.rem_size());
22965        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22966        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22967
22968        CharacterDimensions {
22969            em_width,
22970            em_advance,
22971            line_height,
22972        }
22973    }
22974
22975    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22976        self.load_diff_task.clone()
22977    }
22978
22979    fn read_metadata_from_db(
22980        &mut self,
22981        item_id: u64,
22982        workspace_id: WorkspaceId,
22983        window: &mut Window,
22984        cx: &mut Context<Editor>,
22985    ) {
22986        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22987            && !self.mode.is_minimap()
22988            && WorkspaceSettings::get(None, cx).restore_on_startup
22989                != RestoreOnStartupBehavior::EmptyTab
22990        {
22991            let buffer_snapshot = OnceCell::new();
22992
22993            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22994                && !folds.is_empty()
22995            {
22996                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22997                self.fold_ranges(
22998                    folds
22999                        .into_iter()
23000                        .map(|(start, end)| {
23001                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23002                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23003                        })
23004                        .collect(),
23005                    false,
23006                    window,
23007                    cx,
23008                );
23009            }
23010
23011            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
23012                && !selections.is_empty()
23013            {
23014                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23015                // skip adding the initial selection to selection history
23016                self.selection_history.mode = SelectionHistoryMode::Skipping;
23017                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23018                    s.select_ranges(selections.into_iter().map(|(start, end)| {
23019                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23020                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23021                    }));
23022                });
23023                self.selection_history.mode = SelectionHistoryMode::Normal;
23024            };
23025        }
23026
23027        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
23028    }
23029
23030    fn update_lsp_data(
23031        &mut self,
23032        for_buffer: Option<BufferId>,
23033        window: &mut Window,
23034        cx: &mut Context<'_, Self>,
23035    ) {
23036        self.pull_diagnostics(for_buffer, window, cx);
23037        self.refresh_colors_for_visible_range(for_buffer, window, cx);
23038    }
23039
23040    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
23041        if self.ignore_lsp_data() {
23042            return;
23043        }
23044        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
23045            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
23046        }
23047    }
23048
23049    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
23050        if self.ignore_lsp_data() {
23051            return;
23052        }
23053
23054        if !self.registered_buffers.contains_key(&buffer_id)
23055            && let Some(project) = self.project.as_ref()
23056        {
23057            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
23058                project.update(cx, |project, cx| {
23059                    self.registered_buffers.insert(
23060                        buffer_id,
23061                        project.register_buffer_with_language_servers(&buffer, cx),
23062                    );
23063                });
23064            } else {
23065                self.registered_buffers.remove(&buffer_id);
23066            }
23067        }
23068    }
23069
23070    fn ignore_lsp_data(&self) -> bool {
23071        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
23072        // skip any LSP updates for it.
23073        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
23074    }
23075
23076    fn create_style(&self, cx: &App) -> EditorStyle {
23077        let settings = ThemeSettings::get_global(cx);
23078
23079        let mut text_style = match self.mode {
23080            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23081                color: cx.theme().colors().editor_foreground,
23082                font_family: settings.ui_font.family.clone(),
23083                font_features: settings.ui_font.features.clone(),
23084                font_fallbacks: settings.ui_font.fallbacks.clone(),
23085                font_size: rems(0.875).into(),
23086                font_weight: settings.ui_font.weight,
23087                line_height: relative(settings.buffer_line_height.value()),
23088                ..Default::default()
23089            },
23090            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23091                color: cx.theme().colors().editor_foreground,
23092                font_family: settings.buffer_font.family.clone(),
23093                font_features: settings.buffer_font.features.clone(),
23094                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23095                font_size: settings.buffer_font_size(cx).into(),
23096                font_weight: settings.buffer_font.weight,
23097                line_height: relative(settings.buffer_line_height.value()),
23098                ..Default::default()
23099            },
23100        };
23101        if let Some(text_style_refinement) = &self.text_style_refinement {
23102            text_style.refine(text_style_refinement)
23103        }
23104
23105        let background = match self.mode {
23106            EditorMode::SingleLine => cx.theme().system().transparent,
23107            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23108            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23109            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23110        };
23111
23112        EditorStyle {
23113            background,
23114            border: cx.theme().colors().border,
23115            local_player: cx.theme().players().local(),
23116            text: text_style,
23117            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23118            syntax: cx.theme().syntax().clone(),
23119            status: cx.theme().status().clone(),
23120            inlay_hints_style: make_inlay_hints_style(cx),
23121            edit_prediction_styles: make_suggestion_styles(cx),
23122            unnecessary_code_fade: settings.unnecessary_code_fade,
23123            show_underlines: self.diagnostics_enabled(),
23124        }
23125    }
23126}
23127
23128fn edit_for_markdown_paste<'a>(
23129    buffer: &MultiBufferSnapshot,
23130    range: Range<MultiBufferOffset>,
23131    to_insert: &'a str,
23132    url: Option<url::Url>,
23133) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
23134    if url.is_none() {
23135        return (range, Cow::Borrowed(to_insert));
23136    };
23137
23138    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
23139
23140    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
23141        Cow::Borrowed(to_insert)
23142    } else {
23143        Cow::Owned(format!("[{old_text}]({to_insert})"))
23144    };
23145    (range, new_text)
23146}
23147
23148fn process_completion_for_edit(
23149    completion: &Completion,
23150    intent: CompletionIntent,
23151    buffer: &Entity<Buffer>,
23152    cursor_position: &text::Anchor,
23153    cx: &mut Context<Editor>,
23154) -> CompletionEdit {
23155    let buffer = buffer.read(cx);
23156    let buffer_snapshot = buffer.snapshot();
23157    let (snippet, new_text) = if completion.is_snippet() {
23158        let mut snippet_source = completion.new_text.clone();
23159        // Workaround for typescript language server issues so that methods don't expand within
23160        // strings and functions with type expressions. The previous point is used because the query
23161        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
23162        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
23163        let previous_point = if previous_point.column > 0 {
23164            cursor_position.to_previous_offset(&buffer_snapshot)
23165        } else {
23166            cursor_position.to_offset(&buffer_snapshot)
23167        };
23168        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
23169            && scope.prefers_label_for_snippet_in_completion()
23170            && let Some(label) = completion.label()
23171            && matches!(
23172                completion.kind(),
23173                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
23174            )
23175        {
23176            snippet_source = label;
23177        }
23178        match Snippet::parse(&snippet_source).log_err() {
23179            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
23180            None => (None, completion.new_text.clone()),
23181        }
23182    } else {
23183        (None, completion.new_text.clone())
23184    };
23185
23186    let mut range_to_replace = {
23187        let replace_range = &completion.replace_range;
23188        if let CompletionSource::Lsp {
23189            insert_range: Some(insert_range),
23190            ..
23191        } = &completion.source
23192        {
23193            debug_assert_eq!(
23194                insert_range.start, replace_range.start,
23195                "insert_range and replace_range should start at the same position"
23196            );
23197            debug_assert!(
23198                insert_range
23199                    .start
23200                    .cmp(cursor_position, &buffer_snapshot)
23201                    .is_le(),
23202                "insert_range should start before or at cursor position"
23203            );
23204            debug_assert!(
23205                replace_range
23206                    .start
23207                    .cmp(cursor_position, &buffer_snapshot)
23208                    .is_le(),
23209                "replace_range should start before or at cursor position"
23210            );
23211
23212            let should_replace = match intent {
23213                CompletionIntent::CompleteWithInsert => false,
23214                CompletionIntent::CompleteWithReplace => true,
23215                CompletionIntent::Complete | CompletionIntent::Compose => {
23216                    let insert_mode =
23217                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
23218                            .completions
23219                            .lsp_insert_mode;
23220                    match insert_mode {
23221                        LspInsertMode::Insert => false,
23222                        LspInsertMode::Replace => true,
23223                        LspInsertMode::ReplaceSubsequence => {
23224                            let mut text_to_replace = buffer.chars_for_range(
23225                                buffer.anchor_before(replace_range.start)
23226                                    ..buffer.anchor_after(replace_range.end),
23227                            );
23228                            let mut current_needle = text_to_replace.next();
23229                            for haystack_ch in completion.label.text.chars() {
23230                                if let Some(needle_ch) = current_needle
23231                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
23232                                {
23233                                    current_needle = text_to_replace.next();
23234                                }
23235                            }
23236                            current_needle.is_none()
23237                        }
23238                        LspInsertMode::ReplaceSuffix => {
23239                            if replace_range
23240                                .end
23241                                .cmp(cursor_position, &buffer_snapshot)
23242                                .is_gt()
23243                            {
23244                                let range_after_cursor = *cursor_position..replace_range.end;
23245                                let text_after_cursor = buffer
23246                                    .text_for_range(
23247                                        buffer.anchor_before(range_after_cursor.start)
23248                                            ..buffer.anchor_after(range_after_cursor.end),
23249                                    )
23250                                    .collect::<String>()
23251                                    .to_ascii_lowercase();
23252                                completion
23253                                    .label
23254                                    .text
23255                                    .to_ascii_lowercase()
23256                                    .ends_with(&text_after_cursor)
23257                            } else {
23258                                true
23259                            }
23260                        }
23261                    }
23262                }
23263            };
23264
23265            if should_replace {
23266                replace_range.clone()
23267            } else {
23268                insert_range.clone()
23269            }
23270        } else {
23271            replace_range.clone()
23272        }
23273    };
23274
23275    if range_to_replace
23276        .end
23277        .cmp(cursor_position, &buffer_snapshot)
23278        .is_lt()
23279    {
23280        range_to_replace.end = *cursor_position;
23281    }
23282
23283    let replace_range = range_to_replace.to_offset(buffer);
23284    CompletionEdit {
23285        new_text,
23286        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
23287        snippet,
23288    }
23289}
23290
23291struct CompletionEdit {
23292    new_text: String,
23293    replace_range: Range<BufferOffset>,
23294    snippet: Option<Snippet>,
23295}
23296
23297fn comment_delimiter_for_newline(
23298    start_point: &Point,
23299    buffer: &MultiBufferSnapshot,
23300    language: &LanguageScope,
23301) -> Option<Arc<str>> {
23302    let delimiters = language.line_comment_prefixes();
23303    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
23304    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23305
23306    let num_of_whitespaces = snapshot
23307        .chars_for_range(range.clone())
23308        .take_while(|c| c.is_whitespace())
23309        .count();
23310    let comment_candidate = snapshot
23311        .chars_for_range(range.clone())
23312        .skip(num_of_whitespaces)
23313        .take(max_len_of_delimiter)
23314        .collect::<String>();
23315    let (delimiter, trimmed_len) = delimiters
23316        .iter()
23317        .filter_map(|delimiter| {
23318            let prefix = delimiter.trim_end();
23319            if comment_candidate.starts_with(prefix) {
23320                Some((delimiter, prefix.len()))
23321            } else {
23322                None
23323            }
23324        })
23325        .max_by_key(|(_, len)| *len)?;
23326
23327    if let Some(BlockCommentConfig {
23328        start: block_start, ..
23329    }) = language.block_comment()
23330    {
23331        let block_start_trimmed = block_start.trim_end();
23332        if block_start_trimmed.starts_with(delimiter.trim_end()) {
23333            let line_content = snapshot
23334                .chars_for_range(range)
23335                .skip(num_of_whitespaces)
23336                .take(block_start_trimmed.len())
23337                .collect::<String>();
23338
23339            if line_content.starts_with(block_start_trimmed) {
23340                return None;
23341            }
23342        }
23343    }
23344
23345    let cursor_is_placed_after_comment_marker =
23346        num_of_whitespaces + trimmed_len <= start_point.column as usize;
23347    if cursor_is_placed_after_comment_marker {
23348        Some(delimiter.clone())
23349    } else {
23350        None
23351    }
23352}
23353
23354fn documentation_delimiter_for_newline(
23355    start_point: &Point,
23356    buffer: &MultiBufferSnapshot,
23357    language: &LanguageScope,
23358    newline_formatting: &mut NewlineFormatting,
23359) -> Option<Arc<str>> {
23360    let BlockCommentConfig {
23361        start: start_tag,
23362        end: end_tag,
23363        prefix: delimiter,
23364        tab_size: len,
23365    } = language.documentation_comment()?;
23366    let is_within_block_comment = buffer
23367        .language_scope_at(*start_point)
23368        .is_some_and(|scope| scope.override_name() == Some("comment"));
23369    if !is_within_block_comment {
23370        return None;
23371    }
23372
23373    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23374
23375    let num_of_whitespaces = snapshot
23376        .chars_for_range(range.clone())
23377        .take_while(|c| c.is_whitespace())
23378        .count();
23379
23380    // 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.
23381    let column = start_point.column;
23382    let cursor_is_after_start_tag = {
23383        let start_tag_len = start_tag.len();
23384        let start_tag_line = snapshot
23385            .chars_for_range(range.clone())
23386            .skip(num_of_whitespaces)
23387            .take(start_tag_len)
23388            .collect::<String>();
23389        if start_tag_line.starts_with(start_tag.as_ref()) {
23390            num_of_whitespaces + start_tag_len <= column as usize
23391        } else {
23392            false
23393        }
23394    };
23395
23396    let cursor_is_after_delimiter = {
23397        let delimiter_trim = delimiter.trim_end();
23398        let delimiter_line = snapshot
23399            .chars_for_range(range.clone())
23400            .skip(num_of_whitespaces)
23401            .take(delimiter_trim.len())
23402            .collect::<String>();
23403        if delimiter_line.starts_with(delimiter_trim) {
23404            num_of_whitespaces + delimiter_trim.len() <= column as usize
23405        } else {
23406            false
23407        }
23408    };
23409
23410    let cursor_is_before_end_tag_if_exists = {
23411        let mut char_position = 0u32;
23412        let mut end_tag_offset = None;
23413
23414        'outer: for chunk in snapshot.text_for_range(range) {
23415            if let Some(byte_pos) = chunk.find(&**end_tag) {
23416                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
23417                end_tag_offset = Some(char_position + chars_before_match);
23418                break 'outer;
23419            }
23420            char_position += chunk.chars().count() as u32;
23421        }
23422
23423        if let Some(end_tag_offset) = end_tag_offset {
23424            let cursor_is_before_end_tag = column <= end_tag_offset;
23425            if cursor_is_after_start_tag {
23426                if cursor_is_before_end_tag {
23427                    newline_formatting.insert_extra_newline = true;
23428                }
23429                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
23430                if cursor_is_at_start_of_end_tag {
23431                    newline_formatting.indent_on_extra_newline.len = *len;
23432                }
23433            }
23434            cursor_is_before_end_tag
23435        } else {
23436            true
23437        }
23438    };
23439
23440    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
23441        && cursor_is_before_end_tag_if_exists
23442    {
23443        if cursor_is_after_start_tag {
23444            newline_formatting.indent_on_newline.len = *len;
23445        }
23446        Some(delimiter.clone())
23447    } else {
23448        None
23449    }
23450}
23451
23452#[derive(Debug, Default)]
23453struct NewlineFormatting {
23454    insert_extra_newline: bool,
23455    indent_on_newline: IndentSize,
23456    indent_on_extra_newline: IndentSize,
23457}
23458
23459impl NewlineFormatting {
23460    fn new(
23461        buffer: &MultiBufferSnapshot,
23462        range: Range<MultiBufferOffset>,
23463        language: &LanguageScope,
23464    ) -> Self {
23465        Self {
23466            insert_extra_newline: Self::insert_extra_newline_brackets(
23467                buffer,
23468                range.clone(),
23469                language,
23470            ) || Self::insert_extra_newline_tree_sitter(buffer, range),
23471            indent_on_newline: IndentSize::spaces(0),
23472            indent_on_extra_newline: IndentSize::spaces(0),
23473        }
23474    }
23475
23476    fn insert_extra_newline_brackets(
23477        buffer: &MultiBufferSnapshot,
23478        range: Range<MultiBufferOffset>,
23479        language: &language::LanguageScope,
23480    ) -> bool {
23481        let leading_whitespace_len = buffer
23482            .reversed_chars_at(range.start)
23483            .take_while(|c| c.is_whitespace() && *c != '\n')
23484            .map(|c| c.len_utf8())
23485            .sum::<usize>();
23486        let trailing_whitespace_len = buffer
23487            .chars_at(range.end)
23488            .take_while(|c| c.is_whitespace() && *c != '\n')
23489            .map(|c| c.len_utf8())
23490            .sum::<usize>();
23491        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
23492
23493        language.brackets().any(|(pair, enabled)| {
23494            let pair_start = pair.start.trim_end();
23495            let pair_end = pair.end.trim_start();
23496
23497            enabled
23498                && pair.newline
23499                && buffer.contains_str_at(range.end, pair_end)
23500                && buffer.contains_str_at(
23501                    range.start.saturating_sub_usize(pair_start.len()),
23502                    pair_start,
23503                )
23504        })
23505    }
23506
23507    fn insert_extra_newline_tree_sitter(
23508        buffer: &MultiBufferSnapshot,
23509        range: Range<MultiBufferOffset>,
23510    ) -> bool {
23511        let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
23512            [(buffer, range, _)] => (*buffer, range.clone()),
23513            _ => return false,
23514        };
23515        let pair = {
23516            let mut result: Option<BracketMatch<usize>> = None;
23517
23518            for pair in buffer
23519                .all_bracket_ranges(range.start.0..range.end.0)
23520                .filter(move |pair| {
23521                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
23522                })
23523            {
23524                let len = pair.close_range.end - pair.open_range.start;
23525
23526                if let Some(existing) = &result {
23527                    let existing_len = existing.close_range.end - existing.open_range.start;
23528                    if len > existing_len {
23529                        continue;
23530                    }
23531                }
23532
23533                result = Some(pair);
23534            }
23535
23536            result
23537        };
23538        let Some(pair) = pair else {
23539            return false;
23540        };
23541        pair.newline_only
23542            && buffer
23543                .chars_for_range(pair.open_range.end..range.start.0)
23544                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
23545                .all(|c| c.is_whitespace() && c != '\n')
23546    }
23547}
23548
23549fn update_uncommitted_diff_for_buffer(
23550    editor: Entity<Editor>,
23551    project: &Entity<Project>,
23552    buffers: impl IntoIterator<Item = Entity<Buffer>>,
23553    buffer: Entity<MultiBuffer>,
23554    cx: &mut App,
23555) -> Task<()> {
23556    let mut tasks = Vec::new();
23557    project.update(cx, |project, cx| {
23558        for buffer in buffers {
23559            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
23560                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
23561            }
23562        }
23563    });
23564    cx.spawn(async move |cx| {
23565        let diffs = future::join_all(tasks).await;
23566        if editor
23567            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
23568            .unwrap_or(false)
23569        {
23570            return;
23571        }
23572
23573        buffer
23574            .update(cx, |buffer, cx| {
23575                for diff in diffs.into_iter().flatten() {
23576                    buffer.add_diff(diff, cx);
23577                }
23578            })
23579            .ok();
23580    })
23581}
23582
23583fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
23584    let tab_size = tab_size.get() as usize;
23585    let mut width = offset;
23586
23587    for ch in text.chars() {
23588        width += if ch == '\t' {
23589            tab_size - (width % tab_size)
23590        } else {
23591            1
23592        };
23593    }
23594
23595    width - offset
23596}
23597
23598#[cfg(test)]
23599mod tests {
23600    use super::*;
23601
23602    #[test]
23603    fn test_string_size_with_expanded_tabs() {
23604        let nz = |val| NonZeroU32::new(val).unwrap();
23605        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
23606        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
23607        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
23608        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
23609        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
23610        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
23611        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
23612        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
23613    }
23614}
23615
23616/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
23617struct WordBreakingTokenizer<'a> {
23618    input: &'a str,
23619}
23620
23621impl<'a> WordBreakingTokenizer<'a> {
23622    fn new(input: &'a str) -> Self {
23623        Self { input }
23624    }
23625}
23626
23627fn is_char_ideographic(ch: char) -> bool {
23628    use unicode_script::Script::*;
23629    use unicode_script::UnicodeScript;
23630    matches!(ch.script(), Han | Tangut | Yi)
23631}
23632
23633fn is_grapheme_ideographic(text: &str) -> bool {
23634    text.chars().any(is_char_ideographic)
23635}
23636
23637fn is_grapheme_whitespace(text: &str) -> bool {
23638    text.chars().any(|x| x.is_whitespace())
23639}
23640
23641fn should_stay_with_preceding_ideograph(text: &str) -> bool {
23642    text.chars()
23643        .next()
23644        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
23645}
23646
23647#[derive(PartialEq, Eq, Debug, Clone, Copy)]
23648enum WordBreakToken<'a> {
23649    Word { token: &'a str, grapheme_len: usize },
23650    InlineWhitespace { token: &'a str, grapheme_len: usize },
23651    Newline,
23652}
23653
23654impl<'a> Iterator for WordBreakingTokenizer<'a> {
23655    /// Yields a span, the count of graphemes in the token, and whether it was
23656    /// whitespace. Note that it also breaks at word boundaries.
23657    type Item = WordBreakToken<'a>;
23658
23659    fn next(&mut self) -> Option<Self::Item> {
23660        use unicode_segmentation::UnicodeSegmentation;
23661        if self.input.is_empty() {
23662            return None;
23663        }
23664
23665        let mut iter = self.input.graphemes(true).peekable();
23666        let mut offset = 0;
23667        let mut grapheme_len = 0;
23668        if let Some(first_grapheme) = iter.next() {
23669            let is_newline = first_grapheme == "\n";
23670            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23671            offset += first_grapheme.len();
23672            grapheme_len += 1;
23673            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
23674                if let Some(grapheme) = iter.peek().copied()
23675                    && should_stay_with_preceding_ideograph(grapheme)
23676                {
23677                    offset += grapheme.len();
23678                    grapheme_len += 1;
23679                }
23680            } else {
23681                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23682                let mut next_word_bound = words.peek().copied();
23683                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23684                    next_word_bound = words.next();
23685                }
23686                while let Some(grapheme) = iter.peek().copied() {
23687                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23688                        break;
23689                    };
23690                    if is_grapheme_whitespace(grapheme) != is_whitespace
23691                        || (grapheme == "\n") != is_newline
23692                    {
23693                        break;
23694                    };
23695                    offset += grapheme.len();
23696                    grapheme_len += 1;
23697                    iter.next();
23698                }
23699            }
23700            let token = &self.input[..offset];
23701            self.input = &self.input[offset..];
23702            if token == "\n" {
23703                Some(WordBreakToken::Newline)
23704            } else if is_whitespace {
23705                Some(WordBreakToken::InlineWhitespace {
23706                    token,
23707                    grapheme_len,
23708                })
23709            } else {
23710                Some(WordBreakToken::Word {
23711                    token,
23712                    grapheme_len,
23713                })
23714            }
23715        } else {
23716            None
23717        }
23718    }
23719}
23720
23721#[test]
23722fn test_word_breaking_tokenizer() {
23723    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23724        ("", &[]),
23725        ("  ", &[whitespace("  ", 2)]),
23726        ("Ʒ", &[word("Ʒ", 1)]),
23727        ("Ǽ", &[word("Ǽ", 1)]),
23728        ("", &[word("", 1)]),
23729        ("⋑⋑", &[word("⋑⋑", 2)]),
23730        (
23731            "原理,进而",
23732            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23733        ),
23734        (
23735            "hello world",
23736            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23737        ),
23738        (
23739            "hello, world",
23740            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23741        ),
23742        (
23743            "  hello world",
23744            &[
23745                whitespace("  ", 2),
23746                word("hello", 5),
23747                whitespace(" ", 1),
23748                word("world", 5),
23749            ],
23750        ),
23751        (
23752            "这是什么 \n 钢笔",
23753            &[
23754                word("", 1),
23755                word("", 1),
23756                word("", 1),
23757                word("", 1),
23758                whitespace(" ", 1),
23759                newline(),
23760                whitespace(" ", 1),
23761                word("", 1),
23762                word("", 1),
23763            ],
23764        ),
23765        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23766    ];
23767
23768    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23769        WordBreakToken::Word {
23770            token,
23771            grapheme_len,
23772        }
23773    }
23774
23775    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23776        WordBreakToken::InlineWhitespace {
23777            token,
23778            grapheme_len,
23779        }
23780    }
23781
23782    fn newline() -> WordBreakToken<'static> {
23783        WordBreakToken::Newline
23784    }
23785
23786    for (input, result) in tests {
23787        assert_eq!(
23788            WordBreakingTokenizer::new(input)
23789                .collect::<Vec<_>>()
23790                .as_slice(),
23791            *result,
23792        );
23793    }
23794}
23795
23796fn wrap_with_prefix(
23797    first_line_prefix: String,
23798    subsequent_lines_prefix: String,
23799    unwrapped_text: String,
23800    wrap_column: usize,
23801    tab_size: NonZeroU32,
23802    preserve_existing_whitespace: bool,
23803) -> String {
23804    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23805    let subsequent_lines_prefix_len =
23806        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23807    let mut wrapped_text = String::new();
23808    let mut current_line = first_line_prefix;
23809    let mut is_first_line = true;
23810
23811    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23812    let mut current_line_len = first_line_prefix_len;
23813    let mut in_whitespace = false;
23814    for token in tokenizer {
23815        let have_preceding_whitespace = in_whitespace;
23816        match token {
23817            WordBreakToken::Word {
23818                token,
23819                grapheme_len,
23820            } => {
23821                in_whitespace = false;
23822                let current_prefix_len = if is_first_line {
23823                    first_line_prefix_len
23824                } else {
23825                    subsequent_lines_prefix_len
23826                };
23827                if current_line_len + grapheme_len > wrap_column
23828                    && current_line_len != current_prefix_len
23829                {
23830                    wrapped_text.push_str(current_line.trim_end());
23831                    wrapped_text.push('\n');
23832                    is_first_line = false;
23833                    current_line = subsequent_lines_prefix.clone();
23834                    current_line_len = subsequent_lines_prefix_len;
23835                }
23836                current_line.push_str(token);
23837                current_line_len += grapheme_len;
23838            }
23839            WordBreakToken::InlineWhitespace {
23840                mut token,
23841                mut grapheme_len,
23842            } => {
23843                in_whitespace = true;
23844                if have_preceding_whitespace && !preserve_existing_whitespace {
23845                    continue;
23846                }
23847                if !preserve_existing_whitespace {
23848                    // Keep a single whitespace grapheme as-is
23849                    if let Some(first) =
23850                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23851                    {
23852                        token = first;
23853                    } else {
23854                        token = " ";
23855                    }
23856                    grapheme_len = 1;
23857                }
23858                let current_prefix_len = if is_first_line {
23859                    first_line_prefix_len
23860                } else {
23861                    subsequent_lines_prefix_len
23862                };
23863                if current_line_len + grapheme_len > wrap_column {
23864                    wrapped_text.push_str(current_line.trim_end());
23865                    wrapped_text.push('\n');
23866                    is_first_line = false;
23867                    current_line = subsequent_lines_prefix.clone();
23868                    current_line_len = subsequent_lines_prefix_len;
23869                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23870                    current_line.push_str(token);
23871                    current_line_len += grapheme_len;
23872                }
23873            }
23874            WordBreakToken::Newline => {
23875                in_whitespace = true;
23876                let current_prefix_len = if is_first_line {
23877                    first_line_prefix_len
23878                } else {
23879                    subsequent_lines_prefix_len
23880                };
23881                if preserve_existing_whitespace {
23882                    wrapped_text.push_str(current_line.trim_end());
23883                    wrapped_text.push('\n');
23884                    is_first_line = false;
23885                    current_line = subsequent_lines_prefix.clone();
23886                    current_line_len = subsequent_lines_prefix_len;
23887                } else if have_preceding_whitespace {
23888                    continue;
23889                } else if current_line_len + 1 > wrap_column
23890                    && current_line_len != current_prefix_len
23891                {
23892                    wrapped_text.push_str(current_line.trim_end());
23893                    wrapped_text.push('\n');
23894                    is_first_line = false;
23895                    current_line = subsequent_lines_prefix.clone();
23896                    current_line_len = subsequent_lines_prefix_len;
23897                } else if current_line_len != current_prefix_len {
23898                    current_line.push(' ');
23899                    current_line_len += 1;
23900                }
23901            }
23902        }
23903    }
23904
23905    if !current_line.is_empty() {
23906        wrapped_text.push_str(&current_line);
23907    }
23908    wrapped_text
23909}
23910
23911#[test]
23912fn test_wrap_with_prefix() {
23913    assert_eq!(
23914        wrap_with_prefix(
23915            "# ".to_string(),
23916            "# ".to_string(),
23917            "abcdefg".to_string(),
23918            4,
23919            NonZeroU32::new(4).unwrap(),
23920            false,
23921        ),
23922        "# abcdefg"
23923    );
23924    assert_eq!(
23925        wrap_with_prefix(
23926            "".to_string(),
23927            "".to_string(),
23928            "\thello world".to_string(),
23929            8,
23930            NonZeroU32::new(4).unwrap(),
23931            false,
23932        ),
23933        "hello\nworld"
23934    );
23935    assert_eq!(
23936        wrap_with_prefix(
23937            "// ".to_string(),
23938            "// ".to_string(),
23939            "xx \nyy zz aa bb cc".to_string(),
23940            12,
23941            NonZeroU32::new(4).unwrap(),
23942            false,
23943        ),
23944        "// xx yy zz\n// aa bb cc"
23945    );
23946    assert_eq!(
23947        wrap_with_prefix(
23948            String::new(),
23949            String::new(),
23950            "这是什么 \n 钢笔".to_string(),
23951            3,
23952            NonZeroU32::new(4).unwrap(),
23953            false,
23954        ),
23955        "这是什\n么 钢\n"
23956    );
23957    assert_eq!(
23958        wrap_with_prefix(
23959            String::new(),
23960            String::new(),
23961            format!("foo{}bar", '\u{2009}'), // thin space
23962            80,
23963            NonZeroU32::new(4).unwrap(),
23964            false,
23965        ),
23966        format!("foo{}bar", '\u{2009}')
23967    );
23968}
23969
23970pub trait CollaborationHub {
23971    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23972    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23973    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23974}
23975
23976impl CollaborationHub for Entity<Project> {
23977    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23978        self.read(cx).collaborators()
23979    }
23980
23981    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23982        self.read(cx).user_store().read(cx).participant_indices()
23983    }
23984
23985    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23986        let this = self.read(cx);
23987        let user_ids = this.collaborators().values().map(|c| c.user_id);
23988        this.user_store().read(cx).participant_names(user_ids, cx)
23989    }
23990}
23991
23992pub trait SemanticsProvider {
23993    fn hover(
23994        &self,
23995        buffer: &Entity<Buffer>,
23996        position: text::Anchor,
23997        cx: &mut App,
23998    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23999
24000    fn inline_values(
24001        &self,
24002        buffer_handle: Entity<Buffer>,
24003        range: Range<text::Anchor>,
24004        cx: &mut App,
24005    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
24006
24007    fn applicable_inlay_chunks(
24008        &self,
24009        buffer: &Entity<Buffer>,
24010        ranges: &[Range<text::Anchor>],
24011        cx: &mut App,
24012    ) -> Vec<Range<BufferRow>>;
24013
24014    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
24015
24016    fn inlay_hints(
24017        &self,
24018        invalidate: InvalidationStrategy,
24019        buffer: Entity<Buffer>,
24020        ranges: Vec<Range<text::Anchor>>,
24021        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24022        cx: &mut App,
24023    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
24024
24025    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
24026
24027    fn document_highlights(
24028        &self,
24029        buffer: &Entity<Buffer>,
24030        position: text::Anchor,
24031        cx: &mut App,
24032    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
24033
24034    fn definitions(
24035        &self,
24036        buffer: &Entity<Buffer>,
24037        position: text::Anchor,
24038        kind: GotoDefinitionKind,
24039        cx: &mut App,
24040    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
24041
24042    fn range_for_rename(
24043        &self,
24044        buffer: &Entity<Buffer>,
24045        position: text::Anchor,
24046        cx: &mut App,
24047    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
24048
24049    fn perform_rename(
24050        &self,
24051        buffer: &Entity<Buffer>,
24052        position: text::Anchor,
24053        new_name: String,
24054        cx: &mut App,
24055    ) -> Option<Task<Result<ProjectTransaction>>>;
24056}
24057
24058pub trait CompletionProvider {
24059    fn completions(
24060        &self,
24061        excerpt_id: ExcerptId,
24062        buffer: &Entity<Buffer>,
24063        buffer_position: text::Anchor,
24064        trigger: CompletionContext,
24065        window: &mut Window,
24066        cx: &mut Context<Editor>,
24067    ) -> Task<Result<Vec<CompletionResponse>>>;
24068
24069    fn resolve_completions(
24070        &self,
24071        _buffer: Entity<Buffer>,
24072        _completion_indices: Vec<usize>,
24073        _completions: Rc<RefCell<Box<[Completion]>>>,
24074        _cx: &mut Context<Editor>,
24075    ) -> Task<Result<bool>> {
24076        Task::ready(Ok(false))
24077    }
24078
24079    fn apply_additional_edits_for_completion(
24080        &self,
24081        _buffer: Entity<Buffer>,
24082        _completions: Rc<RefCell<Box<[Completion]>>>,
24083        _completion_index: usize,
24084        _push_to_history: bool,
24085        _cx: &mut Context<Editor>,
24086    ) -> Task<Result<Option<language::Transaction>>> {
24087        Task::ready(Ok(None))
24088    }
24089
24090    fn is_completion_trigger(
24091        &self,
24092        buffer: &Entity<Buffer>,
24093        position: language::Anchor,
24094        text: &str,
24095        trigger_in_words: bool,
24096        cx: &mut Context<Editor>,
24097    ) -> bool;
24098
24099    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
24100
24101    fn sort_completions(&self) -> bool {
24102        true
24103    }
24104
24105    fn filter_completions(&self) -> bool {
24106        true
24107    }
24108
24109    fn show_snippets(&self) -> bool {
24110        false
24111    }
24112}
24113
24114pub trait CodeActionProvider {
24115    fn id(&self) -> Arc<str>;
24116
24117    fn code_actions(
24118        &self,
24119        buffer: &Entity<Buffer>,
24120        range: Range<text::Anchor>,
24121        window: &mut Window,
24122        cx: &mut App,
24123    ) -> Task<Result<Vec<CodeAction>>>;
24124
24125    fn apply_code_action(
24126        &self,
24127        buffer_handle: Entity<Buffer>,
24128        action: CodeAction,
24129        excerpt_id: ExcerptId,
24130        push_to_history: bool,
24131        window: &mut Window,
24132        cx: &mut App,
24133    ) -> Task<Result<ProjectTransaction>>;
24134}
24135
24136impl CodeActionProvider for Entity<Project> {
24137    fn id(&self) -> Arc<str> {
24138        "project".into()
24139    }
24140
24141    fn code_actions(
24142        &self,
24143        buffer: &Entity<Buffer>,
24144        range: Range<text::Anchor>,
24145        _window: &mut Window,
24146        cx: &mut App,
24147    ) -> Task<Result<Vec<CodeAction>>> {
24148        self.update(cx, |project, cx| {
24149            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
24150            let code_actions = project.code_actions(buffer, range, None, cx);
24151            cx.background_spawn(async move {
24152                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
24153                Ok(code_lens_actions
24154                    .context("code lens fetch")?
24155                    .into_iter()
24156                    .flatten()
24157                    .chain(
24158                        code_actions
24159                            .context("code action fetch")?
24160                            .into_iter()
24161                            .flatten(),
24162                    )
24163                    .collect())
24164            })
24165        })
24166    }
24167
24168    fn apply_code_action(
24169        &self,
24170        buffer_handle: Entity<Buffer>,
24171        action: CodeAction,
24172        _excerpt_id: ExcerptId,
24173        push_to_history: bool,
24174        _window: &mut Window,
24175        cx: &mut App,
24176    ) -> Task<Result<ProjectTransaction>> {
24177        self.update(cx, |project, cx| {
24178            project.apply_code_action(buffer_handle, action, push_to_history, cx)
24179        })
24180    }
24181}
24182
24183fn snippet_completions(
24184    project: &Project,
24185    buffer: &Entity<Buffer>,
24186    buffer_anchor: text::Anchor,
24187    classifier: CharClassifier,
24188    cx: &mut App,
24189) -> Task<Result<CompletionResponse>> {
24190    let languages = buffer.read(cx).languages_at(buffer_anchor);
24191    let snippet_store = project.snippets().read(cx);
24192
24193    let scopes: Vec<_> = languages
24194        .iter()
24195        .filter_map(|language| {
24196            let language_name = language.lsp_id();
24197            let snippets = snippet_store.snippets_for(Some(language_name), cx);
24198
24199            if snippets.is_empty() {
24200                None
24201            } else {
24202                Some((language.default_scope(), snippets))
24203            }
24204        })
24205        .collect();
24206
24207    if scopes.is_empty() {
24208        return Task::ready(Ok(CompletionResponse {
24209            completions: vec![],
24210            display_options: CompletionDisplayOptions::default(),
24211            is_incomplete: false,
24212        }));
24213    }
24214
24215    let snapshot = buffer.read(cx).text_snapshot();
24216    let executor = cx.background_executor().clone();
24217
24218    cx.background_spawn(async move {
24219        let is_word_char = |c| classifier.is_word(c);
24220
24221        let mut is_incomplete = false;
24222        let mut completions: Vec<Completion> = Vec::new();
24223
24224        const MAX_PREFIX_LEN: usize = 128;
24225        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
24226        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
24227        let window_start = snapshot.clip_offset(window_start, Bias::Left);
24228
24229        let max_buffer_window: String = snapshot
24230            .text_for_range(window_start..buffer_offset)
24231            .collect();
24232
24233        if max_buffer_window.is_empty() {
24234            return Ok(CompletionResponse {
24235                completions: vec![],
24236                display_options: CompletionDisplayOptions::default(),
24237                is_incomplete: true,
24238            });
24239        }
24240
24241        for (_scope, snippets) in scopes.into_iter() {
24242            // Sort snippets by word count to match longer snippet prefixes first.
24243            let mut sorted_snippet_candidates = snippets
24244                .iter()
24245                .enumerate()
24246                .flat_map(|(snippet_ix, snippet)| {
24247                    snippet
24248                        .prefix
24249                        .iter()
24250                        .enumerate()
24251                        .map(move |(prefix_ix, prefix)| {
24252                            let word_count =
24253                                snippet_candidate_suffixes(prefix, is_word_char).count();
24254                            ((snippet_ix, prefix_ix), prefix, word_count)
24255                        })
24256                })
24257                .collect_vec();
24258            sorted_snippet_candidates
24259                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
24260
24261            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
24262
24263            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
24264                .take(
24265                    sorted_snippet_candidates
24266                        .first()
24267                        .map(|(_, _, word_count)| *word_count)
24268                        .unwrap_or_default(),
24269                )
24270                .collect_vec();
24271
24272            const MAX_RESULTS: usize = 100;
24273            // Each match also remembers how many characters from the buffer it consumed
24274            let mut matches: Vec<(StringMatch, usize)> = vec![];
24275
24276            let mut snippet_list_cutoff_index = 0;
24277            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
24278                let word_count = buffer_index + 1;
24279                // Increase `snippet_list_cutoff_index` until we have all of the
24280                // snippets with sufficiently many words.
24281                while sorted_snippet_candidates
24282                    .get(snippet_list_cutoff_index)
24283                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
24284                        *snippet_word_count >= word_count
24285                    })
24286                {
24287                    snippet_list_cutoff_index += 1;
24288                }
24289
24290                // Take only the candidates with at least `word_count` many words
24291                let snippet_candidates_at_word_len =
24292                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
24293
24294                let candidates = snippet_candidates_at_word_len
24295                    .iter()
24296                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
24297                    .enumerate() // index in `sorted_snippet_candidates`
24298                    // First char must match
24299                    .filter(|(_ix, prefix)| {
24300                        itertools::equal(
24301                            prefix
24302                                .chars()
24303                                .next()
24304                                .into_iter()
24305                                .flat_map(|c| c.to_lowercase()),
24306                            buffer_window
24307                                .chars()
24308                                .next()
24309                                .into_iter()
24310                                .flat_map(|c| c.to_lowercase()),
24311                        )
24312                    })
24313                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
24314                    .collect::<Vec<StringMatchCandidate>>();
24315
24316                matches.extend(
24317                    fuzzy::match_strings(
24318                        &candidates,
24319                        &buffer_window,
24320                        buffer_window.chars().any(|c| c.is_uppercase()),
24321                        true,
24322                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
24323                        &Default::default(),
24324                        executor.clone(),
24325                    )
24326                    .await
24327                    .into_iter()
24328                    .map(|string_match| (string_match, buffer_window.len())),
24329                );
24330
24331                if matches.len() >= MAX_RESULTS {
24332                    break;
24333                }
24334            }
24335
24336            let to_lsp = |point: &text::Anchor| {
24337                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
24338                point_to_lsp(end)
24339            };
24340            let lsp_end = to_lsp(&buffer_anchor);
24341
24342            if matches.len() >= MAX_RESULTS {
24343                is_incomplete = true;
24344            }
24345
24346            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
24347                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
24348                    sorted_snippet_candidates[string_match.candidate_id];
24349                let snippet = &snippets[snippet_index];
24350                let start = buffer_offset - buffer_window_len;
24351                let start = snapshot.anchor_before(start);
24352                let range = start..buffer_anchor;
24353                let lsp_start = to_lsp(&start);
24354                let lsp_range = lsp::Range {
24355                    start: lsp_start,
24356                    end: lsp_end,
24357                };
24358                Completion {
24359                    replace_range: range,
24360                    new_text: snippet.body.clone(),
24361                    source: CompletionSource::Lsp {
24362                        insert_range: None,
24363                        server_id: LanguageServerId(usize::MAX),
24364                        resolved: true,
24365                        lsp_completion: Box::new(lsp::CompletionItem {
24366                            label: snippet.prefix.first().unwrap().clone(),
24367                            kind: Some(CompletionItemKind::SNIPPET),
24368                            label_details: snippet.description.as_ref().map(|description| {
24369                                lsp::CompletionItemLabelDetails {
24370                                    detail: Some(description.clone()),
24371                                    description: None,
24372                                }
24373                            }),
24374                            insert_text_format: Some(InsertTextFormat::SNIPPET),
24375                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
24376                                lsp::InsertReplaceEdit {
24377                                    new_text: snippet.body.clone(),
24378                                    insert: lsp_range,
24379                                    replace: lsp_range,
24380                                },
24381                            )),
24382                            filter_text: Some(snippet.body.clone()),
24383                            sort_text: Some(char::MAX.to_string()),
24384                            ..lsp::CompletionItem::default()
24385                        }),
24386                        lsp_defaults: None,
24387                    },
24388                    label: CodeLabel {
24389                        text: matching_prefix.clone(),
24390                        runs: Vec::new(),
24391                        filter_range: 0..matching_prefix.len(),
24392                    },
24393                    icon_path: None,
24394                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
24395                        single_line: snippet.name.clone().into(),
24396                        plain_text: snippet
24397                            .description
24398                            .clone()
24399                            .map(|description| description.into()),
24400                    }),
24401                    insert_text_mode: None,
24402                    confirm: None,
24403                    match_start: Some(start),
24404                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
24405                }
24406            }));
24407        }
24408
24409        Ok(CompletionResponse {
24410            completions,
24411            display_options: CompletionDisplayOptions::default(),
24412            is_incomplete,
24413        })
24414    })
24415}
24416
24417impl CompletionProvider for Entity<Project> {
24418    fn completions(
24419        &self,
24420        _excerpt_id: ExcerptId,
24421        buffer: &Entity<Buffer>,
24422        buffer_position: text::Anchor,
24423        options: CompletionContext,
24424        _window: &mut Window,
24425        cx: &mut Context<Editor>,
24426    ) -> Task<Result<Vec<CompletionResponse>>> {
24427        self.update(cx, |project, cx| {
24428            let task = project.completions(buffer, buffer_position, options, cx);
24429            cx.background_spawn(task)
24430        })
24431    }
24432
24433    fn resolve_completions(
24434        &self,
24435        buffer: Entity<Buffer>,
24436        completion_indices: Vec<usize>,
24437        completions: Rc<RefCell<Box<[Completion]>>>,
24438        cx: &mut Context<Editor>,
24439    ) -> Task<Result<bool>> {
24440        self.update(cx, |project, cx| {
24441            project.lsp_store().update(cx, |lsp_store, cx| {
24442                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
24443            })
24444        })
24445    }
24446
24447    fn apply_additional_edits_for_completion(
24448        &self,
24449        buffer: Entity<Buffer>,
24450        completions: Rc<RefCell<Box<[Completion]>>>,
24451        completion_index: usize,
24452        push_to_history: bool,
24453        cx: &mut Context<Editor>,
24454    ) -> Task<Result<Option<language::Transaction>>> {
24455        self.update(cx, |project, cx| {
24456            project.lsp_store().update(cx, |lsp_store, cx| {
24457                lsp_store.apply_additional_edits_for_completion(
24458                    buffer,
24459                    completions,
24460                    completion_index,
24461                    push_to_history,
24462                    cx,
24463                )
24464            })
24465        })
24466    }
24467
24468    fn is_completion_trigger(
24469        &self,
24470        buffer: &Entity<Buffer>,
24471        position: language::Anchor,
24472        text: &str,
24473        trigger_in_words: bool,
24474        cx: &mut Context<Editor>,
24475    ) -> bool {
24476        let mut chars = text.chars();
24477        let char = if let Some(char) = chars.next() {
24478            char
24479        } else {
24480            return false;
24481        };
24482        if chars.next().is_some() {
24483            return false;
24484        }
24485
24486        let buffer = buffer.read(cx);
24487        let snapshot = buffer.snapshot();
24488        let classifier = snapshot
24489            .char_classifier_at(position)
24490            .scope_context(Some(CharScopeContext::Completion));
24491        if trigger_in_words && classifier.is_word(char) {
24492            return true;
24493        }
24494
24495        buffer.completion_triggers().contains(text)
24496    }
24497
24498    fn show_snippets(&self) -> bool {
24499        true
24500    }
24501}
24502
24503impl SemanticsProvider for Entity<Project> {
24504    fn hover(
24505        &self,
24506        buffer: &Entity<Buffer>,
24507        position: text::Anchor,
24508        cx: &mut App,
24509    ) -> Option<Task<Option<Vec<project::Hover>>>> {
24510        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
24511    }
24512
24513    fn document_highlights(
24514        &self,
24515        buffer: &Entity<Buffer>,
24516        position: text::Anchor,
24517        cx: &mut App,
24518    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
24519        Some(self.update(cx, |project, cx| {
24520            project.document_highlights(buffer, position, cx)
24521        }))
24522    }
24523
24524    fn definitions(
24525        &self,
24526        buffer: &Entity<Buffer>,
24527        position: text::Anchor,
24528        kind: GotoDefinitionKind,
24529        cx: &mut App,
24530    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
24531        Some(self.update(cx, |project, cx| match kind {
24532            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
24533            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
24534            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
24535            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
24536        }))
24537    }
24538
24539    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
24540        self.update(cx, |project, cx| {
24541            if project
24542                .active_debug_session(cx)
24543                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
24544            {
24545                return true;
24546            }
24547
24548            buffer.update(cx, |buffer, cx| {
24549                project.any_language_server_supports_inlay_hints(buffer, cx)
24550            })
24551        })
24552    }
24553
24554    fn inline_values(
24555        &self,
24556        buffer_handle: Entity<Buffer>,
24557        range: Range<text::Anchor>,
24558        cx: &mut App,
24559    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
24560        self.update(cx, |project, cx| {
24561            let (session, active_stack_frame) = project.active_debug_session(cx)?;
24562
24563            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
24564        })
24565    }
24566
24567    fn applicable_inlay_chunks(
24568        &self,
24569        buffer: &Entity<Buffer>,
24570        ranges: &[Range<text::Anchor>],
24571        cx: &mut App,
24572    ) -> Vec<Range<BufferRow>> {
24573        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24574            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
24575        })
24576    }
24577
24578    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
24579        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
24580            lsp_store.invalidate_inlay_hints(for_buffers)
24581        });
24582    }
24583
24584    fn inlay_hints(
24585        &self,
24586        invalidate: InvalidationStrategy,
24587        buffer: Entity<Buffer>,
24588        ranges: Vec<Range<text::Anchor>>,
24589        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24590        cx: &mut App,
24591    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
24592        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24593            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
24594        }))
24595    }
24596
24597    fn range_for_rename(
24598        &self,
24599        buffer: &Entity<Buffer>,
24600        position: text::Anchor,
24601        cx: &mut App,
24602    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
24603        Some(self.update(cx, |project, cx| {
24604            let buffer = buffer.clone();
24605            let task = project.prepare_rename(buffer.clone(), position, cx);
24606            cx.spawn(async move |_, cx| {
24607                Ok(match task.await? {
24608                    PrepareRenameResponse::Success(range) => Some(range),
24609                    PrepareRenameResponse::InvalidPosition => None,
24610                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
24611                        // Fallback on using TreeSitter info to determine identifier range
24612                        buffer.read_with(cx, |buffer, _| {
24613                            let snapshot = buffer.snapshot();
24614                            let (range, kind) = snapshot.surrounding_word(position, None);
24615                            if kind != Some(CharKind::Word) {
24616                                return None;
24617                            }
24618                            Some(
24619                                snapshot.anchor_before(range.start)
24620                                    ..snapshot.anchor_after(range.end),
24621                            )
24622                        })?
24623                    }
24624                })
24625            })
24626        }))
24627    }
24628
24629    fn perform_rename(
24630        &self,
24631        buffer: &Entity<Buffer>,
24632        position: text::Anchor,
24633        new_name: String,
24634        cx: &mut App,
24635    ) -> Option<Task<Result<ProjectTransaction>>> {
24636        Some(self.update(cx, |project, cx| {
24637            project.perform_rename(buffer.clone(), position, new_name, cx)
24638        }))
24639    }
24640}
24641
24642fn consume_contiguous_rows(
24643    contiguous_row_selections: &mut Vec<Selection<Point>>,
24644    selection: &Selection<Point>,
24645    display_map: &DisplaySnapshot,
24646    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
24647) -> (MultiBufferRow, MultiBufferRow) {
24648    contiguous_row_selections.push(selection.clone());
24649    let start_row = starting_row(selection, display_map);
24650    let mut end_row = ending_row(selection, display_map);
24651
24652    while let Some(next_selection) = selections.peek() {
24653        if next_selection.start.row <= end_row.0 {
24654            end_row = ending_row(next_selection, display_map);
24655            contiguous_row_selections.push(selections.next().unwrap().clone());
24656        } else {
24657            break;
24658        }
24659    }
24660    (start_row, end_row)
24661}
24662
24663fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24664    if selection.start.column > 0 {
24665        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
24666    } else {
24667        MultiBufferRow(selection.start.row)
24668    }
24669}
24670
24671fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24672    if next_selection.end.column > 0 || next_selection.is_empty() {
24673        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
24674    } else {
24675        MultiBufferRow(next_selection.end.row)
24676    }
24677}
24678
24679impl EditorSnapshot {
24680    pub fn remote_selections_in_range<'a>(
24681        &'a self,
24682        range: &'a Range<Anchor>,
24683        collaboration_hub: &dyn CollaborationHub,
24684        cx: &'a App,
24685    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24686        let participant_names = collaboration_hub.user_names(cx);
24687        let participant_indices = collaboration_hub.user_participant_indices(cx);
24688        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24689        let collaborators_by_replica_id = collaborators_by_peer_id
24690            .values()
24691            .map(|collaborator| (collaborator.replica_id, collaborator))
24692            .collect::<HashMap<_, _>>();
24693        self.buffer_snapshot()
24694            .selections_in_range(range, false)
24695            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24696                if replica_id == ReplicaId::AGENT {
24697                    Some(RemoteSelection {
24698                        replica_id,
24699                        selection,
24700                        cursor_shape,
24701                        line_mode,
24702                        collaborator_id: CollaboratorId::Agent,
24703                        user_name: Some("Agent".into()),
24704                        color: cx.theme().players().agent(),
24705                    })
24706                } else {
24707                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24708                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24709                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24710                    Some(RemoteSelection {
24711                        replica_id,
24712                        selection,
24713                        cursor_shape,
24714                        line_mode,
24715                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24716                        user_name,
24717                        color: if let Some(index) = participant_index {
24718                            cx.theme().players().color_for_participant(index.0)
24719                        } else {
24720                            cx.theme().players().absent()
24721                        },
24722                    })
24723                }
24724            })
24725    }
24726
24727    pub fn hunks_for_ranges(
24728        &self,
24729        ranges: impl IntoIterator<Item = Range<Point>>,
24730    ) -> Vec<MultiBufferDiffHunk> {
24731        let mut hunks = Vec::new();
24732        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24733            HashMap::default();
24734        for query_range in ranges {
24735            let query_rows =
24736                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24737            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24738                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24739            ) {
24740                // Include deleted hunks that are adjacent to the query range, because
24741                // otherwise they would be missed.
24742                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24743                if hunk.status().is_deleted() {
24744                    intersects_range |= hunk.row_range.start == query_rows.end;
24745                    intersects_range |= hunk.row_range.end == query_rows.start;
24746                }
24747                if intersects_range {
24748                    if !processed_buffer_rows
24749                        .entry(hunk.buffer_id)
24750                        .or_default()
24751                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24752                    {
24753                        continue;
24754                    }
24755                    hunks.push(hunk);
24756                }
24757            }
24758        }
24759
24760        hunks
24761    }
24762
24763    fn display_diff_hunks_for_rows<'a>(
24764        &'a self,
24765        display_rows: Range<DisplayRow>,
24766        folded_buffers: &'a HashSet<BufferId>,
24767    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24768        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24769        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24770
24771        self.buffer_snapshot()
24772            .diff_hunks_in_range(buffer_start..buffer_end)
24773            .filter_map(|hunk| {
24774                if folded_buffers.contains(&hunk.buffer_id) {
24775                    return None;
24776                }
24777
24778                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24779                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24780
24781                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24782                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24783
24784                let display_hunk = if hunk_display_start.column() != 0 {
24785                    DisplayDiffHunk::Folded {
24786                        display_row: hunk_display_start.row(),
24787                    }
24788                } else {
24789                    let mut end_row = hunk_display_end.row();
24790                    if hunk_display_end.column() > 0 {
24791                        end_row.0 += 1;
24792                    }
24793                    let is_created_file = hunk.is_created_file();
24794
24795                    DisplayDiffHunk::Unfolded {
24796                        status: hunk.status(),
24797                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24798                            ..hunk.diff_base_byte_range.end.0,
24799                        word_diffs: hunk.word_diffs,
24800                        display_row_range: hunk_display_start.row()..end_row,
24801                        multi_buffer_range: Anchor::range_in_buffer(
24802                            hunk.excerpt_id,
24803                            hunk.buffer_range,
24804                        ),
24805                        is_created_file,
24806                    }
24807                };
24808
24809                Some(display_hunk)
24810            })
24811    }
24812
24813    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24814        self.display_snapshot
24815            .buffer_snapshot()
24816            .language_at(position)
24817    }
24818
24819    pub fn is_focused(&self) -> bool {
24820        self.is_focused
24821    }
24822
24823    pub fn placeholder_text(&self) -> Option<String> {
24824        self.placeholder_display_snapshot
24825            .as_ref()
24826            .map(|display_map| display_map.text())
24827    }
24828
24829    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24830        self.scroll_anchor.scroll_position(&self.display_snapshot)
24831    }
24832
24833    pub fn gutter_dimensions(
24834        &self,
24835        font_id: FontId,
24836        font_size: Pixels,
24837        style: &EditorStyle,
24838        window: &mut Window,
24839        cx: &App,
24840    ) -> GutterDimensions {
24841        if self.show_gutter
24842            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
24843            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
24844        {
24845            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24846                matches!(
24847                    ProjectSettings::get_global(cx).git.git_gutter,
24848                    GitGutterSetting::TrackedFiles
24849                )
24850            });
24851            let gutter_settings = EditorSettings::get_global(cx).gutter;
24852            let show_line_numbers = self
24853                .show_line_numbers
24854                .unwrap_or(gutter_settings.line_numbers);
24855            let line_gutter_width = if show_line_numbers {
24856                // Avoid flicker-like gutter resizes when the line number gains another digit by
24857                // only resizing the gutter on files with > 10**min_line_number_digits lines.
24858                let min_width_for_number_on_gutter =
24859                    ch_advance * gutter_settings.min_line_number_digits as f32;
24860                self.max_line_number_width(style, window)
24861                    .max(min_width_for_number_on_gutter)
24862            } else {
24863                0.0.into()
24864            };
24865
24866            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24867            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24868
24869            let git_blame_entries_width =
24870                self.git_blame_gutter_max_author_length
24871                    .map(|max_author_length| {
24872                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24873                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24874
24875                        /// The number of characters to dedicate to gaps and margins.
24876                        const SPACING_WIDTH: usize = 4;
24877
24878                        let max_char_count = max_author_length.min(renderer.max_author_length())
24879                            + ::git::SHORT_SHA_LENGTH
24880                            + MAX_RELATIVE_TIMESTAMP.len()
24881                            + SPACING_WIDTH;
24882
24883                        ch_advance * max_char_count
24884                    });
24885
24886            let is_singleton = self.buffer_snapshot().is_singleton();
24887
24888            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24889            left_padding += if !is_singleton {
24890                ch_width * 4.0
24891            } else if show_runnables || show_breakpoints {
24892                ch_width * 3.0
24893            } else if show_git_gutter && show_line_numbers {
24894                ch_width * 2.0
24895            } else if show_git_gutter || show_line_numbers {
24896                ch_width
24897            } else {
24898                px(0.)
24899            };
24900
24901            let shows_folds = is_singleton && gutter_settings.folds;
24902
24903            let right_padding = if shows_folds && show_line_numbers {
24904                ch_width * 4.0
24905            } else if shows_folds || (!is_singleton && show_line_numbers) {
24906                ch_width * 3.0
24907            } else if show_line_numbers {
24908                ch_width
24909            } else {
24910                px(0.)
24911            };
24912
24913            GutterDimensions {
24914                left_padding,
24915                right_padding,
24916                width: line_gutter_width + left_padding + right_padding,
24917                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24918                git_blame_entries_width,
24919            }
24920        } else if self.offset_content {
24921            GutterDimensions::default_with_margin(font_id, font_size, cx)
24922        } else {
24923            GutterDimensions::default()
24924        }
24925    }
24926
24927    pub fn render_crease_toggle(
24928        &self,
24929        buffer_row: MultiBufferRow,
24930        row_contains_cursor: bool,
24931        editor: Entity<Editor>,
24932        window: &mut Window,
24933        cx: &mut App,
24934    ) -> Option<AnyElement> {
24935        let folded = self.is_line_folded(buffer_row);
24936        let mut is_foldable = false;
24937
24938        if let Some(crease) = self
24939            .crease_snapshot
24940            .query_row(buffer_row, self.buffer_snapshot())
24941        {
24942            is_foldable = true;
24943            match crease {
24944                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24945                    if let Some(render_toggle) = render_toggle {
24946                        let toggle_callback =
24947                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24948                                if folded {
24949                                    editor.update(cx, |editor, cx| {
24950                                        editor.fold_at(buffer_row, window, cx)
24951                                    });
24952                                } else {
24953                                    editor.update(cx, |editor, cx| {
24954                                        editor.unfold_at(buffer_row, window, cx)
24955                                    });
24956                                }
24957                            });
24958                        return Some((render_toggle)(
24959                            buffer_row,
24960                            folded,
24961                            toggle_callback,
24962                            window,
24963                            cx,
24964                        ));
24965                    }
24966                }
24967            }
24968        }
24969
24970        is_foldable |= self.starts_indent(buffer_row);
24971
24972        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24973            Some(
24974                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24975                    .toggle_state(folded)
24976                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24977                        if folded {
24978                            this.unfold_at(buffer_row, window, cx);
24979                        } else {
24980                            this.fold_at(buffer_row, window, cx);
24981                        }
24982                    }))
24983                    .into_any_element(),
24984            )
24985        } else {
24986            None
24987        }
24988    }
24989
24990    pub fn render_crease_trailer(
24991        &self,
24992        buffer_row: MultiBufferRow,
24993        window: &mut Window,
24994        cx: &mut App,
24995    ) -> Option<AnyElement> {
24996        let folded = self.is_line_folded(buffer_row);
24997        if let Crease::Inline { render_trailer, .. } = self
24998            .crease_snapshot
24999            .query_row(buffer_row, self.buffer_snapshot())?
25000        {
25001            let render_trailer = render_trailer.as_ref()?;
25002            Some(render_trailer(buffer_row, folded, window, cx))
25003        } else {
25004            None
25005        }
25006    }
25007
25008    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
25009        let digit_count = self.widest_line_number().ilog10() + 1;
25010        column_pixels(style, digit_count as usize, window)
25011    }
25012}
25013
25014pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
25015    let font_size = style.text.font_size.to_pixels(window.rem_size());
25016    let layout = window.text_system().shape_line(
25017        SharedString::from(" ".repeat(column)),
25018        font_size,
25019        &[TextRun {
25020            len: column,
25021            font: style.text.font(),
25022            color: Hsla::default(),
25023            ..Default::default()
25024        }],
25025        None,
25026    );
25027
25028    layout.width
25029}
25030
25031impl Deref for EditorSnapshot {
25032    type Target = DisplaySnapshot;
25033
25034    fn deref(&self) -> &Self::Target {
25035        &self.display_snapshot
25036    }
25037}
25038
25039#[derive(Clone, Debug, PartialEq, Eq)]
25040pub enum EditorEvent {
25041    InputIgnored {
25042        text: Arc<str>,
25043    },
25044    InputHandled {
25045        utf16_range_to_replace: Option<Range<isize>>,
25046        text: Arc<str>,
25047    },
25048    ExcerptsAdded {
25049        buffer: Entity<Buffer>,
25050        predecessor: ExcerptId,
25051        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
25052    },
25053    ExcerptsRemoved {
25054        ids: Vec<ExcerptId>,
25055        removed_buffer_ids: Vec<BufferId>,
25056    },
25057    BufferFoldToggled {
25058        ids: Vec<ExcerptId>,
25059        folded: bool,
25060    },
25061    ExcerptsEdited {
25062        ids: Vec<ExcerptId>,
25063    },
25064    ExcerptsExpanded {
25065        ids: Vec<ExcerptId>,
25066    },
25067    BufferEdited,
25068    Edited {
25069        transaction_id: clock::Lamport,
25070    },
25071    Reparsed(BufferId),
25072    Focused,
25073    FocusedIn,
25074    Blurred,
25075    DirtyChanged,
25076    Saved,
25077    TitleChanged,
25078    SelectionsChanged {
25079        local: bool,
25080    },
25081    ScrollPositionChanged {
25082        local: bool,
25083        autoscroll: bool,
25084    },
25085    TransactionUndone {
25086        transaction_id: clock::Lamport,
25087    },
25088    TransactionBegun {
25089        transaction_id: clock::Lamport,
25090    },
25091    CursorShapeChanged,
25092    BreadcrumbsChanged,
25093    PushedToNavHistory {
25094        anchor: Anchor,
25095        is_deactivate: bool,
25096    },
25097}
25098
25099impl EventEmitter<EditorEvent> for Editor {}
25100
25101impl Focusable for Editor {
25102    fn focus_handle(&self, _cx: &App) -> FocusHandle {
25103        self.focus_handle.clone()
25104    }
25105}
25106
25107impl Render for Editor {
25108    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25109        EditorElement::new(&cx.entity(), self.create_style(cx))
25110    }
25111}
25112
25113impl EntityInputHandler for Editor {
25114    fn text_for_range(
25115        &mut self,
25116        range_utf16: Range<usize>,
25117        adjusted_range: &mut Option<Range<usize>>,
25118        _: &mut Window,
25119        cx: &mut Context<Self>,
25120    ) -> Option<String> {
25121        let snapshot = self.buffer.read(cx).read(cx);
25122        let start = snapshot.clip_offset_utf16(
25123            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
25124            Bias::Left,
25125        );
25126        let end = snapshot.clip_offset_utf16(
25127            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
25128            Bias::Right,
25129        );
25130        if (start.0.0..end.0.0) != range_utf16 {
25131            adjusted_range.replace(start.0.0..end.0.0);
25132        }
25133        Some(snapshot.text_for_range(start..end).collect())
25134    }
25135
25136    fn selected_text_range(
25137        &mut self,
25138        ignore_disabled_input: bool,
25139        _: &mut Window,
25140        cx: &mut Context<Self>,
25141    ) -> Option<UTF16Selection> {
25142        // Prevent the IME menu from appearing when holding down an alphabetic key
25143        // while input is disabled.
25144        if !ignore_disabled_input && !self.input_enabled {
25145            return None;
25146        }
25147
25148        let selection = self
25149            .selections
25150            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25151        let range = selection.range();
25152
25153        Some(UTF16Selection {
25154            range: range.start.0.0..range.end.0.0,
25155            reversed: selection.reversed,
25156        })
25157    }
25158
25159    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
25160        let snapshot = self.buffer.read(cx).read(cx);
25161        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
25162        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
25163    }
25164
25165    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25166        self.clear_highlights::<InputComposition>(cx);
25167        self.ime_transaction.take();
25168    }
25169
25170    fn replace_text_in_range(
25171        &mut self,
25172        range_utf16: Option<Range<usize>>,
25173        text: &str,
25174        window: &mut Window,
25175        cx: &mut Context<Self>,
25176    ) {
25177        if !self.input_enabled {
25178            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25179            return;
25180        }
25181
25182        self.transact(window, cx, |this, window, cx| {
25183            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
25184                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25185                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25186                Some(this.selection_replacement_ranges(range_utf16, cx))
25187            } else {
25188                this.marked_text_ranges(cx)
25189            };
25190
25191            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
25192                let newest_selection_id = this.selections.newest_anchor().id;
25193                this.selections
25194                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25195                    .iter()
25196                    .zip(ranges_to_replace.iter())
25197                    .find_map(|(selection, range)| {
25198                        if selection.id == newest_selection_id {
25199                            Some(
25200                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25201                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25202                            )
25203                        } else {
25204                            None
25205                        }
25206                    })
25207            });
25208
25209            cx.emit(EditorEvent::InputHandled {
25210                utf16_range_to_replace: range_to_replace,
25211                text: text.into(),
25212            });
25213
25214            if let Some(new_selected_ranges) = new_selected_ranges {
25215                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25216                    selections.select_ranges(new_selected_ranges)
25217                });
25218                this.backspace(&Default::default(), window, cx);
25219            }
25220
25221            this.handle_input(text, window, cx);
25222        });
25223
25224        if let Some(transaction) = self.ime_transaction {
25225            self.buffer.update(cx, |buffer, cx| {
25226                buffer.group_until_transaction(transaction, cx);
25227            });
25228        }
25229
25230        self.unmark_text(window, cx);
25231    }
25232
25233    fn replace_and_mark_text_in_range(
25234        &mut self,
25235        range_utf16: Option<Range<usize>>,
25236        text: &str,
25237        new_selected_range_utf16: Option<Range<usize>>,
25238        window: &mut Window,
25239        cx: &mut Context<Self>,
25240    ) {
25241        if !self.input_enabled {
25242            return;
25243        }
25244
25245        let transaction = self.transact(window, cx, |this, window, cx| {
25246            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
25247                let snapshot = this.buffer.read(cx).read(cx);
25248                if let Some(relative_range_utf16) = range_utf16.as_ref() {
25249                    for marked_range in &mut marked_ranges {
25250                        marked_range.end = marked_range.start + relative_range_utf16.end;
25251                        marked_range.start += relative_range_utf16.start;
25252                        marked_range.start =
25253                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
25254                        marked_range.end =
25255                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
25256                    }
25257                }
25258                Some(marked_ranges)
25259            } else if let Some(range_utf16) = range_utf16 {
25260                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25261                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25262                Some(this.selection_replacement_ranges(range_utf16, cx))
25263            } else {
25264                None
25265            };
25266
25267            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
25268                let newest_selection_id = this.selections.newest_anchor().id;
25269                this.selections
25270                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25271                    .iter()
25272                    .zip(ranges_to_replace.iter())
25273                    .find_map(|(selection, range)| {
25274                        if selection.id == newest_selection_id {
25275                            Some(
25276                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25277                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25278                            )
25279                        } else {
25280                            None
25281                        }
25282                    })
25283            });
25284
25285            cx.emit(EditorEvent::InputHandled {
25286                utf16_range_to_replace: range_to_replace,
25287                text: text.into(),
25288            });
25289
25290            if let Some(ranges) = ranges_to_replace {
25291                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25292                    s.select_ranges(ranges)
25293                });
25294            }
25295
25296            let marked_ranges = {
25297                let snapshot = this.buffer.read(cx).read(cx);
25298                this.selections
25299                    .disjoint_anchors_arc()
25300                    .iter()
25301                    .map(|selection| {
25302                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
25303                    })
25304                    .collect::<Vec<_>>()
25305            };
25306
25307            if text.is_empty() {
25308                this.unmark_text(window, cx);
25309            } else {
25310                this.highlight_text::<InputComposition>(
25311                    marked_ranges.clone(),
25312                    HighlightStyle {
25313                        underline: Some(UnderlineStyle {
25314                            thickness: px(1.),
25315                            color: None,
25316                            wavy: false,
25317                        }),
25318                        ..Default::default()
25319                    },
25320                    cx,
25321                );
25322            }
25323
25324            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
25325            let use_autoclose = this.use_autoclose;
25326            let use_auto_surround = this.use_auto_surround;
25327            this.set_use_autoclose(false);
25328            this.set_use_auto_surround(false);
25329            this.handle_input(text, window, cx);
25330            this.set_use_autoclose(use_autoclose);
25331            this.set_use_auto_surround(use_auto_surround);
25332
25333            if let Some(new_selected_range) = new_selected_range_utf16 {
25334                let snapshot = this.buffer.read(cx).read(cx);
25335                let new_selected_ranges = marked_ranges
25336                    .into_iter()
25337                    .map(|marked_range| {
25338                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
25339                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
25340                            insertion_start.0 + new_selected_range.start,
25341                        ));
25342                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
25343                            insertion_start.0 + new_selected_range.end,
25344                        ));
25345                        snapshot.clip_offset_utf16(new_start, Bias::Left)
25346                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
25347                    })
25348                    .collect::<Vec<_>>();
25349
25350                drop(snapshot);
25351                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25352                    selections.select_ranges(new_selected_ranges)
25353                });
25354            }
25355        });
25356
25357        self.ime_transaction = self.ime_transaction.or(transaction);
25358        if let Some(transaction) = self.ime_transaction {
25359            self.buffer.update(cx, |buffer, cx| {
25360                buffer.group_until_transaction(transaction, cx);
25361            });
25362        }
25363
25364        if self.text_highlights::<InputComposition>(cx).is_none() {
25365            self.ime_transaction.take();
25366        }
25367    }
25368
25369    fn bounds_for_range(
25370        &mut self,
25371        range_utf16: Range<usize>,
25372        element_bounds: gpui::Bounds<Pixels>,
25373        window: &mut Window,
25374        cx: &mut Context<Self>,
25375    ) -> Option<gpui::Bounds<Pixels>> {
25376        let text_layout_details = self.text_layout_details(window);
25377        let CharacterDimensions {
25378            em_width,
25379            em_advance,
25380            line_height,
25381        } = self.character_dimensions(window);
25382
25383        let snapshot = self.snapshot(window, cx);
25384        let scroll_position = snapshot.scroll_position();
25385        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
25386
25387        let start =
25388            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
25389        let x = Pixels::from(
25390            ScrollOffset::from(
25391                snapshot.x_for_display_point(start, &text_layout_details)
25392                    + self.gutter_dimensions.full_width(),
25393            ) - scroll_left,
25394        );
25395        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
25396
25397        Some(Bounds {
25398            origin: element_bounds.origin + point(x, y),
25399            size: size(em_width, line_height),
25400        })
25401    }
25402
25403    fn character_index_for_point(
25404        &mut self,
25405        point: gpui::Point<Pixels>,
25406        _window: &mut Window,
25407        _cx: &mut Context<Self>,
25408    ) -> Option<usize> {
25409        let position_map = self.last_position_map.as_ref()?;
25410        if !position_map.text_hitbox.contains(&point) {
25411            return None;
25412        }
25413        let display_point = position_map.point_for_position(point).previous_valid;
25414        let anchor = position_map
25415            .snapshot
25416            .display_point_to_anchor(display_point, Bias::Left);
25417        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
25418        Some(utf16_offset.0.0)
25419    }
25420
25421    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
25422        self.input_enabled
25423    }
25424}
25425
25426trait SelectionExt {
25427    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
25428    fn spanned_rows(
25429        &self,
25430        include_end_if_at_line_start: bool,
25431        map: &DisplaySnapshot,
25432    ) -> Range<MultiBufferRow>;
25433}
25434
25435impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
25436    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
25437        let start = self
25438            .start
25439            .to_point(map.buffer_snapshot())
25440            .to_display_point(map);
25441        let end = self
25442            .end
25443            .to_point(map.buffer_snapshot())
25444            .to_display_point(map);
25445        if self.reversed {
25446            end..start
25447        } else {
25448            start..end
25449        }
25450    }
25451
25452    fn spanned_rows(
25453        &self,
25454        include_end_if_at_line_start: bool,
25455        map: &DisplaySnapshot,
25456    ) -> Range<MultiBufferRow> {
25457        let start = self.start.to_point(map.buffer_snapshot());
25458        let mut end = self.end.to_point(map.buffer_snapshot());
25459        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
25460            end.row -= 1;
25461        }
25462
25463        let buffer_start = map.prev_line_boundary(start).0;
25464        let buffer_end = map.next_line_boundary(end).0;
25465        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
25466    }
25467}
25468
25469impl<T: InvalidationRegion> InvalidationStack<T> {
25470    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
25471    where
25472        S: Clone + ToOffset,
25473    {
25474        while let Some(region) = self.last() {
25475            let all_selections_inside_invalidation_ranges =
25476                if selections.len() == region.ranges().len() {
25477                    selections
25478                        .iter()
25479                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
25480                        .all(|(selection, invalidation_range)| {
25481                            let head = selection.head().to_offset(buffer);
25482                            invalidation_range.start <= head && invalidation_range.end >= head
25483                        })
25484                } else {
25485                    false
25486                };
25487
25488            if all_selections_inside_invalidation_ranges {
25489                break;
25490            } else {
25491                self.pop();
25492            }
25493        }
25494    }
25495}
25496
25497impl<T> Default for InvalidationStack<T> {
25498    fn default() -> Self {
25499        Self(Default::default())
25500    }
25501}
25502
25503impl<T> Deref for InvalidationStack<T> {
25504    type Target = Vec<T>;
25505
25506    fn deref(&self) -> &Self::Target {
25507        &self.0
25508    }
25509}
25510
25511impl<T> DerefMut for InvalidationStack<T> {
25512    fn deref_mut(&mut self) -> &mut Self::Target {
25513        &mut self.0
25514    }
25515}
25516
25517impl InvalidationRegion for SnippetState {
25518    fn ranges(&self) -> &[Range<Anchor>] {
25519        &self.ranges[self.active_index]
25520    }
25521}
25522
25523fn edit_prediction_edit_text(
25524    current_snapshot: &BufferSnapshot,
25525    edits: &[(Range<Anchor>, impl AsRef<str>)],
25526    edit_preview: &EditPreview,
25527    include_deletions: bool,
25528    cx: &App,
25529) -> HighlightedText {
25530    let edits = edits
25531        .iter()
25532        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
25533        .collect::<Vec<_>>();
25534
25535    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
25536}
25537
25538fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
25539    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
25540    // Just show the raw edit text with basic styling
25541    let mut text = String::new();
25542    let mut highlights = Vec::new();
25543
25544    let insertion_highlight_style = HighlightStyle {
25545        color: Some(cx.theme().colors().text),
25546        ..Default::default()
25547    };
25548
25549    for (_, edit_text) in edits {
25550        let start_offset = text.len();
25551        text.push_str(edit_text);
25552        let end_offset = text.len();
25553
25554        if start_offset < end_offset {
25555            highlights.push((start_offset..end_offset, insertion_highlight_style));
25556        }
25557    }
25558
25559    HighlightedText {
25560        text: text.into(),
25561        highlights,
25562    }
25563}
25564
25565pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
25566    match severity {
25567        lsp::DiagnosticSeverity::ERROR => colors.error,
25568        lsp::DiagnosticSeverity::WARNING => colors.warning,
25569        lsp::DiagnosticSeverity::INFORMATION => colors.info,
25570        lsp::DiagnosticSeverity::HINT => colors.info,
25571        _ => colors.ignored,
25572    }
25573}
25574
25575pub fn styled_runs_for_code_label<'a>(
25576    label: &'a CodeLabel,
25577    syntax_theme: &'a theme::SyntaxTheme,
25578    local_player: &'a theme::PlayerColor,
25579) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
25580    let fade_out = HighlightStyle {
25581        fade_out: Some(0.35),
25582        ..Default::default()
25583    };
25584
25585    let mut prev_end = label.filter_range.end;
25586    label
25587        .runs
25588        .iter()
25589        .enumerate()
25590        .flat_map(move |(ix, (range, highlight_id))| {
25591            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
25592                HighlightStyle {
25593                    color: Some(local_player.cursor),
25594                    ..Default::default()
25595                }
25596            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
25597                HighlightStyle {
25598                    background_color: Some(local_player.selection),
25599                    ..Default::default()
25600                }
25601            } else if let Some(style) = highlight_id.style(syntax_theme) {
25602                style
25603            } else {
25604                return Default::default();
25605            };
25606            let muted_style = style.highlight(fade_out);
25607
25608            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
25609            if range.start >= label.filter_range.end {
25610                if range.start > prev_end {
25611                    runs.push((prev_end..range.start, fade_out));
25612                }
25613                runs.push((range.clone(), muted_style));
25614            } else if range.end <= label.filter_range.end {
25615                runs.push((range.clone(), style));
25616            } else {
25617                runs.push((range.start..label.filter_range.end, style));
25618                runs.push((label.filter_range.end..range.end, muted_style));
25619            }
25620            prev_end = cmp::max(prev_end, range.end);
25621
25622            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
25623                runs.push((prev_end..label.text.len(), fade_out));
25624            }
25625
25626            runs
25627        })
25628}
25629
25630pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
25631    let mut prev_index = 0;
25632    let mut prev_codepoint: Option<char> = None;
25633    text.char_indices()
25634        .chain([(text.len(), '\0')])
25635        .filter_map(move |(index, codepoint)| {
25636            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25637            let is_boundary = index == text.len()
25638                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
25639                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
25640            if is_boundary {
25641                let chunk = &text[prev_index..index];
25642                prev_index = index;
25643                Some(chunk)
25644            } else {
25645                None
25646            }
25647        })
25648}
25649
25650/// Given a string of text immediately before the cursor, iterates over possible
25651/// strings a snippet could match to. More precisely: returns an iterator over
25652/// suffixes of `text` created by splitting at word boundaries (before & after
25653/// every non-word character).
25654///
25655/// Shorter suffixes are returned first.
25656pub(crate) fn snippet_candidate_suffixes(
25657    text: &str,
25658    is_word_char: impl Fn(char) -> bool,
25659) -> impl std::iter::Iterator<Item = &str> {
25660    let mut prev_index = text.len();
25661    let mut prev_codepoint = None;
25662    text.char_indices()
25663        .rev()
25664        .chain([(0, '\0')])
25665        .filter_map(move |(index, codepoint)| {
25666            let prev_index = std::mem::replace(&mut prev_index, index);
25667            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25668            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
25669                None
25670            } else {
25671                let chunk = &text[prev_index..]; // go to end of string
25672                Some(chunk)
25673            }
25674        })
25675}
25676
25677pub trait RangeToAnchorExt: Sized {
25678    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25679
25680    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25681        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25682        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25683    }
25684}
25685
25686impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25687    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25688        let start_offset = self.start.to_offset(snapshot);
25689        let end_offset = self.end.to_offset(snapshot);
25690        if start_offset == end_offset {
25691            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25692        } else {
25693            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25694        }
25695    }
25696}
25697
25698pub trait RowExt {
25699    fn as_f64(&self) -> f64;
25700
25701    fn next_row(&self) -> Self;
25702
25703    fn previous_row(&self) -> Self;
25704
25705    fn minus(&self, other: Self) -> u32;
25706}
25707
25708impl RowExt for DisplayRow {
25709    fn as_f64(&self) -> f64 {
25710        self.0 as _
25711    }
25712
25713    fn next_row(&self) -> Self {
25714        Self(self.0 + 1)
25715    }
25716
25717    fn previous_row(&self) -> Self {
25718        Self(self.0.saturating_sub(1))
25719    }
25720
25721    fn minus(&self, other: Self) -> u32 {
25722        self.0 - other.0
25723    }
25724}
25725
25726impl RowExt for MultiBufferRow {
25727    fn as_f64(&self) -> f64 {
25728        self.0 as _
25729    }
25730
25731    fn next_row(&self) -> Self {
25732        Self(self.0 + 1)
25733    }
25734
25735    fn previous_row(&self) -> Self {
25736        Self(self.0.saturating_sub(1))
25737    }
25738
25739    fn minus(&self, other: Self) -> u32 {
25740        self.0 - other.0
25741    }
25742}
25743
25744trait RowRangeExt {
25745    type Row;
25746
25747    fn len(&self) -> usize;
25748
25749    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25750}
25751
25752impl RowRangeExt for Range<MultiBufferRow> {
25753    type Row = MultiBufferRow;
25754
25755    fn len(&self) -> usize {
25756        (self.end.0 - self.start.0) as usize
25757    }
25758
25759    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25760        (self.start.0..self.end.0).map(MultiBufferRow)
25761    }
25762}
25763
25764impl RowRangeExt for Range<DisplayRow> {
25765    type Row = DisplayRow;
25766
25767    fn len(&self) -> usize {
25768        (self.end.0 - self.start.0) as usize
25769    }
25770
25771    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25772        (self.start.0..self.end.0).map(DisplayRow)
25773    }
25774}
25775
25776/// If select range has more than one line, we
25777/// just point the cursor to range.start.
25778fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25779    if range.start.row == range.end.row {
25780        range
25781    } else {
25782        range.start..range.start
25783    }
25784}
25785pub struct KillRing(ClipboardItem);
25786impl Global for KillRing {}
25787
25788const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25789
25790enum BreakpointPromptEditAction {
25791    Log,
25792    Condition,
25793    HitCondition,
25794}
25795
25796struct BreakpointPromptEditor {
25797    pub(crate) prompt: Entity<Editor>,
25798    editor: WeakEntity<Editor>,
25799    breakpoint_anchor: Anchor,
25800    breakpoint: Breakpoint,
25801    edit_action: BreakpointPromptEditAction,
25802    block_ids: HashSet<CustomBlockId>,
25803    editor_margins: Arc<Mutex<EditorMargins>>,
25804    _subscriptions: Vec<Subscription>,
25805}
25806
25807impl BreakpointPromptEditor {
25808    const MAX_LINES: u8 = 4;
25809
25810    fn new(
25811        editor: WeakEntity<Editor>,
25812        breakpoint_anchor: Anchor,
25813        breakpoint: Breakpoint,
25814        edit_action: BreakpointPromptEditAction,
25815        window: &mut Window,
25816        cx: &mut Context<Self>,
25817    ) -> Self {
25818        let base_text = match edit_action {
25819            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25820            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25821            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25822        }
25823        .map(|msg| msg.to_string())
25824        .unwrap_or_default();
25825
25826        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25827        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25828
25829        let prompt = cx.new(|cx| {
25830            let mut prompt = Editor::new(
25831                EditorMode::AutoHeight {
25832                    min_lines: 1,
25833                    max_lines: Some(Self::MAX_LINES as usize),
25834                },
25835                buffer,
25836                None,
25837                window,
25838                cx,
25839            );
25840            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25841            prompt.set_show_cursor_when_unfocused(false, cx);
25842            prompt.set_placeholder_text(
25843                match edit_action {
25844                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25845                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25846                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25847                },
25848                window,
25849                cx,
25850            );
25851
25852            prompt
25853        });
25854
25855        Self {
25856            prompt,
25857            editor,
25858            breakpoint_anchor,
25859            breakpoint,
25860            edit_action,
25861            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25862            block_ids: Default::default(),
25863            _subscriptions: vec![],
25864        }
25865    }
25866
25867    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25868        self.block_ids.extend(block_ids)
25869    }
25870
25871    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25872        if let Some(editor) = self.editor.upgrade() {
25873            let message = self
25874                .prompt
25875                .read(cx)
25876                .buffer
25877                .read(cx)
25878                .as_singleton()
25879                .expect("A multi buffer in breakpoint prompt isn't possible")
25880                .read(cx)
25881                .as_rope()
25882                .to_string();
25883
25884            editor.update(cx, |editor, cx| {
25885                editor.edit_breakpoint_at_anchor(
25886                    self.breakpoint_anchor,
25887                    self.breakpoint.clone(),
25888                    match self.edit_action {
25889                        BreakpointPromptEditAction::Log => {
25890                            BreakpointEditAction::EditLogMessage(message.into())
25891                        }
25892                        BreakpointPromptEditAction::Condition => {
25893                            BreakpointEditAction::EditCondition(message.into())
25894                        }
25895                        BreakpointPromptEditAction::HitCondition => {
25896                            BreakpointEditAction::EditHitCondition(message.into())
25897                        }
25898                    },
25899                    cx,
25900                );
25901
25902                editor.remove_blocks(self.block_ids.clone(), None, cx);
25903                cx.focus_self(window);
25904            });
25905        }
25906    }
25907
25908    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25909        self.editor
25910            .update(cx, |editor, cx| {
25911                editor.remove_blocks(self.block_ids.clone(), None, cx);
25912                window.focus(&editor.focus_handle, cx);
25913            })
25914            .log_err();
25915    }
25916
25917    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25918        let settings = ThemeSettings::get_global(cx);
25919        let text_style = TextStyle {
25920            color: if self.prompt.read(cx).read_only(cx) {
25921                cx.theme().colors().text_disabled
25922            } else {
25923                cx.theme().colors().text
25924            },
25925            font_family: settings.buffer_font.family.clone(),
25926            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25927            font_size: settings.buffer_font_size(cx).into(),
25928            font_weight: settings.buffer_font.weight,
25929            line_height: relative(settings.buffer_line_height.value()),
25930            ..Default::default()
25931        };
25932        EditorElement::new(
25933            &self.prompt,
25934            EditorStyle {
25935                background: cx.theme().colors().editor_background,
25936                local_player: cx.theme().players().local(),
25937                text: text_style,
25938                ..Default::default()
25939            },
25940        )
25941    }
25942}
25943
25944impl Render for BreakpointPromptEditor {
25945    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25946        let editor_margins = *self.editor_margins.lock();
25947        let gutter_dimensions = editor_margins.gutter;
25948        h_flex()
25949            .key_context("Editor")
25950            .bg(cx.theme().colors().editor_background)
25951            .border_y_1()
25952            .border_color(cx.theme().status().info_border)
25953            .size_full()
25954            .py(window.line_height() / 2.5)
25955            .on_action(cx.listener(Self::confirm))
25956            .on_action(cx.listener(Self::cancel))
25957            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25958            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25959    }
25960}
25961
25962impl Focusable for BreakpointPromptEditor {
25963    fn focus_handle(&self, cx: &App) -> FocusHandle {
25964        self.prompt.focus_handle(cx)
25965    }
25966}
25967
25968fn all_edits_insertions_or_deletions(
25969    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25970    snapshot: &MultiBufferSnapshot,
25971) -> bool {
25972    let mut all_insertions = true;
25973    let mut all_deletions = true;
25974
25975    for (range, new_text) in edits.iter() {
25976        let range_is_empty = range.to_offset(snapshot).is_empty();
25977        let text_is_empty = new_text.is_empty();
25978
25979        if range_is_empty != text_is_empty {
25980            if range_is_empty {
25981                all_deletions = false;
25982            } else {
25983                all_insertions = false;
25984            }
25985        } else {
25986            return false;
25987        }
25988
25989        if !all_insertions && !all_deletions {
25990            return false;
25991        }
25992    }
25993    all_insertions || all_deletions
25994}
25995
25996struct MissingEditPredictionKeybindingTooltip;
25997
25998impl Render for MissingEditPredictionKeybindingTooltip {
25999    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26000        ui::tooltip_container(cx, |container, cx| {
26001            container
26002                .flex_shrink_0()
26003                .max_w_80()
26004                .min_h(rems_from_px(124.))
26005                .justify_between()
26006                .child(
26007                    v_flex()
26008                        .flex_1()
26009                        .text_ui_sm(cx)
26010                        .child(Label::new("Conflict with Accept Keybinding"))
26011                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
26012                )
26013                .child(
26014                    h_flex()
26015                        .pb_1()
26016                        .gap_1()
26017                        .items_end()
26018                        .w_full()
26019                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
26020                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
26021                        }))
26022                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
26023                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
26024                        })),
26025                )
26026        })
26027    }
26028}
26029
26030#[derive(Debug, Clone, Copy, PartialEq)]
26031pub struct LineHighlight {
26032    pub background: Background,
26033    pub border: Option<gpui::Hsla>,
26034    pub include_gutter: bool,
26035    pub type_id: Option<TypeId>,
26036}
26037
26038struct LineManipulationResult {
26039    pub new_text: String,
26040    pub line_count_before: usize,
26041    pub line_count_after: usize,
26042}
26043
26044fn render_diff_hunk_controls(
26045    row: u32,
26046    status: &DiffHunkStatus,
26047    hunk_range: Range<Anchor>,
26048    is_created_file: bool,
26049    line_height: Pixels,
26050    editor: &Entity<Editor>,
26051    _window: &mut Window,
26052    cx: &mut App,
26053) -> AnyElement {
26054    h_flex()
26055        .h(line_height)
26056        .mr_1()
26057        .gap_1()
26058        .px_0p5()
26059        .pb_1()
26060        .border_x_1()
26061        .border_b_1()
26062        .border_color(cx.theme().colors().border_variant)
26063        .rounded_b_lg()
26064        .bg(cx.theme().colors().editor_background)
26065        .gap_1()
26066        .block_mouse_except_scroll()
26067        .shadow_md()
26068        .child(if status.has_secondary_hunk() {
26069            Button::new(("stage", row as u64), "Stage")
26070                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26071                .tooltip({
26072                    let focus_handle = editor.focus_handle(cx);
26073                    move |_window, cx| {
26074                        Tooltip::for_action_in(
26075                            "Stage Hunk",
26076                            &::git::ToggleStaged,
26077                            &focus_handle,
26078                            cx,
26079                        )
26080                    }
26081                })
26082                .on_click({
26083                    let editor = editor.clone();
26084                    move |_event, _window, cx| {
26085                        editor.update(cx, |editor, cx| {
26086                            editor.stage_or_unstage_diff_hunks(
26087                                true,
26088                                vec![hunk_range.start..hunk_range.start],
26089                                cx,
26090                            );
26091                        });
26092                    }
26093                })
26094        } else {
26095            Button::new(("unstage", row as u64), "Unstage")
26096                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26097                .tooltip({
26098                    let focus_handle = editor.focus_handle(cx);
26099                    move |_window, cx| {
26100                        Tooltip::for_action_in(
26101                            "Unstage Hunk",
26102                            &::git::ToggleStaged,
26103                            &focus_handle,
26104                            cx,
26105                        )
26106                    }
26107                })
26108                .on_click({
26109                    let editor = editor.clone();
26110                    move |_event, _window, cx| {
26111                        editor.update(cx, |editor, cx| {
26112                            editor.stage_or_unstage_diff_hunks(
26113                                false,
26114                                vec![hunk_range.start..hunk_range.start],
26115                                cx,
26116                            );
26117                        });
26118                    }
26119                })
26120        })
26121        .child(
26122            Button::new(("restore", row as u64), "Restore")
26123                .tooltip({
26124                    let focus_handle = editor.focus_handle(cx);
26125                    move |_window, cx| {
26126                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
26127                    }
26128                })
26129                .on_click({
26130                    let editor = editor.clone();
26131                    move |_event, window, cx| {
26132                        editor.update(cx, |editor, cx| {
26133                            let snapshot = editor.snapshot(window, cx);
26134                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
26135                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
26136                        });
26137                    }
26138                })
26139                .disabled(is_created_file),
26140        )
26141        .when(
26142            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
26143            |el| {
26144                el.child(
26145                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
26146                        .shape(IconButtonShape::Square)
26147                        .icon_size(IconSize::Small)
26148                        // .disabled(!has_multiple_hunks)
26149                        .tooltip({
26150                            let focus_handle = editor.focus_handle(cx);
26151                            move |_window, cx| {
26152                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
26153                            }
26154                        })
26155                        .on_click({
26156                            let editor = editor.clone();
26157                            move |_event, window, cx| {
26158                                editor.update(cx, |editor, cx| {
26159                                    let snapshot = editor.snapshot(window, cx);
26160                                    let position =
26161                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
26162                                    editor.go_to_hunk_before_or_after_position(
26163                                        &snapshot,
26164                                        position,
26165                                        Direction::Next,
26166                                        window,
26167                                        cx,
26168                                    );
26169                                    editor.expand_selected_diff_hunks(cx);
26170                                });
26171                            }
26172                        }),
26173                )
26174                .child(
26175                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
26176                        .shape(IconButtonShape::Square)
26177                        .icon_size(IconSize::Small)
26178                        // .disabled(!has_multiple_hunks)
26179                        .tooltip({
26180                            let focus_handle = editor.focus_handle(cx);
26181                            move |_window, cx| {
26182                                Tooltip::for_action_in(
26183                                    "Previous Hunk",
26184                                    &GoToPreviousHunk,
26185                                    &focus_handle,
26186                                    cx,
26187                                )
26188                            }
26189                        })
26190                        .on_click({
26191                            let editor = editor.clone();
26192                            move |_event, window, cx| {
26193                                editor.update(cx, |editor, cx| {
26194                                    let snapshot = editor.snapshot(window, cx);
26195                                    let point =
26196                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
26197                                    editor.go_to_hunk_before_or_after_position(
26198                                        &snapshot,
26199                                        point,
26200                                        Direction::Prev,
26201                                        window,
26202                                        cx,
26203                                    );
26204                                    editor.expand_selected_diff_hunks(cx);
26205                                });
26206                            }
26207                        }),
26208                )
26209            },
26210        )
26211        .into_any_element()
26212}
26213
26214pub fn multibuffer_context_lines(cx: &App) -> u32 {
26215    EditorSettings::try_get(cx)
26216        .map(|settings| settings.excerpt_context_lines)
26217        .unwrap_or(2)
26218        .min(32)
26219}