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;
   15mod blink_manager;
   16mod clangd_ext;
   17pub mod code_context_menus;
   18pub mod display_map;
   19mod editor_settings;
   20mod element;
   21mod git;
   22mod highlight_matching_bracket;
   23mod hover_links;
   24pub mod hover_popover;
   25mod indent_guides;
   26mod inlays;
   27pub mod items;
   28mod jsx_tag_auto_close;
   29mod linked_editing_ranges;
   30mod lsp_colors;
   31mod lsp_ext;
   32mod mouse_context_menu;
   33pub mod movement;
   34mod persistence;
   35mod rust_analyzer_ext;
   36pub mod scroll;
   37mod selections_collection;
   38pub mod tasks;
   39
   40#[cfg(test)]
   41mod code_completion_tests;
   42#[cfg(test)]
   43mod edit_prediction_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46mod signature_help;
   47#[cfg(any(test, feature = "test-support"))]
   48pub mod test;
   49
   50pub(crate) use actions::*;
   51pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   52pub use edit_prediction::Direction;
   53pub use editor_settings::{
   54    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   55    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   56};
   57pub use element::{
   58    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   59};
   60pub use git::blame::BlameRenderer;
   61pub use hover_popover::hover_markdown_style;
   62pub use inlays::Inlay;
   63pub use items::MAX_TAB_TITLE_LEN;
   64pub use lsp::CompletionContext;
   65pub use lsp_ext::lsp_tasks;
   66pub use multi_buffer::{
   67    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   68    RowInfo, ToOffset, ToPoint,
   69};
   70pub use text::Bias;
   71
   72use ::git::{
   73    Restore,
   74    blame::{BlameEntry, ParsedCommitMessage},
   75    status::FileStatus,
   76};
   77use aho_corasick::AhoCorasick;
   78use anyhow::{Context as _, Result, anyhow};
   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::{EditPredictionProvider, EditPredictionProviderHandle};
   92use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   93use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   94use futures::{
   95    FutureExt, StreamExt as _,
   96    future::{self, Shared, join},
   97    stream::FuturesUnordered,
   98};
   99use fuzzy::{StringMatch, StringMatchCandidate};
  100use git::blame::{GitBlame, GlobalBlameRenderer};
  101use gpui::{
  102    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  103    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  104    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  105    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  106    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  107    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  108    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  109    div, point, prelude::*, pulsating_between, px, relative, size,
  110};
  111use hover_links::{HoverLink, HoveredLinkState, find_file};
  112use hover_popover::{HoverState, hide_hover};
  113use indent_guides::ActiveIndentGuidesState;
  114use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  115use itertools::{Either, Itertools};
  116use language::{
  117    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  118    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  119    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  120    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  121    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  122    language_settings::{
  123        self, LspInsertMode, RewrapBehavior, WordsCompletionMode, all_language_settings,
  124        language_settings,
  125    },
  126    point_from_lsp, point_to_lsp, text_diff_with_options,
  127};
  128use linked_editing_ranges::refresh_linked_ranges;
  129use lsp::{
  130    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  131    LanguageServerId,
  132};
  133use lsp_colors::LspColorData;
  134use markdown::Markdown;
  135use mouse_context_menu::MouseContextMenu;
  136use movement::TextLayoutDetails;
  137use multi_buffer::{
  138    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  139};
  140use parking_lot::Mutex;
  141use persistence::DB;
  142use project::{
  143    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  144    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  145    InvalidationStrategy, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem,
  146    ProjectPath, ProjectTransaction, TaskSourceKind,
  147    debugger::{
  148        breakpoint_store::{
  149            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  150            BreakpointStore, BreakpointStoreEvent,
  151        },
  152        session::{Session, SessionEvent},
  153    },
  154    git_store::GitStoreEvent,
  155    lsp_store::{
  156        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  157        OpenLspBufferHandle,
  158    },
  159    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  160};
  161use rand::seq::SliceRandom;
  162use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  163use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  164use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  165use serde::{Deserialize, Serialize};
  166use settings::{
  167    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  168    update_settings_file,
  169};
  170use smallvec::{SmallVec, smallvec};
  171use snippet::Snippet;
  172use std::{
  173    any::{Any, TypeId},
  174    borrow::Cow,
  175    cell::{OnceCell, RefCell},
  176    cmp::{self, Ordering, Reverse},
  177    iter::{self, Peekable},
  178    mem,
  179    num::NonZeroU32,
  180    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  181    path::{Path, PathBuf},
  182    rc::Rc,
  183    sync::Arc,
  184    time::{Duration, Instant},
  185};
  186use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  187use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  188use theme::{
  189    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  190    observe_buffer_font_size_adjustment,
  191};
  192use ui::{
  193    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  194    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  195};
  196use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  197use workspace::{
  198    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  199    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  200    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  201    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  202    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  203    searchable::SearchEvent,
  204};
  205
  206use crate::{
  207    code_context_menus::CompletionsMenuSource,
  208    editor_settings::MultiCursorModifier,
  209    hover_links::{find_url, find_url_from_range},
  210    inlays::{
  211        InlineValueCache,
  212        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  213    },
  214    scroll::{ScrollOffset, ScrollPixelOffset},
  215    selections_collection::resolve_selections_wrapping_blocks,
  216    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  217};
  218
  219pub const FILE_HEADER_HEIGHT: u32 = 2;
  220pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  221const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  222const MAX_LINE_LEN: usize = 1024;
  223const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  224const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  225pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  226#[doc(hidden)]
  227pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  228pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  229
  230pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  233pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  234
  235pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  236pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  237pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  238
  239pub type RenderDiffHunkControlsFn = Arc<
  240    dyn Fn(
  241        u32,
  242        &DiffHunkStatus,
  243        Range<Anchor>,
  244        bool,
  245        Pixels,
  246        &Entity<Editor>,
  247        &mut Window,
  248        &mut App,
  249    ) -> AnyElement,
  250>;
  251
  252enum ReportEditorEvent {
  253    Saved { auto_saved: bool },
  254    EditorOpened,
  255    Closed,
  256}
  257
  258impl ReportEditorEvent {
  259    pub fn event_type(&self) -> &'static str {
  260        match self {
  261            Self::Saved { .. } => "Editor Saved",
  262            Self::EditorOpened => "Editor Opened",
  263            Self::Closed => "Editor Closed",
  264        }
  265    }
  266}
  267
  268pub enum ActiveDebugLine {}
  269pub enum DebugStackFrameLine {}
  270enum DocumentHighlightRead {}
  271enum DocumentHighlightWrite {}
  272enum InputComposition {}
  273pub enum PendingInput {}
  274enum SelectedTextHighlight {}
  275
  276pub enum ConflictsOuter {}
  277pub enum ConflictsOurs {}
  278pub enum ConflictsTheirs {}
  279pub enum ConflictsOursMarker {}
  280pub enum ConflictsTheirsMarker {}
  281
  282#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  283pub enum Navigated {
  284    Yes,
  285    No,
  286}
  287
  288impl Navigated {
  289    pub fn from_bool(yes: bool) -> Navigated {
  290        if yes { Navigated::Yes } else { Navigated::No }
  291    }
  292}
  293
  294#[derive(Debug, Clone, PartialEq, Eq)]
  295enum DisplayDiffHunk {
  296    Folded {
  297        display_row: DisplayRow,
  298    },
  299    Unfolded {
  300        is_created_file: bool,
  301        diff_base_byte_range: Range<usize>,
  302        display_row_range: Range<DisplayRow>,
  303        multi_buffer_range: Range<Anchor>,
  304        status: DiffHunkStatus,
  305    },
  306}
  307
  308pub enum HideMouseCursorOrigin {
  309    TypingAction,
  310    MovementAction,
  311}
  312
  313pub fn init_settings(cx: &mut App) {
  314    EditorSettings::register(cx);
  315}
  316
  317pub fn init(cx: &mut App) {
  318    init_settings(cx);
  319
  320    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  321
  322    workspace::register_project_item::<Editor>(cx);
  323    workspace::FollowableViewRegistry::register::<Editor>(cx);
  324    workspace::register_serializable_item::<Editor>(cx);
  325
  326    cx.observe_new(
  327        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  328            workspace.register_action(Editor::new_file);
  329            workspace.register_action(Editor::new_file_split);
  330            workspace.register_action(Editor::new_file_vertical);
  331            workspace.register_action(Editor::new_file_horizontal);
  332            workspace.register_action(Editor::cancel_language_server_work);
  333            workspace.register_action(Editor::toggle_focus);
  334        },
  335    )
  336    .detach();
  337
  338    cx.on_action(move |_: &workspace::NewFile, cx| {
  339        let app_state = workspace::AppState::global(cx);
  340        if let Some(app_state) = app_state.upgrade() {
  341            workspace::open_new(
  342                Default::default(),
  343                app_state,
  344                cx,
  345                |workspace, window, cx| {
  346                    Editor::new_file(workspace, &Default::default(), window, cx)
  347                },
  348            )
  349            .detach();
  350        }
  351    });
  352    cx.on_action(move |_: &workspace::NewWindow, cx| {
  353        let app_state = workspace::AppState::global(cx);
  354        if let Some(app_state) = app_state.upgrade() {
  355            workspace::open_new(
  356                Default::default(),
  357                app_state,
  358                cx,
  359                |workspace, window, cx| {
  360                    cx.activate(true);
  361                    Editor::new_file(workspace, &Default::default(), window, cx)
  362                },
  363            )
  364            .detach();
  365        }
  366    });
  367}
  368
  369pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  370    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  371}
  372
  373pub trait DiagnosticRenderer {
  374    fn render_group(
  375        &self,
  376        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  377        buffer_id: BufferId,
  378        snapshot: EditorSnapshot,
  379        editor: WeakEntity<Editor>,
  380        cx: &mut App,
  381    ) -> Vec<BlockProperties<Anchor>>;
  382
  383    fn render_hover(
  384        &self,
  385        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  386        range: Range<Point>,
  387        buffer_id: BufferId,
  388        cx: &mut App,
  389    ) -> Option<Entity<markdown::Markdown>>;
  390
  391    fn open_link(
  392        &self,
  393        editor: &mut Editor,
  394        link: SharedString,
  395        window: &mut Window,
  396        cx: &mut Context<Editor>,
  397    );
  398}
  399
  400pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  401
  402impl GlobalDiagnosticRenderer {
  403    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  404        cx.try_global::<Self>().map(|g| g.0.clone())
  405    }
  406}
  407
  408impl gpui::Global for GlobalDiagnosticRenderer {}
  409pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  410    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  411}
  412
  413pub struct SearchWithinRange;
  414
  415trait InvalidationRegion {
  416    fn ranges(&self) -> &[Range<Anchor>];
  417}
  418
  419#[derive(Clone, Debug, PartialEq)]
  420pub enum SelectPhase {
  421    Begin {
  422        position: DisplayPoint,
  423        add: bool,
  424        click_count: usize,
  425    },
  426    BeginColumnar {
  427        position: DisplayPoint,
  428        reset: bool,
  429        mode: ColumnarMode,
  430        goal_column: u32,
  431    },
  432    Extend {
  433        position: DisplayPoint,
  434        click_count: usize,
  435    },
  436    Update {
  437        position: DisplayPoint,
  438        goal_column: u32,
  439        scroll_delta: gpui::Point<f32>,
  440    },
  441    End,
  442}
  443
  444#[derive(Clone, Debug, PartialEq)]
  445pub enum ColumnarMode {
  446    FromMouse,
  447    FromSelection,
  448}
  449
  450#[derive(Clone, Debug)]
  451pub enum SelectMode {
  452    Character,
  453    Word(Range<Anchor>),
  454    Line(Range<Anchor>),
  455    All,
  456}
  457
  458#[derive(Clone, PartialEq, Eq, Debug)]
  459pub enum EditorMode {
  460    SingleLine,
  461    AutoHeight {
  462        min_lines: usize,
  463        max_lines: Option<usize>,
  464    },
  465    Full {
  466        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  467        scale_ui_elements_with_buffer_font_size: bool,
  468        /// When set to `true`, the editor will render a background for the active line.
  469        show_active_line_background: bool,
  470        /// When set to `true`, the editor's height will be determined by its content.
  471        sized_by_content: bool,
  472    },
  473    Minimap {
  474        parent: WeakEntity<Editor>,
  475    },
  476}
  477
  478impl EditorMode {
  479    pub fn full() -> Self {
  480        Self::Full {
  481            scale_ui_elements_with_buffer_font_size: true,
  482            show_active_line_background: true,
  483            sized_by_content: false,
  484        }
  485    }
  486
  487    #[inline]
  488    pub fn is_full(&self) -> bool {
  489        matches!(self, Self::Full { .. })
  490    }
  491
  492    #[inline]
  493    pub fn is_single_line(&self) -> bool {
  494        matches!(self, Self::SingleLine { .. })
  495    }
  496
  497    #[inline]
  498    fn is_minimap(&self) -> bool {
  499        matches!(self, Self::Minimap { .. })
  500    }
  501}
  502
  503#[derive(Copy, Clone, Debug)]
  504pub enum SoftWrap {
  505    /// Prefer not to wrap at all.
  506    ///
  507    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  508    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  509    GitDiff,
  510    /// Prefer a single line generally, unless an overly long line is encountered.
  511    None,
  512    /// Soft wrap lines that exceed the editor width.
  513    EditorWidth,
  514    /// Soft wrap lines at the preferred line length.
  515    Column(u32),
  516    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  517    Bounded(u32),
  518}
  519
  520#[derive(Clone)]
  521pub struct EditorStyle {
  522    pub background: Hsla,
  523    pub border: Hsla,
  524    pub local_player: PlayerColor,
  525    pub text: TextStyle,
  526    pub scrollbar_width: Pixels,
  527    pub syntax: Arc<SyntaxTheme>,
  528    pub status: StatusColors,
  529    pub inlay_hints_style: HighlightStyle,
  530    pub edit_prediction_styles: EditPredictionStyles,
  531    pub unnecessary_code_fade: f32,
  532    pub show_underlines: bool,
  533}
  534
  535impl Default for EditorStyle {
  536    fn default() -> Self {
  537        Self {
  538            background: Hsla::default(),
  539            border: Hsla::default(),
  540            local_player: PlayerColor::default(),
  541            text: TextStyle::default(),
  542            scrollbar_width: Pixels::default(),
  543            syntax: Default::default(),
  544            // HACK: Status colors don't have a real default.
  545            // We should look into removing the status colors from the editor
  546            // style and retrieve them directly from the theme.
  547            status: StatusColors::dark(),
  548            inlay_hints_style: HighlightStyle::default(),
  549            edit_prediction_styles: EditPredictionStyles {
  550                insertion: HighlightStyle::default(),
  551                whitespace: HighlightStyle::default(),
  552            },
  553            unnecessary_code_fade: Default::default(),
  554            show_underlines: true,
  555        }
  556    }
  557}
  558
  559pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  560    let show_background = language_settings::language_settings(None, None, cx)
  561        .inlay_hints
  562        .show_background;
  563
  564    let mut style = cx.theme().syntax().get("hint");
  565
  566    if style.color.is_none() {
  567        style.color = Some(cx.theme().status().hint);
  568    }
  569
  570    if !show_background {
  571        style.background_color = None;
  572        return style;
  573    }
  574
  575    if style.background_color.is_none() {
  576        style.background_color = Some(cx.theme().status().hint_background);
  577    }
  578
  579    style
  580}
  581
  582pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  583    EditPredictionStyles {
  584        insertion: HighlightStyle {
  585            color: Some(cx.theme().status().predictive),
  586            ..HighlightStyle::default()
  587        },
  588        whitespace: HighlightStyle {
  589            background_color: Some(cx.theme().status().created_background),
  590            ..HighlightStyle::default()
  591        },
  592    }
  593}
  594
  595type CompletionId = usize;
  596
  597pub(crate) enum EditDisplayMode {
  598    TabAccept,
  599    DiffPopover,
  600    Inline,
  601}
  602
  603enum EditPrediction {
  604    Edit {
  605        edits: Vec<(Range<Anchor>, String)>,
  606        edit_preview: Option<EditPreview>,
  607        display_mode: EditDisplayMode,
  608        snapshot: BufferSnapshot,
  609    },
  610    /// Move to a specific location in the active editor
  611    MoveWithin {
  612        target: Anchor,
  613        snapshot: BufferSnapshot,
  614    },
  615    /// Move to a specific location in a different editor (not the active one)
  616    MoveOutside {
  617        target: language::Anchor,
  618        snapshot: BufferSnapshot,
  619    },
  620}
  621
  622struct EditPredictionState {
  623    inlay_ids: Vec<InlayId>,
  624    completion: EditPrediction,
  625    completion_id: Option<SharedString>,
  626    invalidation_range: Option<Range<Anchor>>,
  627}
  628
  629enum EditPredictionSettings {
  630    Disabled,
  631    Enabled {
  632        show_in_menu: bool,
  633        preview_requires_modifier: bool,
  634    },
  635}
  636
  637enum EditPredictionHighlight {}
  638
  639#[derive(Debug, Clone)]
  640struct InlineDiagnostic {
  641    message: SharedString,
  642    group_id: usize,
  643    is_primary: bool,
  644    start: Point,
  645    severity: lsp::DiagnosticSeverity,
  646}
  647
  648pub enum MenuEditPredictionsPolicy {
  649    Never,
  650    ByProvider,
  651}
  652
  653pub enum EditPredictionPreview {
  654    /// Modifier is not pressed
  655    Inactive { released_too_fast: bool },
  656    /// Modifier pressed
  657    Active {
  658        since: Instant,
  659        previous_scroll_position: Option<ScrollAnchor>,
  660    },
  661}
  662
  663impl EditPredictionPreview {
  664    pub fn released_too_fast(&self) -> bool {
  665        match self {
  666            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  667            EditPredictionPreview::Active { .. } => false,
  668        }
  669    }
  670
  671    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  672        if let EditPredictionPreview::Active {
  673            previous_scroll_position,
  674            ..
  675        } = self
  676        {
  677            *previous_scroll_position = scroll_position;
  678        }
  679    }
  680}
  681
  682pub struct ContextMenuOptions {
  683    pub min_entries_visible: usize,
  684    pub max_entries_visible: usize,
  685    pub placement: Option<ContextMenuPlacement>,
  686}
  687
  688#[derive(Debug, Clone, PartialEq, Eq)]
  689pub enum ContextMenuPlacement {
  690    Above,
  691    Below,
  692}
  693
  694#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  695struct EditorActionId(usize);
  696
  697impl EditorActionId {
  698    pub fn post_inc(&mut self) -> Self {
  699        let answer = self.0;
  700
  701        *self = Self(answer + 1);
  702
  703        Self(answer)
  704    }
  705}
  706
  707// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  708// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  709
  710type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  711type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  712
  713#[derive(Default)]
  714struct ScrollbarMarkerState {
  715    scrollbar_size: Size<Pixels>,
  716    dirty: bool,
  717    markers: Arc<[PaintQuad]>,
  718    pending_refresh: Option<Task<Result<()>>>,
  719}
  720
  721impl ScrollbarMarkerState {
  722    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  723        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  724    }
  725}
  726
  727#[derive(Clone, Copy, PartialEq, Eq)]
  728pub enum MinimapVisibility {
  729    Disabled,
  730    Enabled {
  731        /// The configuration currently present in the users settings.
  732        setting_configuration: bool,
  733        /// Whether to override the currently set visibility from the users setting.
  734        toggle_override: bool,
  735    },
  736}
  737
  738impl MinimapVisibility {
  739    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  740        if mode.is_full() {
  741            Self::Enabled {
  742                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  743                toggle_override: false,
  744            }
  745        } else {
  746            Self::Disabled
  747        }
  748    }
  749
  750    fn hidden(&self) -> Self {
  751        match *self {
  752            Self::Enabled {
  753                setting_configuration,
  754                ..
  755            } => Self::Enabled {
  756                setting_configuration,
  757                toggle_override: setting_configuration,
  758            },
  759            Self::Disabled => Self::Disabled,
  760        }
  761    }
  762
  763    fn disabled(&self) -> bool {
  764        matches!(*self, Self::Disabled)
  765    }
  766
  767    fn settings_visibility(&self) -> bool {
  768        match *self {
  769            Self::Enabled {
  770                setting_configuration,
  771                ..
  772            } => setting_configuration,
  773            _ => false,
  774        }
  775    }
  776
  777    fn visible(&self) -> bool {
  778        match *self {
  779            Self::Enabled {
  780                setting_configuration,
  781                toggle_override,
  782            } => setting_configuration ^ toggle_override,
  783            _ => false,
  784        }
  785    }
  786
  787    fn toggle_visibility(&self) -> Self {
  788        match *self {
  789            Self::Enabled {
  790                toggle_override,
  791                setting_configuration,
  792            } => Self::Enabled {
  793                setting_configuration,
  794                toggle_override: !toggle_override,
  795            },
  796            Self::Disabled => Self::Disabled,
  797        }
  798    }
  799}
  800
  801#[derive(Clone, Debug)]
  802struct RunnableTasks {
  803    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  804    offset: multi_buffer::Anchor,
  805    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  806    column: u32,
  807    // Values of all named captures, including those starting with '_'
  808    extra_variables: HashMap<String, String>,
  809    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  810    context_range: Range<BufferOffset>,
  811}
  812
  813impl RunnableTasks {
  814    fn resolve<'a>(
  815        &'a self,
  816        cx: &'a task::TaskContext,
  817    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  818        self.templates.iter().filter_map(|(kind, template)| {
  819            template
  820                .resolve_task(&kind.to_id_base(), cx)
  821                .map(|task| (kind.clone(), task))
  822        })
  823    }
  824}
  825
  826#[derive(Clone)]
  827pub struct ResolvedTasks {
  828    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  829    position: Anchor,
  830}
  831
  832#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  833struct BufferOffset(usize);
  834
  835/// Addons allow storing per-editor state in other crates (e.g. Vim)
  836pub trait Addon: 'static {
  837    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  838
  839    fn render_buffer_header_controls(
  840        &self,
  841        _: &ExcerptInfo,
  842        _: &Window,
  843        _: &App,
  844    ) -> Option<AnyElement> {
  845        None
  846    }
  847
  848    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  849        None
  850    }
  851
  852    fn to_any(&self) -> &dyn std::any::Any;
  853
  854    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  855        None
  856    }
  857}
  858
  859struct ChangeLocation {
  860    current: Option<Vec<Anchor>>,
  861    original: Vec<Anchor>,
  862}
  863impl ChangeLocation {
  864    fn locations(&self) -> &[Anchor] {
  865        self.current.as_ref().unwrap_or(&self.original)
  866    }
  867}
  868
  869/// A set of caret positions, registered when the editor was edited.
  870pub struct ChangeList {
  871    changes: Vec<ChangeLocation>,
  872    /// Currently "selected" change.
  873    position: Option<usize>,
  874}
  875
  876impl ChangeList {
  877    pub fn new() -> Self {
  878        Self {
  879            changes: Vec::new(),
  880            position: None,
  881        }
  882    }
  883
  884    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  885    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  886    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  887        if self.changes.is_empty() {
  888            return None;
  889        }
  890
  891        let prev = self.position.unwrap_or(self.changes.len());
  892        let next = if direction == Direction::Prev {
  893            prev.saturating_sub(count)
  894        } else {
  895            (prev + count).min(self.changes.len() - 1)
  896        };
  897        self.position = Some(next);
  898        self.changes.get(next).map(|change| change.locations())
  899    }
  900
  901    /// Adds a new change to the list, resetting the change list position.
  902    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  903        self.position.take();
  904        if let Some(last) = self.changes.last_mut()
  905            && group
  906        {
  907            last.current = Some(new_positions)
  908        } else {
  909            self.changes.push(ChangeLocation {
  910                original: new_positions,
  911                current: None,
  912            });
  913        }
  914    }
  915
  916    pub fn last(&self) -> Option<&[Anchor]> {
  917        self.changes.last().map(|change| change.locations())
  918    }
  919
  920    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  921        self.changes.last().map(|change| change.original.as_slice())
  922    }
  923
  924    pub fn invert_last_group(&mut self) {
  925        if let Some(last) = self.changes.last_mut()
  926            && let Some(current) = last.current.as_mut()
  927        {
  928            mem::swap(&mut last.original, current);
  929        }
  930    }
  931}
  932
  933#[derive(Clone)]
  934struct InlineBlamePopoverState {
  935    scroll_handle: ScrollHandle,
  936    commit_message: Option<ParsedCommitMessage>,
  937    markdown: Entity<Markdown>,
  938}
  939
  940struct InlineBlamePopover {
  941    position: gpui::Point<Pixels>,
  942    hide_task: Option<Task<()>>,
  943    popover_bounds: Option<Bounds<Pixels>>,
  944    popover_state: InlineBlamePopoverState,
  945    keyboard_grace: bool,
  946}
  947
  948enum SelectionDragState {
  949    /// State when no drag related activity is detected.
  950    None,
  951    /// State when the mouse is down on a selection that is about to be dragged.
  952    ReadyToDrag {
  953        selection: Selection<Anchor>,
  954        click_position: gpui::Point<Pixels>,
  955        mouse_down_time: Instant,
  956    },
  957    /// State when the mouse is dragging the selection in the editor.
  958    Dragging {
  959        selection: Selection<Anchor>,
  960        drop_cursor: Selection<Anchor>,
  961        hide_drop_cursor: bool,
  962    },
  963}
  964
  965enum ColumnarSelectionState {
  966    FromMouse {
  967        selection_tail: Anchor,
  968        display_point: Option<DisplayPoint>,
  969    },
  970    FromSelection {
  971        selection_tail: Anchor,
  972    },
  973}
  974
  975/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  976/// a breakpoint on them.
  977#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  978struct PhantomBreakpointIndicator {
  979    display_row: DisplayRow,
  980    /// There's a small debounce between hovering over the line and showing the indicator.
  981    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  982    is_active: bool,
  983    collides_with_existing_breakpoint: bool,
  984}
  985
  986/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  987///
  988/// See the [module level documentation](self) for more information.
  989pub struct Editor {
  990    focus_handle: FocusHandle,
  991    last_focused_descendant: Option<WeakFocusHandle>,
  992    /// The text buffer being edited
  993    buffer: Entity<MultiBuffer>,
  994    /// Map of how text in the buffer should be displayed.
  995    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  996    pub display_map: Entity<DisplayMap>,
  997    placeholder_display_map: Option<Entity<DisplayMap>>,
  998    pub selections: SelectionsCollection,
  999    pub scroll_manager: ScrollManager,
 1000    /// When inline assist editors are linked, they all render cursors because
 1001    /// typing enters text into each of them, even the ones that aren't focused.
 1002    pub(crate) show_cursor_when_unfocused: bool,
 1003    columnar_selection_state: Option<ColumnarSelectionState>,
 1004    add_selections_state: Option<AddSelectionsState>,
 1005    select_next_state: Option<SelectNextState>,
 1006    select_prev_state: Option<SelectNextState>,
 1007    selection_history: SelectionHistory,
 1008    defer_selection_effects: bool,
 1009    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1010    autoclose_regions: Vec<AutocloseRegion>,
 1011    snippet_stack: InvalidationStack<SnippetState>,
 1012    select_syntax_node_history: SelectSyntaxNodeHistory,
 1013    ime_transaction: Option<TransactionId>,
 1014    pub diagnostics_max_severity: DiagnosticSeverity,
 1015    active_diagnostics: ActiveDiagnostic,
 1016    show_inline_diagnostics: bool,
 1017    inline_diagnostics_update: Task<()>,
 1018    inline_diagnostics_enabled: bool,
 1019    diagnostics_enabled: bool,
 1020    word_completions_enabled: bool,
 1021    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1022    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1023    hard_wrap: Option<usize>,
 1024    project: Option<Entity<Project>>,
 1025    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1026    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1027    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1028    blink_manager: Entity<BlinkManager>,
 1029    show_cursor_names: bool,
 1030    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1031    pub show_local_selections: bool,
 1032    mode: EditorMode,
 1033    show_breadcrumbs: bool,
 1034    show_gutter: bool,
 1035    show_scrollbars: ScrollbarAxes,
 1036    minimap_visibility: MinimapVisibility,
 1037    offset_content: bool,
 1038    disable_expand_excerpt_buttons: bool,
 1039    show_line_numbers: Option<bool>,
 1040    use_relative_line_numbers: Option<bool>,
 1041    show_git_diff_gutter: Option<bool>,
 1042    show_code_actions: Option<bool>,
 1043    show_runnables: Option<bool>,
 1044    show_breakpoints: Option<bool>,
 1045    show_wrap_guides: Option<bool>,
 1046    show_indent_guides: Option<bool>,
 1047    highlight_order: usize,
 1048    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1049    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1050    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1051    scrollbar_marker_state: ScrollbarMarkerState,
 1052    active_indent_guides_state: ActiveIndentGuidesState,
 1053    nav_history: Option<ItemNavHistory>,
 1054    context_menu: RefCell<Option<CodeContextMenu>>,
 1055    context_menu_options: Option<ContextMenuOptions>,
 1056    mouse_context_menu: Option<MouseContextMenu>,
 1057    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1058    inline_blame_popover: Option<InlineBlamePopover>,
 1059    inline_blame_popover_show_task: Option<Task<()>>,
 1060    signature_help_state: SignatureHelpState,
 1061    auto_signature_help: Option<bool>,
 1062    find_all_references_task_sources: Vec<Anchor>,
 1063    next_completion_id: CompletionId,
 1064    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1065    code_actions_task: Option<Task<Result<()>>>,
 1066    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1067    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1068    document_highlights_task: Option<Task<()>>,
 1069    linked_editing_range_task: Option<Task<Option<()>>>,
 1070    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1071    pending_rename: Option<RenameState>,
 1072    searchable: bool,
 1073    cursor_shape: CursorShape,
 1074    current_line_highlight: Option<CurrentLineHighlight>,
 1075    collapse_matches: bool,
 1076    autoindent_mode: Option<AutoindentMode>,
 1077    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1078    input_enabled: bool,
 1079    use_modal_editing: bool,
 1080    read_only: bool,
 1081    leader_id: Option<CollaboratorId>,
 1082    remote_id: Option<ViewId>,
 1083    pub hover_state: HoverState,
 1084    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1085    gutter_hovered: bool,
 1086    hovered_link_state: Option<HoveredLinkState>,
 1087    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1088    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1089    active_edit_prediction: Option<EditPredictionState>,
 1090    /// Used to prevent flickering as the user types while the menu is open
 1091    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1092    edit_prediction_settings: EditPredictionSettings,
 1093    edit_predictions_hidden_for_vim_mode: bool,
 1094    show_edit_predictions_override: Option<bool>,
 1095    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1096    edit_prediction_preview: EditPredictionPreview,
 1097    edit_prediction_indent_conflict: bool,
 1098    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1099    next_inlay_id: usize,
 1100    next_color_inlay_id: usize,
 1101    _subscriptions: Vec<Subscription>,
 1102    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1103    gutter_dimensions: GutterDimensions,
 1104    style: Option<EditorStyle>,
 1105    text_style_refinement: Option<TextStyleRefinement>,
 1106    next_editor_action_id: EditorActionId,
 1107    editor_actions: Rc<
 1108        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1109    >,
 1110    use_autoclose: bool,
 1111    use_auto_surround: bool,
 1112    auto_replace_emoji_shortcode: bool,
 1113    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1114    show_git_blame_gutter: bool,
 1115    show_git_blame_inline: bool,
 1116    show_git_blame_inline_delay_task: Option<Task<()>>,
 1117    git_blame_inline_enabled: bool,
 1118    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1119    serialize_dirty_buffers: bool,
 1120    show_selection_menu: Option<bool>,
 1121    blame: Option<Entity<GitBlame>>,
 1122    blame_subscription: Option<Subscription>,
 1123    custom_context_menu: Option<
 1124        Box<
 1125            dyn 'static
 1126                + Fn(
 1127                    &mut Self,
 1128                    DisplayPoint,
 1129                    &mut Window,
 1130                    &mut Context<Self>,
 1131                ) -> Option<Entity<ui::ContextMenu>>,
 1132        >,
 1133    >,
 1134    last_bounds: Option<Bounds<Pixels>>,
 1135    last_position_map: Option<Rc<PositionMap>>,
 1136    expect_bounds_change: Option<Bounds<Pixels>>,
 1137    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1138    tasks_update_task: Option<Task<()>>,
 1139    breakpoint_store: Option<Entity<BreakpointStore>>,
 1140    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1141    hovered_diff_hunk_row: Option<DisplayRow>,
 1142    pull_diagnostics_task: Task<()>,
 1143    in_project_search: bool,
 1144    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1145    breadcrumb_header: Option<String>,
 1146    focused_block: Option<FocusedBlock>,
 1147    next_scroll_position: NextScrollCursorCenterTopBottom,
 1148    addons: HashMap<TypeId, Box<dyn Addon>>,
 1149    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1150    load_diff_task: Option<Shared<Task<()>>>,
 1151    /// Whether we are temporarily displaying a diff other than git's
 1152    temporary_diff_override: bool,
 1153    selection_mark_mode: bool,
 1154    toggle_fold_multiple_buffers: Task<()>,
 1155    _scroll_cursor_center_top_bottom_task: Task<()>,
 1156    serialize_selections: Task<()>,
 1157    serialize_folds: Task<()>,
 1158    mouse_cursor_hidden: bool,
 1159    minimap: Option<Entity<Self>>,
 1160    hide_mouse_mode: HideMouseMode,
 1161    pub change_list: ChangeList,
 1162    inline_value_cache: InlineValueCache,
 1163    selection_drag_state: SelectionDragState,
 1164    colors: Option<LspColorData>,
 1165    post_scroll_update: Task<()>,
 1166    refresh_colors_task: Task<()>,
 1167    inlay_hints: Option<LspInlayHintData>,
 1168    folding_newlines: Task<()>,
 1169    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1170}
 1171
 1172fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1173    if debounce_ms > 0 {
 1174        Some(Duration::from_millis(debounce_ms))
 1175    } else {
 1176        None
 1177    }
 1178}
 1179
 1180#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1181enum NextScrollCursorCenterTopBottom {
 1182    #[default]
 1183    Center,
 1184    Top,
 1185    Bottom,
 1186}
 1187
 1188impl NextScrollCursorCenterTopBottom {
 1189    fn next(&self) -> Self {
 1190        match self {
 1191            Self::Center => Self::Top,
 1192            Self::Top => Self::Bottom,
 1193            Self::Bottom => Self::Center,
 1194        }
 1195    }
 1196}
 1197
 1198#[derive(Clone)]
 1199pub struct EditorSnapshot {
 1200    pub mode: EditorMode,
 1201    show_gutter: bool,
 1202    show_line_numbers: Option<bool>,
 1203    show_git_diff_gutter: Option<bool>,
 1204    show_code_actions: Option<bool>,
 1205    show_runnables: Option<bool>,
 1206    show_breakpoints: Option<bool>,
 1207    git_blame_gutter_max_author_length: Option<usize>,
 1208    pub display_snapshot: DisplaySnapshot,
 1209    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1210    is_focused: bool,
 1211    scroll_anchor: ScrollAnchor,
 1212    ongoing_scroll: OngoingScroll,
 1213    current_line_highlight: CurrentLineHighlight,
 1214    gutter_hovered: bool,
 1215}
 1216
 1217#[derive(Default, Debug, Clone, Copy)]
 1218pub struct GutterDimensions {
 1219    pub left_padding: Pixels,
 1220    pub right_padding: Pixels,
 1221    pub width: Pixels,
 1222    pub margin: Pixels,
 1223    pub git_blame_entries_width: Option<Pixels>,
 1224}
 1225
 1226impl GutterDimensions {
 1227    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1228        Self {
 1229            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1230            ..Default::default()
 1231        }
 1232    }
 1233
 1234    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1235        -cx.text_system().descent(font_id, font_size)
 1236    }
 1237    /// The full width of the space taken up by the gutter.
 1238    pub fn full_width(&self) -> Pixels {
 1239        self.margin + self.width
 1240    }
 1241
 1242    /// The width of the space reserved for the fold indicators,
 1243    /// use alongside 'justify_end' and `gutter_width` to
 1244    /// right align content with the line numbers
 1245    pub fn fold_area_width(&self) -> Pixels {
 1246        self.margin + self.right_padding
 1247    }
 1248}
 1249
 1250struct CharacterDimensions {
 1251    em_width: Pixels,
 1252    em_advance: Pixels,
 1253    line_height: Pixels,
 1254}
 1255
 1256#[derive(Debug)]
 1257pub struct RemoteSelection {
 1258    pub replica_id: ReplicaId,
 1259    pub selection: Selection<Anchor>,
 1260    pub cursor_shape: CursorShape,
 1261    pub collaborator_id: CollaboratorId,
 1262    pub line_mode: bool,
 1263    pub user_name: Option<SharedString>,
 1264    pub color: PlayerColor,
 1265}
 1266
 1267#[derive(Clone, Debug)]
 1268struct SelectionHistoryEntry {
 1269    selections: Arc<[Selection<Anchor>]>,
 1270    select_next_state: Option<SelectNextState>,
 1271    select_prev_state: Option<SelectNextState>,
 1272    add_selections_state: Option<AddSelectionsState>,
 1273}
 1274
 1275#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1276enum SelectionHistoryMode {
 1277    Normal,
 1278    Undoing,
 1279    Redoing,
 1280    Skipping,
 1281}
 1282
 1283#[derive(Clone, PartialEq, Eq, Hash)]
 1284struct HoveredCursor {
 1285    replica_id: ReplicaId,
 1286    selection_id: usize,
 1287}
 1288
 1289impl Default for SelectionHistoryMode {
 1290    fn default() -> Self {
 1291        Self::Normal
 1292    }
 1293}
 1294
 1295#[derive(Debug)]
 1296/// SelectionEffects controls the side-effects of updating the selection.
 1297///
 1298/// The default behaviour does "what you mostly want":
 1299/// - it pushes to the nav history if the cursor moved by >10 lines
 1300/// - it re-triggers completion requests
 1301/// - it scrolls to fit
 1302///
 1303/// You might want to modify these behaviours. For example when doing a "jump"
 1304/// like go to definition, we always want to add to nav history; but when scrolling
 1305/// in vim mode we never do.
 1306///
 1307/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1308/// move.
 1309#[derive(Clone)]
 1310pub struct SelectionEffects {
 1311    nav_history: Option<bool>,
 1312    completions: bool,
 1313    scroll: Option<Autoscroll>,
 1314}
 1315
 1316impl Default for SelectionEffects {
 1317    fn default() -> Self {
 1318        Self {
 1319            nav_history: None,
 1320            completions: true,
 1321            scroll: Some(Autoscroll::fit()),
 1322        }
 1323    }
 1324}
 1325impl SelectionEffects {
 1326    pub fn scroll(scroll: Autoscroll) -> Self {
 1327        Self {
 1328            scroll: Some(scroll),
 1329            ..Default::default()
 1330        }
 1331    }
 1332
 1333    pub fn no_scroll() -> Self {
 1334        Self {
 1335            scroll: None,
 1336            ..Default::default()
 1337        }
 1338    }
 1339
 1340    pub fn completions(self, completions: bool) -> Self {
 1341        Self {
 1342            completions,
 1343            ..self
 1344        }
 1345    }
 1346
 1347    pub fn nav_history(self, nav_history: bool) -> Self {
 1348        Self {
 1349            nav_history: Some(nav_history),
 1350            ..self
 1351        }
 1352    }
 1353}
 1354
 1355struct DeferredSelectionEffectsState {
 1356    changed: bool,
 1357    effects: SelectionEffects,
 1358    old_cursor_position: Anchor,
 1359    history_entry: SelectionHistoryEntry,
 1360}
 1361
 1362#[derive(Default)]
 1363struct SelectionHistory {
 1364    #[allow(clippy::type_complexity)]
 1365    selections_by_transaction:
 1366        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1367    mode: SelectionHistoryMode,
 1368    undo_stack: VecDeque<SelectionHistoryEntry>,
 1369    redo_stack: VecDeque<SelectionHistoryEntry>,
 1370}
 1371
 1372impl SelectionHistory {
 1373    #[track_caller]
 1374    fn insert_transaction(
 1375        &mut self,
 1376        transaction_id: TransactionId,
 1377        selections: Arc<[Selection<Anchor>]>,
 1378    ) {
 1379        if selections.is_empty() {
 1380            log::error!(
 1381                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1382                std::panic::Location::caller()
 1383            );
 1384            return;
 1385        }
 1386        self.selections_by_transaction
 1387            .insert(transaction_id, (selections, None));
 1388    }
 1389
 1390    #[allow(clippy::type_complexity)]
 1391    fn transaction(
 1392        &self,
 1393        transaction_id: TransactionId,
 1394    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1395        self.selections_by_transaction.get(&transaction_id)
 1396    }
 1397
 1398    #[allow(clippy::type_complexity)]
 1399    fn transaction_mut(
 1400        &mut self,
 1401        transaction_id: TransactionId,
 1402    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1403        self.selections_by_transaction.get_mut(&transaction_id)
 1404    }
 1405
 1406    fn push(&mut self, entry: SelectionHistoryEntry) {
 1407        if !entry.selections.is_empty() {
 1408            match self.mode {
 1409                SelectionHistoryMode::Normal => {
 1410                    self.push_undo(entry);
 1411                    self.redo_stack.clear();
 1412                }
 1413                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1414                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1415                SelectionHistoryMode::Skipping => {}
 1416            }
 1417        }
 1418    }
 1419
 1420    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1421        if self
 1422            .undo_stack
 1423            .back()
 1424            .is_none_or(|e| e.selections != entry.selections)
 1425        {
 1426            self.undo_stack.push_back(entry);
 1427            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1428                self.undo_stack.pop_front();
 1429            }
 1430        }
 1431    }
 1432
 1433    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1434        if self
 1435            .redo_stack
 1436            .back()
 1437            .is_none_or(|e| e.selections != entry.selections)
 1438        {
 1439            self.redo_stack.push_back(entry);
 1440            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1441                self.redo_stack.pop_front();
 1442            }
 1443        }
 1444    }
 1445}
 1446
 1447#[derive(Clone, Copy)]
 1448pub struct RowHighlightOptions {
 1449    pub autoscroll: bool,
 1450    pub include_gutter: bool,
 1451}
 1452
 1453impl Default for RowHighlightOptions {
 1454    fn default() -> Self {
 1455        Self {
 1456            autoscroll: Default::default(),
 1457            include_gutter: true,
 1458        }
 1459    }
 1460}
 1461
 1462struct RowHighlight {
 1463    index: usize,
 1464    range: Range<Anchor>,
 1465    color: Hsla,
 1466    options: RowHighlightOptions,
 1467    type_id: TypeId,
 1468}
 1469
 1470#[derive(Clone, Debug)]
 1471struct AddSelectionsState {
 1472    groups: Vec<AddSelectionsGroup>,
 1473}
 1474
 1475#[derive(Clone, Debug)]
 1476struct AddSelectionsGroup {
 1477    above: bool,
 1478    stack: Vec<usize>,
 1479}
 1480
 1481#[derive(Clone)]
 1482struct SelectNextState {
 1483    query: AhoCorasick,
 1484    wordwise: bool,
 1485    done: bool,
 1486}
 1487
 1488impl std::fmt::Debug for SelectNextState {
 1489    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1490        f.debug_struct(std::any::type_name::<Self>())
 1491            .field("wordwise", &self.wordwise)
 1492            .field("done", &self.done)
 1493            .finish()
 1494    }
 1495}
 1496
 1497#[derive(Debug)]
 1498struct AutocloseRegion {
 1499    selection_id: usize,
 1500    range: Range<Anchor>,
 1501    pair: BracketPair,
 1502}
 1503
 1504#[derive(Debug)]
 1505struct SnippetState {
 1506    ranges: Vec<Vec<Range<Anchor>>>,
 1507    active_index: usize,
 1508    choices: Vec<Option<Vec<String>>>,
 1509}
 1510
 1511#[doc(hidden)]
 1512pub struct RenameState {
 1513    pub range: Range<Anchor>,
 1514    pub old_name: Arc<str>,
 1515    pub editor: Entity<Editor>,
 1516    block_id: CustomBlockId,
 1517}
 1518
 1519struct InvalidationStack<T>(Vec<T>);
 1520
 1521struct RegisteredEditPredictionProvider {
 1522    provider: Arc<dyn EditPredictionProviderHandle>,
 1523    _subscription: Subscription,
 1524}
 1525
 1526#[derive(Debug, PartialEq, Eq)]
 1527pub struct ActiveDiagnosticGroup {
 1528    pub active_range: Range<Anchor>,
 1529    pub active_message: String,
 1530    pub group_id: usize,
 1531    pub blocks: HashSet<CustomBlockId>,
 1532}
 1533
 1534#[derive(Debug, PartialEq, Eq)]
 1535
 1536pub(crate) enum ActiveDiagnostic {
 1537    None,
 1538    All,
 1539    Group(ActiveDiagnosticGroup),
 1540}
 1541
 1542#[derive(Serialize, Deserialize, Clone, Debug)]
 1543pub struct ClipboardSelection {
 1544    /// The number of bytes in this selection.
 1545    pub len: usize,
 1546    /// Whether this was a full-line selection.
 1547    pub is_entire_line: bool,
 1548    /// The indentation of the first line when this content was originally copied.
 1549    pub first_line_indent: u32,
 1550}
 1551
 1552// selections, scroll behavior, was newest selection reversed
 1553type SelectSyntaxNodeHistoryState = (
 1554    Box<[Selection<usize>]>,
 1555    SelectSyntaxNodeScrollBehavior,
 1556    bool,
 1557);
 1558
 1559#[derive(Default)]
 1560struct SelectSyntaxNodeHistory {
 1561    stack: Vec<SelectSyntaxNodeHistoryState>,
 1562    // disable temporarily to allow changing selections without losing the stack
 1563    pub disable_clearing: bool,
 1564}
 1565
 1566impl SelectSyntaxNodeHistory {
 1567    pub fn try_clear(&mut self) {
 1568        if !self.disable_clearing {
 1569            self.stack.clear();
 1570        }
 1571    }
 1572
 1573    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1574        self.stack.push(selection);
 1575    }
 1576
 1577    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1578        self.stack.pop()
 1579    }
 1580}
 1581
 1582enum SelectSyntaxNodeScrollBehavior {
 1583    CursorTop,
 1584    FitSelection,
 1585    CursorBottom,
 1586}
 1587
 1588#[derive(Debug)]
 1589pub(crate) struct NavigationData {
 1590    cursor_anchor: Anchor,
 1591    cursor_position: Point,
 1592    scroll_anchor: ScrollAnchor,
 1593    scroll_top_row: u32,
 1594}
 1595
 1596#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1597pub enum GotoDefinitionKind {
 1598    Symbol,
 1599    Declaration,
 1600    Type,
 1601    Implementation,
 1602}
 1603
 1604pub enum FormatTarget {
 1605    Buffers(HashSet<Entity<Buffer>>),
 1606    Ranges(Vec<Range<MultiBufferPoint>>),
 1607}
 1608
 1609pub(crate) struct FocusedBlock {
 1610    id: BlockId,
 1611    focus_handle: WeakFocusHandle,
 1612}
 1613
 1614#[derive(Clone)]
 1615enum JumpData {
 1616    MultiBufferRow {
 1617        row: MultiBufferRow,
 1618        line_offset_from_top: u32,
 1619    },
 1620    MultiBufferPoint {
 1621        excerpt_id: ExcerptId,
 1622        position: Point,
 1623        anchor: text::Anchor,
 1624        line_offset_from_top: u32,
 1625    },
 1626}
 1627
 1628pub enum MultibufferSelectionMode {
 1629    First,
 1630    All,
 1631}
 1632
 1633#[derive(Clone, Copy, Debug, Default)]
 1634pub struct RewrapOptions {
 1635    pub override_language_settings: bool,
 1636    pub preserve_existing_whitespace: bool,
 1637}
 1638
 1639impl Editor {
 1640    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1641        let buffer = cx.new(|cx| Buffer::local("", cx));
 1642        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1643        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1644    }
 1645
 1646    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1647        let buffer = cx.new(|cx| Buffer::local("", cx));
 1648        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1649        Self::new(EditorMode::full(), buffer, None, window, cx)
 1650    }
 1651
 1652    pub fn auto_height(
 1653        min_lines: usize,
 1654        max_lines: usize,
 1655        window: &mut Window,
 1656        cx: &mut Context<Self>,
 1657    ) -> Self {
 1658        let buffer = cx.new(|cx| Buffer::local("", cx));
 1659        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1660        Self::new(
 1661            EditorMode::AutoHeight {
 1662                min_lines,
 1663                max_lines: Some(max_lines),
 1664            },
 1665            buffer,
 1666            None,
 1667            window,
 1668            cx,
 1669        )
 1670    }
 1671
 1672    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1673    /// The editor grows as tall as needed to fit its content.
 1674    pub fn auto_height_unbounded(
 1675        min_lines: usize,
 1676        window: &mut Window,
 1677        cx: &mut Context<Self>,
 1678    ) -> Self {
 1679        let buffer = cx.new(|cx| Buffer::local("", cx));
 1680        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1681        Self::new(
 1682            EditorMode::AutoHeight {
 1683                min_lines,
 1684                max_lines: None,
 1685            },
 1686            buffer,
 1687            None,
 1688            window,
 1689            cx,
 1690        )
 1691    }
 1692
 1693    pub fn for_buffer(
 1694        buffer: Entity<Buffer>,
 1695        project: Option<Entity<Project>>,
 1696        window: &mut Window,
 1697        cx: &mut Context<Self>,
 1698    ) -> Self {
 1699        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1700        Self::new(EditorMode::full(), buffer, project, window, cx)
 1701    }
 1702
 1703    pub fn for_multibuffer(
 1704        buffer: Entity<MultiBuffer>,
 1705        project: Option<Entity<Project>>,
 1706        window: &mut Window,
 1707        cx: &mut Context<Self>,
 1708    ) -> Self {
 1709        Self::new(EditorMode::full(), buffer, project, window, cx)
 1710    }
 1711
 1712    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1713        let mut clone = Self::new(
 1714            self.mode.clone(),
 1715            self.buffer.clone(),
 1716            self.project.clone(),
 1717            window,
 1718            cx,
 1719        );
 1720        self.display_map.update(cx, |display_map, cx| {
 1721            let snapshot = display_map.snapshot(cx);
 1722            clone.display_map.update(cx, |display_map, cx| {
 1723                display_map.set_state(&snapshot, cx);
 1724            });
 1725        });
 1726        clone.folds_did_change(cx);
 1727        clone.selections.clone_state(&self.selections);
 1728        clone.scroll_manager.clone_state(&self.scroll_manager);
 1729        clone.searchable = self.searchable;
 1730        clone.read_only = self.read_only;
 1731        clone
 1732    }
 1733
 1734    pub fn new(
 1735        mode: EditorMode,
 1736        buffer: Entity<MultiBuffer>,
 1737        project: Option<Entity<Project>>,
 1738        window: &mut Window,
 1739        cx: &mut Context<Self>,
 1740    ) -> Self {
 1741        Editor::new_internal(mode, buffer, project, None, window, cx)
 1742    }
 1743
 1744    fn new_internal(
 1745        mode: EditorMode,
 1746        multi_buffer: Entity<MultiBuffer>,
 1747        project: Option<Entity<Project>>,
 1748        display_map: Option<Entity<DisplayMap>>,
 1749        window: &mut Window,
 1750        cx: &mut Context<Self>,
 1751    ) -> Self {
 1752        debug_assert!(
 1753            display_map.is_none() || mode.is_minimap(),
 1754            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1755        );
 1756
 1757        let full_mode = mode.is_full();
 1758        let is_minimap = mode.is_minimap();
 1759        let diagnostics_max_severity = if full_mode {
 1760            EditorSettings::get_global(cx)
 1761                .diagnostics_max_severity
 1762                .unwrap_or(DiagnosticSeverity::Hint)
 1763        } else {
 1764            DiagnosticSeverity::Off
 1765        };
 1766        let style = window.text_style();
 1767        let font_size = style.font_size.to_pixels(window.rem_size());
 1768        let editor = cx.entity().downgrade();
 1769        let fold_placeholder = FoldPlaceholder {
 1770            constrain_width: false,
 1771            render: Arc::new(move |fold_id, fold_range, cx| {
 1772                let editor = editor.clone();
 1773                div()
 1774                    .id(fold_id)
 1775                    .bg(cx.theme().colors().ghost_element_background)
 1776                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1777                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1778                    .rounded_xs()
 1779                    .size_full()
 1780                    .cursor_pointer()
 1781                    .child("⋯")
 1782                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1783                    .on_click(move |_, _window, cx| {
 1784                        editor
 1785                            .update(cx, |editor, cx| {
 1786                                editor.unfold_ranges(
 1787                                    &[fold_range.start..fold_range.end],
 1788                                    true,
 1789                                    false,
 1790                                    cx,
 1791                                );
 1792                                cx.stop_propagation();
 1793                            })
 1794                            .ok();
 1795                    })
 1796                    .into_any()
 1797            }),
 1798            merge_adjacent: true,
 1799            ..FoldPlaceholder::default()
 1800        };
 1801        let display_map = display_map.unwrap_or_else(|| {
 1802            cx.new(|cx| {
 1803                DisplayMap::new(
 1804                    multi_buffer.clone(),
 1805                    style.font(),
 1806                    font_size,
 1807                    None,
 1808                    FILE_HEADER_HEIGHT,
 1809                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1810                    fold_placeholder,
 1811                    diagnostics_max_severity,
 1812                    cx,
 1813                )
 1814            })
 1815        });
 1816
 1817        let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
 1818
 1819        let blink_manager = cx.new(|cx| {
 1820            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1821            if is_minimap {
 1822                blink_manager.disable(cx);
 1823            }
 1824            blink_manager
 1825        });
 1826
 1827        let soft_wrap_mode_override =
 1828            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1829
 1830        let mut project_subscriptions = Vec::new();
 1831        if full_mode && let Some(project) = project.as_ref() {
 1832            project_subscriptions.push(cx.subscribe_in(
 1833                project,
 1834                window,
 1835                |editor, _, event, window, cx| match event {
 1836                    project::Event::RefreshCodeLens => {
 1837                        // we always query lens with actions, without storing them, always refreshing them
 1838                    }
 1839                    project::Event::RefreshInlayHints(server_id) => {
 1840                        editor.refresh_inlay_hints(
 1841                            InlayHintRefreshReason::RefreshRequested(*server_id),
 1842                            cx,
 1843                        );
 1844                    }
 1845                    project::Event::LanguageServerRemoved(..) => {
 1846                        if editor.tasks_update_task.is_none() {
 1847                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1848                        }
 1849                        editor.registered_buffers.clear();
 1850                        editor.register_visible_buffers(cx);
 1851                    }
 1852                    project::Event::LanguageServerAdded(..) => {
 1853                        if editor.tasks_update_task.is_none() {
 1854                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1855                        }
 1856                    }
 1857                    project::Event::SnippetEdit(id, snippet_edits) => {
 1858                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1859                            let focus_handle = editor.focus_handle(cx);
 1860                            if focus_handle.is_focused(window) {
 1861                                let snapshot = buffer.read(cx).snapshot();
 1862                                for (range, snippet) in snippet_edits {
 1863                                    let editor_range =
 1864                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1865                                    editor
 1866                                        .insert_snippet(
 1867                                            &[editor_range],
 1868                                            snippet.clone(),
 1869                                            window,
 1870                                            cx,
 1871                                        )
 1872                                        .ok();
 1873                                }
 1874                            }
 1875                        }
 1876                    }
 1877                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1878                        let buffer_id = *buffer_id;
 1879                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1880                            editor.register_buffer(buffer_id, cx);
 1881                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1882                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1883                            refresh_linked_ranges(editor, window, cx);
 1884                            editor.refresh_code_actions(window, cx);
 1885                            editor.refresh_document_highlights(cx);
 1886                        }
 1887                    }
 1888
 1889                    project::Event::EntryRenamed(transaction) => {
 1890                        let Some(workspace) = editor.workspace() else {
 1891                            return;
 1892                        };
 1893                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1894                        else {
 1895                            return;
 1896                        };
 1897                        if active_editor.entity_id() == cx.entity_id() {
 1898                            let edited_buffers_already_open = {
 1899                                let other_editors: Vec<Entity<Editor>> = workspace
 1900                                    .read(cx)
 1901                                    .panes()
 1902                                    .iter()
 1903                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1904                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1905                                    .collect();
 1906
 1907                                transaction.0.keys().all(|buffer| {
 1908                                    other_editors.iter().any(|editor| {
 1909                                        let multi_buffer = editor.read(cx).buffer();
 1910                                        multi_buffer.read(cx).is_singleton()
 1911                                            && multi_buffer.read(cx).as_singleton().map_or(
 1912                                                false,
 1913                                                |singleton| {
 1914                                                    singleton.entity_id() == buffer.entity_id()
 1915                                                },
 1916                                            )
 1917                                    })
 1918                                })
 1919                            };
 1920
 1921                            if !edited_buffers_already_open {
 1922                                let workspace = workspace.downgrade();
 1923                                let transaction = transaction.clone();
 1924                                cx.defer_in(window, move |_, window, cx| {
 1925                                    cx.spawn_in(window, async move |editor, cx| {
 1926                                        Self::open_project_transaction(
 1927                                            &editor,
 1928                                            workspace,
 1929                                            transaction,
 1930                                            "Rename".to_string(),
 1931                                            cx,
 1932                                        )
 1933                                        .await
 1934                                        .ok()
 1935                                    })
 1936                                    .detach();
 1937                                });
 1938                            }
 1939                        }
 1940                    }
 1941
 1942                    _ => {}
 1943                },
 1944            ));
 1945            if let Some(task_inventory) = project
 1946                .read(cx)
 1947                .task_store()
 1948                .read(cx)
 1949                .task_inventory()
 1950                .cloned()
 1951            {
 1952                project_subscriptions.push(cx.observe_in(
 1953                    &task_inventory,
 1954                    window,
 1955                    |editor, _, window, cx| {
 1956                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1957                    },
 1958                ));
 1959            };
 1960
 1961            project_subscriptions.push(cx.subscribe_in(
 1962                &project.read(cx).breakpoint_store(),
 1963                window,
 1964                |editor, _, event, window, cx| match event {
 1965                    BreakpointStoreEvent::ClearDebugLines => {
 1966                        editor.clear_row_highlights::<ActiveDebugLine>();
 1967                        editor.refresh_inline_values(cx);
 1968                    }
 1969                    BreakpointStoreEvent::SetDebugLine => {
 1970                        if editor.go_to_active_debug_line(window, cx) {
 1971                            cx.stop_propagation();
 1972                        }
 1973
 1974                        editor.refresh_inline_values(cx);
 1975                    }
 1976                    _ => {}
 1977                },
 1978            ));
 1979            let git_store = project.read(cx).git_store().clone();
 1980            let project = project.clone();
 1981            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1982                if let GitStoreEvent::RepositoryAdded = event {
 1983                    this.load_diff_task = Some(
 1984                        update_uncommitted_diff_for_buffer(
 1985                            cx.entity(),
 1986                            &project,
 1987                            this.buffer.read(cx).all_buffers(),
 1988                            this.buffer.clone(),
 1989                            cx,
 1990                        )
 1991                        .shared(),
 1992                    );
 1993                }
 1994            }));
 1995        }
 1996
 1997        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 1998
 1999        let inlay_hint_settings =
 2000            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2001        let focus_handle = cx.focus_handle();
 2002        if !is_minimap {
 2003            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2004                .detach();
 2005            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2006                .detach();
 2007            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2008                .detach();
 2009            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2010                .detach();
 2011            cx.observe_pending_input(window, Self::observe_pending_input)
 2012                .detach();
 2013        }
 2014
 2015        let show_indent_guides =
 2016            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2017                Some(false)
 2018            } else {
 2019                None
 2020            };
 2021
 2022        let breakpoint_store = match (&mode, project.as_ref()) {
 2023            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2024            _ => None,
 2025        };
 2026
 2027        let mut code_action_providers = Vec::new();
 2028        let mut load_uncommitted_diff = None;
 2029        if let Some(project) = project.clone() {
 2030            load_uncommitted_diff = Some(
 2031                update_uncommitted_diff_for_buffer(
 2032                    cx.entity(),
 2033                    &project,
 2034                    multi_buffer.read(cx).all_buffers(),
 2035                    multi_buffer.clone(),
 2036                    cx,
 2037                )
 2038                .shared(),
 2039            );
 2040            code_action_providers.push(Rc::new(project) as Rc<_>);
 2041        }
 2042
 2043        let mut editor = Self {
 2044            focus_handle,
 2045            show_cursor_when_unfocused: false,
 2046            last_focused_descendant: None,
 2047            buffer: multi_buffer.clone(),
 2048            display_map: display_map.clone(),
 2049            placeholder_display_map: None,
 2050            selections,
 2051            scroll_manager: ScrollManager::new(cx),
 2052            columnar_selection_state: None,
 2053            add_selections_state: None,
 2054            select_next_state: None,
 2055            select_prev_state: None,
 2056            selection_history: SelectionHistory::default(),
 2057            defer_selection_effects: false,
 2058            deferred_selection_effects_state: None,
 2059            autoclose_regions: Vec::new(),
 2060            snippet_stack: InvalidationStack::default(),
 2061            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2062            ime_transaction: None,
 2063            active_diagnostics: ActiveDiagnostic::None,
 2064            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2065            inline_diagnostics_update: Task::ready(()),
 2066            inline_diagnostics: Vec::new(),
 2067            soft_wrap_mode_override,
 2068            diagnostics_max_severity,
 2069            hard_wrap: None,
 2070            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2071            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2072            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2073            project,
 2074            blink_manager: blink_manager.clone(),
 2075            show_local_selections: true,
 2076            show_scrollbars: ScrollbarAxes {
 2077                horizontal: full_mode,
 2078                vertical: full_mode,
 2079            },
 2080            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2081            offset_content: !matches!(mode, EditorMode::SingleLine),
 2082            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2083            show_gutter: full_mode,
 2084            show_line_numbers: (!full_mode).then_some(false),
 2085            use_relative_line_numbers: None,
 2086            disable_expand_excerpt_buttons: !full_mode,
 2087            show_git_diff_gutter: None,
 2088            show_code_actions: None,
 2089            show_runnables: None,
 2090            show_breakpoints: None,
 2091            show_wrap_guides: None,
 2092            show_indent_guides,
 2093            highlight_order: 0,
 2094            highlighted_rows: HashMap::default(),
 2095            background_highlights: HashMap::default(),
 2096            gutter_highlights: HashMap::default(),
 2097            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2098            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2099            nav_history: None,
 2100            context_menu: RefCell::new(None),
 2101            context_menu_options: None,
 2102            mouse_context_menu: None,
 2103            completion_tasks: Vec::new(),
 2104            inline_blame_popover: None,
 2105            inline_blame_popover_show_task: None,
 2106            signature_help_state: SignatureHelpState::default(),
 2107            auto_signature_help: None,
 2108            find_all_references_task_sources: Vec::new(),
 2109            next_completion_id: 0,
 2110            next_inlay_id: 0,
 2111            code_action_providers,
 2112            available_code_actions: None,
 2113            code_actions_task: None,
 2114            quick_selection_highlight_task: None,
 2115            debounced_selection_highlight_task: None,
 2116            document_highlights_task: None,
 2117            linked_editing_range_task: None,
 2118            pending_rename: None,
 2119            searchable: !is_minimap,
 2120            cursor_shape: EditorSettings::get_global(cx)
 2121                .cursor_shape
 2122                .unwrap_or_default(),
 2123            current_line_highlight: None,
 2124            autoindent_mode: Some(AutoindentMode::EachLine),
 2125            collapse_matches: false,
 2126            workspace: None,
 2127            input_enabled: !is_minimap,
 2128            use_modal_editing: full_mode,
 2129            read_only: is_minimap,
 2130            use_autoclose: true,
 2131            use_auto_surround: true,
 2132            auto_replace_emoji_shortcode: false,
 2133            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2134            leader_id: None,
 2135            remote_id: None,
 2136            hover_state: HoverState::default(),
 2137            pending_mouse_down: None,
 2138            hovered_link_state: None,
 2139            edit_prediction_provider: None,
 2140            active_edit_prediction: None,
 2141            stale_edit_prediction_in_menu: None,
 2142            edit_prediction_preview: EditPredictionPreview::Inactive {
 2143                released_too_fast: false,
 2144            },
 2145            inline_diagnostics_enabled: full_mode,
 2146            diagnostics_enabled: full_mode,
 2147            word_completions_enabled: full_mode,
 2148            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2149            gutter_hovered: false,
 2150            pixel_position_of_newest_cursor: None,
 2151            last_bounds: None,
 2152            last_position_map: None,
 2153            expect_bounds_change: None,
 2154            gutter_dimensions: GutterDimensions::default(),
 2155            style: None,
 2156            show_cursor_names: false,
 2157            hovered_cursors: HashMap::default(),
 2158            next_editor_action_id: EditorActionId::default(),
 2159            editor_actions: Rc::default(),
 2160            edit_predictions_hidden_for_vim_mode: false,
 2161            show_edit_predictions_override: None,
 2162            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2163            edit_prediction_settings: EditPredictionSettings::Disabled,
 2164            edit_prediction_indent_conflict: false,
 2165            edit_prediction_requires_modifier_in_indent_conflict: true,
 2166            custom_context_menu: None,
 2167            show_git_blame_gutter: false,
 2168            show_git_blame_inline: false,
 2169            show_selection_menu: None,
 2170            show_git_blame_inline_delay_task: None,
 2171            git_blame_inline_enabled: full_mode
 2172                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2173            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2174            serialize_dirty_buffers: !is_minimap
 2175                && ProjectSettings::get_global(cx)
 2176                    .session
 2177                    .restore_unsaved_buffers,
 2178            blame: None,
 2179            blame_subscription: None,
 2180            tasks: BTreeMap::default(),
 2181
 2182            breakpoint_store,
 2183            gutter_breakpoint_indicator: (None, None),
 2184            hovered_diff_hunk_row: None,
 2185            _subscriptions: (!is_minimap)
 2186                .then(|| {
 2187                    vec![
 2188                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2189                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2190                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2191                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2192                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2193                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2194                        cx.observe_window_activation(window, |editor, window, cx| {
 2195                            let active = window.is_window_active();
 2196                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2197                                if active {
 2198                                    blink_manager.enable(cx);
 2199                                } else {
 2200                                    blink_manager.disable(cx);
 2201                                }
 2202                            });
 2203                            if active {
 2204                                editor.show_mouse_cursor(cx);
 2205                            }
 2206                        }),
 2207                    ]
 2208                })
 2209                .unwrap_or_default(),
 2210            tasks_update_task: None,
 2211            pull_diagnostics_task: Task::ready(()),
 2212            colors: None,
 2213            refresh_colors_task: Task::ready(()),
 2214            inlay_hints: None,
 2215            next_color_inlay_id: 0,
 2216            post_scroll_update: Task::ready(()),
 2217            linked_edit_ranges: Default::default(),
 2218            in_project_search: false,
 2219            previous_search_ranges: None,
 2220            breadcrumb_header: None,
 2221            focused_block: None,
 2222            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2223            addons: HashMap::default(),
 2224            registered_buffers: HashMap::default(),
 2225            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2226            selection_mark_mode: false,
 2227            toggle_fold_multiple_buffers: Task::ready(()),
 2228            serialize_selections: Task::ready(()),
 2229            serialize_folds: Task::ready(()),
 2230            text_style_refinement: None,
 2231            load_diff_task: load_uncommitted_diff,
 2232            temporary_diff_override: false,
 2233            mouse_cursor_hidden: false,
 2234            minimap: None,
 2235            hide_mouse_mode: EditorSettings::get_global(cx)
 2236                .hide_mouse
 2237                .unwrap_or_default(),
 2238            change_list: ChangeList::new(),
 2239            mode,
 2240            selection_drag_state: SelectionDragState::None,
 2241            folding_newlines: Task::ready(()),
 2242            lookup_key: None,
 2243        };
 2244
 2245        if is_minimap {
 2246            return editor;
 2247        }
 2248
 2249        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2250            editor
 2251                ._subscriptions
 2252                .push(cx.observe(breakpoints, |_, _, cx| {
 2253                    cx.notify();
 2254                }));
 2255        }
 2256        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2257        editor._subscriptions.extend(project_subscriptions);
 2258
 2259        editor._subscriptions.push(cx.subscribe_in(
 2260            &cx.entity(),
 2261            window,
 2262            |editor, _, e: &EditorEvent, window, cx| match e {
 2263                EditorEvent::ScrollPositionChanged { local, .. } => {
 2264                    if *local {
 2265                        let new_anchor = editor.scroll_manager.anchor();
 2266                        let snapshot = editor.snapshot(window, cx);
 2267                        editor.update_restoration_data(cx, move |data| {
 2268                            data.scroll_position = (
 2269                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2270                                new_anchor.offset,
 2271                            );
 2272                        });
 2273                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2274                        editor.inline_blame_popover.take();
 2275                    }
 2276                }
 2277                EditorEvent::Edited { .. } => {
 2278                    if !vim_enabled(cx) {
 2279                        let display_map = editor.display_snapshot(cx);
 2280                        let selections = editor.selections.all_adjusted_display(&display_map);
 2281                        let pop_state = editor
 2282                            .change_list
 2283                            .last()
 2284                            .map(|previous| {
 2285                                previous.len() == selections.len()
 2286                                    && previous.iter().enumerate().all(|(ix, p)| {
 2287                                        p.to_display_point(&display_map).row()
 2288                                            == selections[ix].head().row()
 2289                                    })
 2290                            })
 2291                            .unwrap_or(false);
 2292                        let new_positions = selections
 2293                            .into_iter()
 2294                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2295                            .collect();
 2296                        editor
 2297                            .change_list
 2298                            .push_to_change_list(pop_state, new_positions);
 2299                    }
 2300                }
 2301                _ => (),
 2302            },
 2303        ));
 2304
 2305        if let Some(dap_store) = editor
 2306            .project
 2307            .as_ref()
 2308            .map(|project| project.read(cx).dap_store())
 2309        {
 2310            let weak_editor = cx.weak_entity();
 2311
 2312            editor
 2313                ._subscriptions
 2314                .push(
 2315                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2316                        let session_entity = cx.entity();
 2317                        weak_editor
 2318                            .update(cx, |editor, cx| {
 2319                                editor._subscriptions.push(
 2320                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2321                                );
 2322                            })
 2323                            .ok();
 2324                    }),
 2325                );
 2326
 2327            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2328                editor
 2329                    ._subscriptions
 2330                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2331            }
 2332        }
 2333
 2334        // skip adding the initial selection to selection history
 2335        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2336        editor.end_selection(window, cx);
 2337        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2338
 2339        editor.scroll_manager.show_scrollbars(window, cx);
 2340        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2341
 2342        if full_mode {
 2343            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2344            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2345
 2346            if editor.git_blame_inline_enabled {
 2347                editor.start_git_blame_inline(false, window, cx);
 2348            }
 2349
 2350            editor.go_to_active_debug_line(window, cx);
 2351
 2352            editor.minimap =
 2353                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2354            editor.colors = Some(LspColorData::new(cx));
 2355            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2356
 2357            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2358                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2359            }
 2360            editor.update_lsp_data(None, window, cx);
 2361            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2362        }
 2363
 2364        editor
 2365    }
 2366
 2367    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2368        self.selections.display_map(cx)
 2369    }
 2370
 2371    pub fn deploy_mouse_context_menu(
 2372        &mut self,
 2373        position: gpui::Point<Pixels>,
 2374        context_menu: Entity<ContextMenu>,
 2375        window: &mut Window,
 2376        cx: &mut Context<Self>,
 2377    ) {
 2378        self.mouse_context_menu = Some(MouseContextMenu::new(
 2379            self,
 2380            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2381            context_menu,
 2382            window,
 2383            cx,
 2384        ));
 2385    }
 2386
 2387    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2388        self.mouse_context_menu
 2389            .as_ref()
 2390            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2391    }
 2392
 2393    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2394        if self
 2395            .selections
 2396            .pending_anchor()
 2397            .is_some_and(|pending_selection| {
 2398                let snapshot = self.buffer().read(cx).snapshot(cx);
 2399                pending_selection.range().includes(range, &snapshot)
 2400            })
 2401        {
 2402            return true;
 2403        }
 2404
 2405        self.selections
 2406            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2407            .into_iter()
 2408            .any(|selection| {
 2409                // This is needed to cover a corner case, if we just check for an existing
 2410                // selection in the fold range, having a cursor at the start of the fold
 2411                // marks it as selected. Non-empty selections don't cause this.
 2412                let length = selection.end - selection.start;
 2413                length > 0
 2414            })
 2415    }
 2416
 2417    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2418        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2419    }
 2420
 2421    fn key_context_internal(
 2422        &self,
 2423        has_active_edit_prediction: bool,
 2424        window: &mut Window,
 2425        cx: &mut App,
 2426    ) -> KeyContext {
 2427        let mut key_context = KeyContext::new_with_defaults();
 2428        key_context.add("Editor");
 2429        let mode = match self.mode {
 2430            EditorMode::SingleLine => "single_line",
 2431            EditorMode::AutoHeight { .. } => "auto_height",
 2432            EditorMode::Minimap { .. } => "minimap",
 2433            EditorMode::Full { .. } => "full",
 2434        };
 2435
 2436        if EditorSettings::jupyter_enabled(cx) {
 2437            key_context.add("jupyter");
 2438        }
 2439
 2440        key_context.set("mode", mode);
 2441        if self.pending_rename.is_some() {
 2442            key_context.add("renaming");
 2443        }
 2444
 2445        match self.context_menu.borrow().as_ref() {
 2446            Some(CodeContextMenu::Completions(menu)) => {
 2447                if menu.visible() {
 2448                    key_context.add("menu");
 2449                    key_context.add("showing_completions");
 2450                }
 2451            }
 2452            Some(CodeContextMenu::CodeActions(menu)) => {
 2453                if menu.visible() {
 2454                    key_context.add("menu");
 2455                    key_context.add("showing_code_actions")
 2456                }
 2457            }
 2458            None => {}
 2459        }
 2460
 2461        if self.signature_help_state.has_multiple_signatures() {
 2462            key_context.add("showing_signature_help");
 2463        }
 2464
 2465        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2466        if !self.focus_handle(cx).contains_focused(window, cx)
 2467            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2468        {
 2469            for addon in self.addons.values() {
 2470                addon.extend_key_context(&mut key_context, cx)
 2471            }
 2472        }
 2473
 2474        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2475            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2476                Some(
 2477                    file.full_path(cx)
 2478                        .extension()?
 2479                        .to_string_lossy()
 2480                        .into_owned(),
 2481                )
 2482            }) {
 2483                key_context.set("extension", extension);
 2484            }
 2485        } else {
 2486            key_context.add("multibuffer");
 2487        }
 2488
 2489        if has_active_edit_prediction {
 2490            if self.edit_prediction_in_conflict() {
 2491                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2492            } else {
 2493                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2494                key_context.add("copilot_suggestion");
 2495            }
 2496        }
 2497
 2498        if self.selection_mark_mode {
 2499            key_context.add("selection_mode");
 2500        }
 2501
 2502        let disjoint = self.selections.disjoint_anchors();
 2503        let snapshot = self.snapshot(window, cx);
 2504        let snapshot = snapshot.buffer_snapshot();
 2505        if self.mode == EditorMode::SingleLine
 2506            && let [selection] = disjoint
 2507            && selection.start == selection.end
 2508            && selection.end.to_offset(snapshot) == snapshot.len()
 2509        {
 2510            key_context.add("end_of_input");
 2511        }
 2512
 2513        key_context
 2514    }
 2515
 2516    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2517        self.last_bounds.as_ref()
 2518    }
 2519
 2520    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2521        if self.mouse_cursor_hidden {
 2522            self.mouse_cursor_hidden = false;
 2523            cx.notify();
 2524        }
 2525    }
 2526
 2527    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2528        let hide_mouse_cursor = match origin {
 2529            HideMouseCursorOrigin::TypingAction => {
 2530                matches!(
 2531                    self.hide_mouse_mode,
 2532                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2533                )
 2534            }
 2535            HideMouseCursorOrigin::MovementAction => {
 2536                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2537            }
 2538        };
 2539        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2540            self.mouse_cursor_hidden = hide_mouse_cursor;
 2541            cx.notify();
 2542        }
 2543    }
 2544
 2545    pub fn edit_prediction_in_conflict(&self) -> bool {
 2546        if !self.show_edit_predictions_in_menu() {
 2547            return false;
 2548        }
 2549
 2550        let showing_completions = self
 2551            .context_menu
 2552            .borrow()
 2553            .as_ref()
 2554            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2555
 2556        showing_completions
 2557            || self.edit_prediction_requires_modifier()
 2558            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2559            // bindings to insert tab characters.
 2560            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2561    }
 2562
 2563    pub fn accept_edit_prediction_keybind(
 2564        &self,
 2565        accept_partial: bool,
 2566        window: &mut Window,
 2567        cx: &mut App,
 2568    ) -> AcceptEditPredictionBinding {
 2569        let key_context = self.key_context_internal(true, window, cx);
 2570        let in_conflict = self.edit_prediction_in_conflict();
 2571
 2572        let bindings = if accept_partial {
 2573            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2574        } else {
 2575            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2576        };
 2577
 2578        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2579        // just the first one.
 2580        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2581            !in_conflict
 2582                || binding
 2583                    .keystrokes()
 2584                    .first()
 2585                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2586        }))
 2587    }
 2588
 2589    pub fn new_file(
 2590        workspace: &mut Workspace,
 2591        _: &workspace::NewFile,
 2592        window: &mut Window,
 2593        cx: &mut Context<Workspace>,
 2594    ) {
 2595        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2596            "Failed to create buffer",
 2597            window,
 2598            cx,
 2599            |e, _, _| match e.error_code() {
 2600                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2601                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2602                e.error_tag("required").unwrap_or("the latest version")
 2603            )),
 2604                _ => None,
 2605            },
 2606        );
 2607    }
 2608
 2609    pub fn new_in_workspace(
 2610        workspace: &mut Workspace,
 2611        window: &mut Window,
 2612        cx: &mut Context<Workspace>,
 2613    ) -> Task<Result<Entity<Editor>>> {
 2614        let project = workspace.project().clone();
 2615        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2616
 2617        cx.spawn_in(window, async move |workspace, cx| {
 2618            let buffer = create.await?;
 2619            workspace.update_in(cx, |workspace, window, cx| {
 2620                let editor =
 2621                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2622                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2623                editor
 2624            })
 2625        })
 2626    }
 2627
 2628    fn new_file_vertical(
 2629        workspace: &mut Workspace,
 2630        _: &workspace::NewFileSplitVertical,
 2631        window: &mut Window,
 2632        cx: &mut Context<Workspace>,
 2633    ) {
 2634        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2635    }
 2636
 2637    fn new_file_horizontal(
 2638        workspace: &mut Workspace,
 2639        _: &workspace::NewFileSplitHorizontal,
 2640        window: &mut Window,
 2641        cx: &mut Context<Workspace>,
 2642    ) {
 2643        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2644    }
 2645
 2646    fn new_file_split(
 2647        workspace: &mut Workspace,
 2648        action: &workspace::NewFileSplit,
 2649        window: &mut Window,
 2650        cx: &mut Context<Workspace>,
 2651    ) {
 2652        Self::new_file_in_direction(workspace, action.0, window, cx)
 2653    }
 2654
 2655    fn new_file_in_direction(
 2656        workspace: &mut Workspace,
 2657        direction: SplitDirection,
 2658        window: &mut Window,
 2659        cx: &mut Context<Workspace>,
 2660    ) {
 2661        let project = workspace.project().clone();
 2662        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2663
 2664        cx.spawn_in(window, async move |workspace, cx| {
 2665            let buffer = create.await?;
 2666            workspace.update_in(cx, move |workspace, window, cx| {
 2667                workspace.split_item(
 2668                    direction,
 2669                    Box::new(
 2670                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2671                    ),
 2672                    window,
 2673                    cx,
 2674                )
 2675            })?;
 2676            anyhow::Ok(())
 2677        })
 2678        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2679            match e.error_code() {
 2680                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2681                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2682                e.error_tag("required").unwrap_or("the latest version")
 2683            )),
 2684                _ => None,
 2685            }
 2686        });
 2687    }
 2688
 2689    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2690        self.leader_id
 2691    }
 2692
 2693    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2694        &self.buffer
 2695    }
 2696
 2697    pub fn project(&self) -> Option<&Entity<Project>> {
 2698        self.project.as_ref()
 2699    }
 2700
 2701    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2702        self.workspace.as_ref()?.0.upgrade()
 2703    }
 2704
 2705    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2706        self.buffer().read(cx).title(cx)
 2707    }
 2708
 2709    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2710        let git_blame_gutter_max_author_length = self
 2711            .render_git_blame_gutter(cx)
 2712            .then(|| {
 2713                if let Some(blame) = self.blame.as_ref() {
 2714                    let max_author_length =
 2715                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2716                    Some(max_author_length)
 2717                } else {
 2718                    None
 2719                }
 2720            })
 2721            .flatten();
 2722
 2723        EditorSnapshot {
 2724            mode: self.mode.clone(),
 2725            show_gutter: self.show_gutter,
 2726            show_line_numbers: self.show_line_numbers,
 2727            show_git_diff_gutter: self.show_git_diff_gutter,
 2728            show_code_actions: self.show_code_actions,
 2729            show_runnables: self.show_runnables,
 2730            show_breakpoints: self.show_breakpoints,
 2731            git_blame_gutter_max_author_length,
 2732            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2733            placeholder_display_snapshot: self
 2734                .placeholder_display_map
 2735                .as_ref()
 2736                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2737            scroll_anchor: self.scroll_manager.anchor(),
 2738            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2739            is_focused: self.focus_handle.is_focused(window),
 2740            current_line_highlight: self
 2741                .current_line_highlight
 2742                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2743            gutter_hovered: self.gutter_hovered,
 2744        }
 2745    }
 2746
 2747    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2748        self.buffer.read(cx).language_at(point, cx)
 2749    }
 2750
 2751    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2752        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2753    }
 2754
 2755    pub fn active_excerpt(
 2756        &self,
 2757        cx: &App,
 2758    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2759        self.buffer
 2760            .read(cx)
 2761            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2762    }
 2763
 2764    pub fn mode(&self) -> &EditorMode {
 2765        &self.mode
 2766    }
 2767
 2768    pub fn set_mode(&mut self, mode: EditorMode) {
 2769        self.mode = mode;
 2770    }
 2771
 2772    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2773        self.collaboration_hub.as_deref()
 2774    }
 2775
 2776    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2777        self.collaboration_hub = Some(hub);
 2778    }
 2779
 2780    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2781        self.in_project_search = in_project_search;
 2782    }
 2783
 2784    pub fn set_custom_context_menu(
 2785        &mut self,
 2786        f: impl 'static
 2787        + Fn(
 2788            &mut Self,
 2789            DisplayPoint,
 2790            &mut Window,
 2791            &mut Context<Self>,
 2792        ) -> Option<Entity<ui::ContextMenu>>,
 2793    ) {
 2794        self.custom_context_menu = Some(Box::new(f))
 2795    }
 2796
 2797    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2798        self.completion_provider = provider;
 2799    }
 2800
 2801    #[cfg(any(test, feature = "test-support"))]
 2802    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2803        self.completion_provider.clone()
 2804    }
 2805
 2806    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2807        self.semantics_provider.clone()
 2808    }
 2809
 2810    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2811        self.semantics_provider = provider;
 2812    }
 2813
 2814    pub fn set_edit_prediction_provider<T>(
 2815        &mut self,
 2816        provider: Option<Entity<T>>,
 2817        window: &mut Window,
 2818        cx: &mut Context<Self>,
 2819    ) where
 2820        T: EditPredictionProvider,
 2821    {
 2822        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2823            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2824                if this.focus_handle.is_focused(window) {
 2825                    this.update_visible_edit_prediction(window, cx);
 2826                }
 2827            }),
 2828            provider: Arc::new(provider),
 2829        });
 2830        self.update_edit_prediction_settings(cx);
 2831        self.refresh_edit_prediction(false, false, window, cx);
 2832    }
 2833
 2834    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2835        self.placeholder_display_map
 2836            .as_ref()
 2837            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2838    }
 2839
 2840    pub fn set_placeholder_text(
 2841        &mut self,
 2842        placeholder_text: &str,
 2843        window: &mut Window,
 2844        cx: &mut Context<Self>,
 2845    ) {
 2846        let multibuffer = cx
 2847            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2848
 2849        let style = window.text_style();
 2850
 2851        self.placeholder_display_map = Some(cx.new(|cx| {
 2852            DisplayMap::new(
 2853                multibuffer,
 2854                style.font(),
 2855                style.font_size.to_pixels(window.rem_size()),
 2856                None,
 2857                FILE_HEADER_HEIGHT,
 2858                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2859                Default::default(),
 2860                DiagnosticSeverity::Off,
 2861                cx,
 2862            )
 2863        }));
 2864        cx.notify();
 2865    }
 2866
 2867    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2868        self.cursor_shape = cursor_shape;
 2869
 2870        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2871        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2872
 2873        cx.notify();
 2874    }
 2875
 2876    pub fn set_current_line_highlight(
 2877        &mut self,
 2878        current_line_highlight: Option<CurrentLineHighlight>,
 2879    ) {
 2880        self.current_line_highlight = current_line_highlight;
 2881    }
 2882
 2883    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2884        self.collapse_matches = collapse_matches;
 2885    }
 2886
 2887    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2888        if self.collapse_matches {
 2889            return range.start..range.start;
 2890        }
 2891        range.clone()
 2892    }
 2893
 2894    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2895        if self.display_map.read(cx).clip_at_line_ends != clip {
 2896            self.display_map
 2897                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2898        }
 2899    }
 2900
 2901    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2902        self.input_enabled = input_enabled;
 2903    }
 2904
 2905    pub fn set_edit_predictions_hidden_for_vim_mode(
 2906        &mut self,
 2907        hidden: bool,
 2908        window: &mut Window,
 2909        cx: &mut Context<Self>,
 2910    ) {
 2911        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2912            self.edit_predictions_hidden_for_vim_mode = hidden;
 2913            if hidden {
 2914                self.update_visible_edit_prediction(window, cx);
 2915            } else {
 2916                self.refresh_edit_prediction(true, false, window, cx);
 2917            }
 2918        }
 2919    }
 2920
 2921    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2922        self.menu_edit_predictions_policy = value;
 2923    }
 2924
 2925    pub fn set_autoindent(&mut self, autoindent: bool) {
 2926        if autoindent {
 2927            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2928        } else {
 2929            self.autoindent_mode = None;
 2930        }
 2931    }
 2932
 2933    pub fn read_only(&self, cx: &App) -> bool {
 2934        self.read_only || self.buffer.read(cx).read_only()
 2935    }
 2936
 2937    pub fn set_read_only(&mut self, read_only: bool) {
 2938        self.read_only = read_only;
 2939    }
 2940
 2941    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2942        self.use_autoclose = autoclose;
 2943    }
 2944
 2945    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2946        self.use_auto_surround = auto_surround;
 2947    }
 2948
 2949    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2950        self.auto_replace_emoji_shortcode = auto_replace;
 2951    }
 2952
 2953    pub fn toggle_edit_predictions(
 2954        &mut self,
 2955        _: &ToggleEditPrediction,
 2956        window: &mut Window,
 2957        cx: &mut Context<Self>,
 2958    ) {
 2959        if self.show_edit_predictions_override.is_some() {
 2960            self.set_show_edit_predictions(None, window, cx);
 2961        } else {
 2962            let show_edit_predictions = !self.edit_predictions_enabled();
 2963            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2964        }
 2965    }
 2966
 2967    pub fn set_show_edit_predictions(
 2968        &mut self,
 2969        show_edit_predictions: Option<bool>,
 2970        window: &mut Window,
 2971        cx: &mut Context<Self>,
 2972    ) {
 2973        self.show_edit_predictions_override = show_edit_predictions;
 2974        self.update_edit_prediction_settings(cx);
 2975
 2976        if let Some(false) = show_edit_predictions {
 2977            self.discard_edit_prediction(false, cx);
 2978        } else {
 2979            self.refresh_edit_prediction(false, true, window, cx);
 2980        }
 2981    }
 2982
 2983    fn edit_predictions_disabled_in_scope(
 2984        &self,
 2985        buffer: &Entity<Buffer>,
 2986        buffer_position: language::Anchor,
 2987        cx: &App,
 2988    ) -> bool {
 2989        let snapshot = buffer.read(cx).snapshot();
 2990        let settings = snapshot.settings_at(buffer_position, cx);
 2991
 2992        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2993            return false;
 2994        };
 2995
 2996        scope.override_name().is_some_and(|scope_name| {
 2997            settings
 2998                .edit_predictions_disabled_in
 2999                .iter()
 3000                .any(|s| s == scope_name)
 3001        })
 3002    }
 3003
 3004    pub fn set_use_modal_editing(&mut self, to: bool) {
 3005        self.use_modal_editing = to;
 3006    }
 3007
 3008    pub fn use_modal_editing(&self) -> bool {
 3009        self.use_modal_editing
 3010    }
 3011
 3012    fn selections_did_change(
 3013        &mut self,
 3014        local: bool,
 3015        old_cursor_position: &Anchor,
 3016        effects: SelectionEffects,
 3017        window: &mut Window,
 3018        cx: &mut Context<Self>,
 3019    ) {
 3020        window.invalidate_character_coordinates();
 3021
 3022        // Copy selections to primary selection buffer
 3023        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3024        if local {
 3025            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3026            let buffer_handle = self.buffer.read(cx).read(cx);
 3027
 3028            let mut text = String::new();
 3029            for (index, selection) in selections.iter().enumerate() {
 3030                let text_for_selection = buffer_handle
 3031                    .text_for_range(selection.start..selection.end)
 3032                    .collect::<String>();
 3033
 3034                text.push_str(&text_for_selection);
 3035                if index != selections.len() - 1 {
 3036                    text.push('\n');
 3037                }
 3038            }
 3039
 3040            if !text.is_empty() {
 3041                cx.write_to_primary(ClipboardItem::new_string(text));
 3042            }
 3043        }
 3044
 3045        let selection_anchors = self.selections.disjoint_anchors_arc();
 3046
 3047        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3048            self.buffer.update(cx, |buffer, cx| {
 3049                buffer.set_active_selections(
 3050                    &selection_anchors,
 3051                    self.selections.line_mode(),
 3052                    self.cursor_shape,
 3053                    cx,
 3054                )
 3055            });
 3056        }
 3057        let display_map = self
 3058            .display_map
 3059            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3060        let buffer = display_map.buffer_snapshot();
 3061        if self.selections.count() == 1 {
 3062            self.add_selections_state = None;
 3063        }
 3064        self.select_next_state = None;
 3065        self.select_prev_state = None;
 3066        self.select_syntax_node_history.try_clear();
 3067        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3068        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3069        self.take_rename(false, window, cx);
 3070
 3071        let newest_selection = self.selections.newest_anchor();
 3072        let new_cursor_position = newest_selection.head();
 3073        let selection_start = newest_selection.start;
 3074
 3075        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3076            self.push_to_nav_history(
 3077                *old_cursor_position,
 3078                Some(new_cursor_position.to_point(buffer)),
 3079                false,
 3080                effects.nav_history == Some(true),
 3081                cx,
 3082            );
 3083        }
 3084
 3085        if local {
 3086            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3087                self.register_buffer(buffer_id, cx);
 3088            }
 3089
 3090            let mut context_menu = self.context_menu.borrow_mut();
 3091            let completion_menu = match context_menu.as_ref() {
 3092                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3093                Some(CodeContextMenu::CodeActions(_)) => {
 3094                    *context_menu = None;
 3095                    None
 3096                }
 3097                None => None,
 3098            };
 3099            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3100            drop(context_menu);
 3101
 3102            if effects.completions
 3103                && let Some(completion_position) = completion_position
 3104            {
 3105                let start_offset = selection_start.to_offset(buffer);
 3106                let position_matches = start_offset == completion_position.to_offset(buffer);
 3107                let continue_showing = if position_matches {
 3108                    if self.snippet_stack.is_empty() {
 3109                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3110                            == Some(CharKind::Word)
 3111                    } else {
 3112                        // Snippet choices can be shown even when the cursor is in whitespace.
 3113                        // Dismissing the menu with actions like backspace is handled by
 3114                        // invalidation regions.
 3115                        true
 3116                    }
 3117                } else {
 3118                    false
 3119                };
 3120
 3121                if continue_showing {
 3122                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3123                } else {
 3124                    self.hide_context_menu(window, cx);
 3125                }
 3126            }
 3127
 3128            hide_hover(self, cx);
 3129
 3130            if old_cursor_position.to_display_point(&display_map).row()
 3131                != new_cursor_position.to_display_point(&display_map).row()
 3132            {
 3133                self.available_code_actions.take();
 3134            }
 3135            self.refresh_code_actions(window, cx);
 3136            self.refresh_document_highlights(cx);
 3137            refresh_linked_ranges(self, window, cx);
 3138
 3139            self.refresh_selected_text_highlights(false, window, cx);
 3140            self.refresh_matching_bracket_highlights(window, cx);
 3141            self.update_visible_edit_prediction(window, cx);
 3142            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3143            self.inline_blame_popover.take();
 3144            if self.git_blame_inline_enabled {
 3145                self.start_inline_blame_timer(window, cx);
 3146            }
 3147        }
 3148
 3149        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3150        cx.emit(EditorEvent::SelectionsChanged { local });
 3151
 3152        let selections = &self.selections.disjoint_anchors_arc();
 3153        if selections.len() == 1 {
 3154            cx.emit(SearchEvent::ActiveMatchChanged)
 3155        }
 3156        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3157            let inmemory_selections = selections
 3158                .iter()
 3159                .map(|s| {
 3160                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3161                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3162                })
 3163                .collect();
 3164            self.update_restoration_data(cx, |data| {
 3165                data.selections = inmemory_selections;
 3166            });
 3167
 3168            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3169                && let Some(workspace_id) =
 3170                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3171            {
 3172                let snapshot = self.buffer().read(cx).snapshot(cx);
 3173                let selections = selections.clone();
 3174                let background_executor = cx.background_executor().clone();
 3175                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3176                self.serialize_selections = cx.background_spawn(async move {
 3177                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3178                    let db_selections = selections
 3179                        .iter()
 3180                        .map(|selection| {
 3181                            (
 3182                                selection.start.to_offset(&snapshot),
 3183                                selection.end.to_offset(&snapshot),
 3184                            )
 3185                        })
 3186                        .collect();
 3187
 3188                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3189                        .await
 3190                        .with_context(|| {
 3191                            format!(
 3192                                "persisting editor selections for editor {editor_id}, \
 3193                                workspace {workspace_id:?}"
 3194                            )
 3195                        })
 3196                        .log_err();
 3197                });
 3198            }
 3199        }
 3200
 3201        cx.notify();
 3202    }
 3203
 3204    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3205        use text::ToOffset as _;
 3206        use text::ToPoint as _;
 3207
 3208        if self.mode.is_minimap()
 3209            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3210        {
 3211            return;
 3212        }
 3213
 3214        if !self.buffer().read(cx).is_singleton() {
 3215            return;
 3216        }
 3217
 3218        let display_snapshot = self
 3219            .display_map
 3220            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3221        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3222            return;
 3223        };
 3224        let inmemory_folds = display_snapshot
 3225            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3226            .map(|fold| {
 3227                fold.range.start.text_anchor.to_point(&snapshot)
 3228                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3229            })
 3230            .collect();
 3231        self.update_restoration_data(cx, |data| {
 3232            data.folds = inmemory_folds;
 3233        });
 3234
 3235        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3236            return;
 3237        };
 3238        let background_executor = cx.background_executor().clone();
 3239        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3240        let db_folds = display_snapshot
 3241            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3242            .map(|fold| {
 3243                (
 3244                    fold.range.start.text_anchor.to_offset(&snapshot),
 3245                    fold.range.end.text_anchor.to_offset(&snapshot),
 3246                )
 3247            })
 3248            .collect();
 3249        self.serialize_folds = cx.background_spawn(async move {
 3250            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3251            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3252                .await
 3253                .with_context(|| {
 3254                    format!(
 3255                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3256                    )
 3257                })
 3258                .log_err();
 3259        });
 3260    }
 3261
 3262    pub fn sync_selections(
 3263        &mut self,
 3264        other: Entity<Editor>,
 3265        cx: &mut Context<Self>,
 3266    ) -> gpui::Subscription {
 3267        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3268        if !other_selections.is_empty() {
 3269            self.selections.change_with(cx, |selections| {
 3270                selections.select_anchors(other_selections);
 3271            });
 3272        }
 3273
 3274        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3275            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3276                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3277                if other_selections.is_empty() {
 3278                    return;
 3279                }
 3280                this.selections.change_with(cx, |selections| {
 3281                    selections.select_anchors(other_selections);
 3282                });
 3283            }
 3284        });
 3285
 3286        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3287            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3288                let these_selections = this.selections.disjoint_anchors().to_vec();
 3289                if these_selections.is_empty() {
 3290                    return;
 3291                }
 3292                other.update(cx, |other_editor, cx| {
 3293                    other_editor.selections.change_with(cx, |selections| {
 3294                        selections.select_anchors(these_selections);
 3295                    })
 3296                });
 3297            }
 3298        });
 3299
 3300        Subscription::join(other_subscription, this_subscription)
 3301    }
 3302
 3303    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3304    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3305    /// effects of selection change occur at the end of the transaction.
 3306    pub fn change_selections<R>(
 3307        &mut self,
 3308        effects: SelectionEffects,
 3309        window: &mut Window,
 3310        cx: &mut Context<Self>,
 3311        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3312    ) -> R {
 3313        if let Some(state) = &mut self.deferred_selection_effects_state {
 3314            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3315            state.effects.completions = effects.completions;
 3316            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3317            let (changed, result) = self.selections.change_with(cx, change);
 3318            state.changed |= changed;
 3319            return result;
 3320        }
 3321        let mut state = DeferredSelectionEffectsState {
 3322            changed: false,
 3323            effects,
 3324            old_cursor_position: self.selections.newest_anchor().head(),
 3325            history_entry: SelectionHistoryEntry {
 3326                selections: self.selections.disjoint_anchors_arc(),
 3327                select_next_state: self.select_next_state.clone(),
 3328                select_prev_state: self.select_prev_state.clone(),
 3329                add_selections_state: self.add_selections_state.clone(),
 3330            },
 3331        };
 3332        let (changed, result) = self.selections.change_with(cx, change);
 3333        state.changed = state.changed || changed;
 3334        if self.defer_selection_effects {
 3335            self.deferred_selection_effects_state = Some(state);
 3336        } else {
 3337            self.apply_selection_effects(state, window, cx);
 3338        }
 3339        result
 3340    }
 3341
 3342    /// Defers the effects of selection change, so that the effects of multiple calls to
 3343    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3344    /// to selection history and the state of popovers based on selection position aren't
 3345    /// erroneously updated.
 3346    pub fn with_selection_effects_deferred<R>(
 3347        &mut self,
 3348        window: &mut Window,
 3349        cx: &mut Context<Self>,
 3350        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3351    ) -> R {
 3352        let already_deferred = self.defer_selection_effects;
 3353        self.defer_selection_effects = true;
 3354        let result = update(self, window, cx);
 3355        if !already_deferred {
 3356            self.defer_selection_effects = false;
 3357            if let Some(state) = self.deferred_selection_effects_state.take() {
 3358                self.apply_selection_effects(state, window, cx);
 3359            }
 3360        }
 3361        result
 3362    }
 3363
 3364    fn apply_selection_effects(
 3365        &mut self,
 3366        state: DeferredSelectionEffectsState,
 3367        window: &mut Window,
 3368        cx: &mut Context<Self>,
 3369    ) {
 3370        if state.changed {
 3371            self.selection_history.push(state.history_entry);
 3372
 3373            if let Some(autoscroll) = state.effects.scroll {
 3374                self.request_autoscroll(autoscroll, cx);
 3375            }
 3376
 3377            let old_cursor_position = &state.old_cursor_position;
 3378
 3379            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3380
 3381            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3382                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3383            }
 3384        }
 3385    }
 3386
 3387    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3388    where
 3389        I: IntoIterator<Item = (Range<S>, T)>,
 3390        S: ToOffset,
 3391        T: Into<Arc<str>>,
 3392    {
 3393        if self.read_only(cx) {
 3394            return;
 3395        }
 3396
 3397        self.buffer
 3398            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3399    }
 3400
 3401    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3402    where
 3403        I: IntoIterator<Item = (Range<S>, T)>,
 3404        S: ToOffset,
 3405        T: Into<Arc<str>>,
 3406    {
 3407        if self.read_only(cx) {
 3408            return;
 3409        }
 3410
 3411        self.buffer.update(cx, |buffer, cx| {
 3412            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3413        });
 3414    }
 3415
 3416    pub fn edit_with_block_indent<I, S, T>(
 3417        &mut self,
 3418        edits: I,
 3419        original_indent_columns: Vec<Option<u32>>,
 3420        cx: &mut Context<Self>,
 3421    ) where
 3422        I: IntoIterator<Item = (Range<S>, T)>,
 3423        S: ToOffset,
 3424        T: Into<Arc<str>>,
 3425    {
 3426        if self.read_only(cx) {
 3427            return;
 3428        }
 3429
 3430        self.buffer.update(cx, |buffer, cx| {
 3431            buffer.edit(
 3432                edits,
 3433                Some(AutoindentMode::Block {
 3434                    original_indent_columns,
 3435                }),
 3436                cx,
 3437            )
 3438        });
 3439    }
 3440
 3441    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3442        self.hide_context_menu(window, cx);
 3443
 3444        match phase {
 3445            SelectPhase::Begin {
 3446                position,
 3447                add,
 3448                click_count,
 3449            } => self.begin_selection(position, add, click_count, window, cx),
 3450            SelectPhase::BeginColumnar {
 3451                position,
 3452                goal_column,
 3453                reset,
 3454                mode,
 3455            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3456            SelectPhase::Extend {
 3457                position,
 3458                click_count,
 3459            } => self.extend_selection(position, click_count, window, cx),
 3460            SelectPhase::Update {
 3461                position,
 3462                goal_column,
 3463                scroll_delta,
 3464            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3465            SelectPhase::End => self.end_selection(window, cx),
 3466        }
 3467    }
 3468
 3469    fn extend_selection(
 3470        &mut self,
 3471        position: DisplayPoint,
 3472        click_count: usize,
 3473        window: &mut Window,
 3474        cx: &mut Context<Self>,
 3475    ) {
 3476        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3477        let tail = self.selections.newest::<usize>(&display_map).tail();
 3478        let click_count = click_count.max(match self.selections.select_mode() {
 3479            SelectMode::Character => 1,
 3480            SelectMode::Word(_) => 2,
 3481            SelectMode::Line(_) => 3,
 3482            SelectMode::All => 4,
 3483        });
 3484        self.begin_selection(position, false, click_count, window, cx);
 3485
 3486        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3487
 3488        let current_selection = match self.selections.select_mode() {
 3489            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3490            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3491        };
 3492
 3493        let mut pending_selection = self
 3494            .selections
 3495            .pending_anchor()
 3496            .cloned()
 3497            .expect("extend_selection not called with pending selection");
 3498
 3499        if pending_selection
 3500            .start
 3501            .cmp(¤t_selection.start, display_map.buffer_snapshot())
 3502            == Ordering::Greater
 3503        {
 3504            pending_selection.start = current_selection.start;
 3505        }
 3506        if pending_selection
 3507            .end
 3508            .cmp(¤t_selection.end, display_map.buffer_snapshot())
 3509            == Ordering::Less
 3510        {
 3511            pending_selection.end = current_selection.end;
 3512            pending_selection.reversed = true;
 3513        }
 3514
 3515        let mut pending_mode = self.selections.pending_mode().unwrap();
 3516        match &mut pending_mode {
 3517            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3518            _ => {}
 3519        }
 3520
 3521        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3522            SelectionEffects::scroll(Autoscroll::fit())
 3523        } else {
 3524            SelectionEffects::no_scroll()
 3525        };
 3526
 3527        self.change_selections(effects, window, cx, |s| {
 3528            s.set_pending(pending_selection.clone(), pending_mode);
 3529            s.set_is_extending(true);
 3530        });
 3531    }
 3532
 3533    fn begin_selection(
 3534        &mut self,
 3535        position: DisplayPoint,
 3536        add: bool,
 3537        click_count: usize,
 3538        window: &mut Window,
 3539        cx: &mut Context<Self>,
 3540    ) {
 3541        if !self.focus_handle.is_focused(window) {
 3542            self.last_focused_descendant = None;
 3543            window.focus(&self.focus_handle);
 3544        }
 3545
 3546        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3547        let buffer = display_map.buffer_snapshot();
 3548        let position = display_map.clip_point(position, Bias::Left);
 3549
 3550        let start;
 3551        let end;
 3552        let mode;
 3553        let mut auto_scroll;
 3554        match click_count {
 3555            1 => {
 3556                start = buffer.anchor_before(position.to_point(&display_map));
 3557                end = start;
 3558                mode = SelectMode::Character;
 3559                auto_scroll = true;
 3560            }
 3561            2 => {
 3562                let position = display_map
 3563                    .clip_point(position, Bias::Left)
 3564                    .to_offset(&display_map, Bias::Left);
 3565                let (range, _) = buffer.surrounding_word(position, None);
 3566                start = buffer.anchor_before(range.start);
 3567                end = buffer.anchor_before(range.end);
 3568                mode = SelectMode::Word(start..end);
 3569                auto_scroll = true;
 3570            }
 3571            3 => {
 3572                let position = display_map
 3573                    .clip_point(position, Bias::Left)
 3574                    .to_point(&display_map);
 3575                let line_start = display_map.prev_line_boundary(position).0;
 3576                let next_line_start = buffer.clip_point(
 3577                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3578                    Bias::Left,
 3579                );
 3580                start = buffer.anchor_before(line_start);
 3581                end = buffer.anchor_before(next_line_start);
 3582                mode = SelectMode::Line(start..end);
 3583                auto_scroll = true;
 3584            }
 3585            _ => {
 3586                start = buffer.anchor_before(0);
 3587                end = buffer.anchor_before(buffer.len());
 3588                mode = SelectMode::All;
 3589                auto_scroll = false;
 3590            }
 3591        }
 3592        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3593
 3594        let point_to_delete: Option<usize> = {
 3595            let selected_points: Vec<Selection<Point>> =
 3596                self.selections.disjoint_in_range(start..end, &display_map);
 3597
 3598            if !add || click_count > 1 {
 3599                None
 3600            } else if !selected_points.is_empty() {
 3601                Some(selected_points[0].id)
 3602            } else {
 3603                let clicked_point_already_selected =
 3604                    self.selections.disjoint_anchors().iter().find(|selection| {
 3605                        selection.start.to_point(buffer) == start.to_point(buffer)
 3606                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3607                    });
 3608
 3609                clicked_point_already_selected.map(|selection| selection.id)
 3610            }
 3611        };
 3612
 3613        let selections_count = self.selections.count();
 3614        let effects = if auto_scroll {
 3615            SelectionEffects::default()
 3616        } else {
 3617            SelectionEffects::no_scroll()
 3618        };
 3619
 3620        self.change_selections(effects, window, cx, |s| {
 3621            if let Some(point_to_delete) = point_to_delete {
 3622                s.delete(point_to_delete);
 3623
 3624                if selections_count == 1 {
 3625                    s.set_pending_anchor_range(start..end, mode);
 3626                }
 3627            } else {
 3628                if !add {
 3629                    s.clear_disjoint();
 3630                }
 3631
 3632                s.set_pending_anchor_range(start..end, mode);
 3633            }
 3634        });
 3635    }
 3636
 3637    fn begin_columnar_selection(
 3638        &mut self,
 3639        position: DisplayPoint,
 3640        goal_column: u32,
 3641        reset: bool,
 3642        mode: ColumnarMode,
 3643        window: &mut Window,
 3644        cx: &mut Context<Self>,
 3645    ) {
 3646        if !self.focus_handle.is_focused(window) {
 3647            self.last_focused_descendant = None;
 3648            window.focus(&self.focus_handle);
 3649        }
 3650
 3651        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3652
 3653        if reset {
 3654            let pointer_position = display_map
 3655                .buffer_snapshot()
 3656                .anchor_before(position.to_point(&display_map));
 3657
 3658            self.change_selections(
 3659                SelectionEffects::scroll(Autoscroll::newest()),
 3660                window,
 3661                cx,
 3662                |s| {
 3663                    s.clear_disjoint();
 3664                    s.set_pending_anchor_range(
 3665                        pointer_position..pointer_position,
 3666                        SelectMode::Character,
 3667                    );
 3668                },
 3669            );
 3670        };
 3671
 3672        let tail = self.selections.newest::<Point>(&display_map).tail();
 3673        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3674        self.columnar_selection_state = match mode {
 3675            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3676                selection_tail: selection_anchor,
 3677                display_point: if reset {
 3678                    if position.column() != goal_column {
 3679                        Some(DisplayPoint::new(position.row(), goal_column))
 3680                    } else {
 3681                        None
 3682                    }
 3683                } else {
 3684                    None
 3685                },
 3686            }),
 3687            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3688                selection_tail: selection_anchor,
 3689            }),
 3690        };
 3691
 3692        if !reset {
 3693            self.select_columns(position, goal_column, &display_map, window, cx);
 3694        }
 3695    }
 3696
 3697    fn update_selection(
 3698        &mut self,
 3699        position: DisplayPoint,
 3700        goal_column: u32,
 3701        scroll_delta: gpui::Point<f32>,
 3702        window: &mut Window,
 3703        cx: &mut Context<Self>,
 3704    ) {
 3705        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3706
 3707        if self.columnar_selection_state.is_some() {
 3708            self.select_columns(position, goal_column, &display_map, window, cx);
 3709        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3710            let buffer = display_map.buffer_snapshot();
 3711            let head;
 3712            let tail;
 3713            let mode = self.selections.pending_mode().unwrap();
 3714            match &mode {
 3715                SelectMode::Character => {
 3716                    head = position.to_point(&display_map);
 3717                    tail = pending.tail().to_point(buffer);
 3718                }
 3719                SelectMode::Word(original_range) => {
 3720                    let offset = display_map
 3721                        .clip_point(position, Bias::Left)
 3722                        .to_offset(&display_map, Bias::Left);
 3723                    let original_range = original_range.to_offset(buffer);
 3724
 3725                    let head_offset = if buffer.is_inside_word(offset, None)
 3726                        || original_range.contains(&offset)
 3727                    {
 3728                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3729                        if word_range.start < original_range.start {
 3730                            word_range.start
 3731                        } else {
 3732                            word_range.end
 3733                        }
 3734                    } else {
 3735                        offset
 3736                    };
 3737
 3738                    head = head_offset.to_point(buffer);
 3739                    if head_offset <= original_range.start {
 3740                        tail = original_range.end.to_point(buffer);
 3741                    } else {
 3742                        tail = original_range.start.to_point(buffer);
 3743                    }
 3744                }
 3745                SelectMode::Line(original_range) => {
 3746                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3747
 3748                    let position = display_map
 3749                        .clip_point(position, Bias::Left)
 3750                        .to_point(&display_map);
 3751                    let line_start = display_map.prev_line_boundary(position).0;
 3752                    let next_line_start = buffer.clip_point(
 3753                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3754                        Bias::Left,
 3755                    );
 3756
 3757                    if line_start < original_range.start {
 3758                        head = line_start
 3759                    } else {
 3760                        head = next_line_start
 3761                    }
 3762
 3763                    if head <= original_range.start {
 3764                        tail = original_range.end;
 3765                    } else {
 3766                        tail = original_range.start;
 3767                    }
 3768                }
 3769                SelectMode::All => {
 3770                    return;
 3771                }
 3772            };
 3773
 3774            if head < tail {
 3775                pending.start = buffer.anchor_before(head);
 3776                pending.end = buffer.anchor_before(tail);
 3777                pending.reversed = true;
 3778            } else {
 3779                pending.start = buffer.anchor_before(tail);
 3780                pending.end = buffer.anchor_before(head);
 3781                pending.reversed = false;
 3782            }
 3783
 3784            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3785                s.set_pending(pending.clone(), mode);
 3786            });
 3787        } else {
 3788            log::error!("update_selection dispatched with no pending selection");
 3789            return;
 3790        }
 3791
 3792        self.apply_scroll_delta(scroll_delta, window, cx);
 3793        cx.notify();
 3794    }
 3795
 3796    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3797        self.columnar_selection_state.take();
 3798        if let Some(pending_mode) = self.selections.pending_mode() {
 3799            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3800            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3801                s.select(selections);
 3802                s.clear_pending();
 3803                if s.is_extending() {
 3804                    s.set_is_extending(false);
 3805                } else {
 3806                    s.set_select_mode(pending_mode);
 3807                }
 3808            });
 3809        }
 3810    }
 3811
 3812    fn select_columns(
 3813        &mut self,
 3814        head: DisplayPoint,
 3815        goal_column: u32,
 3816        display_map: &DisplaySnapshot,
 3817        window: &mut Window,
 3818        cx: &mut Context<Self>,
 3819    ) {
 3820        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3821            return;
 3822        };
 3823
 3824        let tail = match columnar_state {
 3825            ColumnarSelectionState::FromMouse {
 3826                selection_tail,
 3827                display_point,
 3828            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3829            ColumnarSelectionState::FromSelection { selection_tail } => {
 3830                selection_tail.to_display_point(display_map)
 3831            }
 3832        };
 3833
 3834        let start_row = cmp::min(tail.row(), head.row());
 3835        let end_row = cmp::max(tail.row(), head.row());
 3836        let start_column = cmp::min(tail.column(), goal_column);
 3837        let end_column = cmp::max(tail.column(), goal_column);
 3838        let reversed = start_column < tail.column();
 3839
 3840        let selection_ranges = (start_row.0..=end_row.0)
 3841            .map(DisplayRow)
 3842            .filter_map(|row| {
 3843                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3844                    || start_column <= display_map.line_len(row))
 3845                    && !display_map.is_block_line(row)
 3846                {
 3847                    let start = display_map
 3848                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3849                        .to_point(display_map);
 3850                    let end = display_map
 3851                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3852                        .to_point(display_map);
 3853                    if reversed {
 3854                        Some(end..start)
 3855                    } else {
 3856                        Some(start..end)
 3857                    }
 3858                } else {
 3859                    None
 3860                }
 3861            })
 3862            .collect::<Vec<_>>();
 3863        if selection_ranges.is_empty() {
 3864            return;
 3865        }
 3866
 3867        let ranges = match columnar_state {
 3868            ColumnarSelectionState::FromMouse { .. } => {
 3869                let mut non_empty_ranges = selection_ranges
 3870                    .iter()
 3871                    .filter(|selection_range| selection_range.start != selection_range.end)
 3872                    .peekable();
 3873                if non_empty_ranges.peek().is_some() {
 3874                    non_empty_ranges.cloned().collect()
 3875                } else {
 3876                    selection_ranges
 3877                }
 3878            }
 3879            _ => selection_ranges,
 3880        };
 3881
 3882        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3883            s.select_ranges(ranges);
 3884        });
 3885        cx.notify();
 3886    }
 3887
 3888    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3889        self.selections
 3890            .all_adjusted(snapshot)
 3891            .iter()
 3892            .any(|selection| !selection.is_empty())
 3893    }
 3894
 3895    pub fn has_pending_nonempty_selection(&self) -> bool {
 3896        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3897            Some(Selection { start, end, .. }) => start != end,
 3898            None => false,
 3899        };
 3900
 3901        pending_nonempty_selection
 3902            || (self.columnar_selection_state.is_some()
 3903                && self.selections.disjoint_anchors().len() > 1)
 3904    }
 3905
 3906    pub fn has_pending_selection(&self) -> bool {
 3907        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3908    }
 3909
 3910    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3911        self.selection_mark_mode = false;
 3912        self.selection_drag_state = SelectionDragState::None;
 3913
 3914        if self.clear_expanded_diff_hunks(cx) {
 3915            cx.notify();
 3916            return;
 3917        }
 3918        if self.dismiss_menus_and_popups(true, window, cx) {
 3919            return;
 3920        }
 3921
 3922        if self.mode.is_full()
 3923            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3924        {
 3925            return;
 3926        }
 3927
 3928        cx.propagate();
 3929    }
 3930
 3931    pub fn dismiss_menus_and_popups(
 3932        &mut self,
 3933        is_user_requested: bool,
 3934        window: &mut Window,
 3935        cx: &mut Context<Self>,
 3936    ) -> bool {
 3937        if self.take_rename(false, window, cx).is_some() {
 3938            return true;
 3939        }
 3940
 3941        if self.hide_blame_popover(true, cx) {
 3942            return true;
 3943        }
 3944
 3945        if hide_hover(self, cx) {
 3946            return true;
 3947        }
 3948
 3949        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3950            return true;
 3951        }
 3952
 3953        if self.hide_context_menu(window, cx).is_some() {
 3954            return true;
 3955        }
 3956
 3957        if self.mouse_context_menu.take().is_some() {
 3958            return true;
 3959        }
 3960
 3961        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3962            return true;
 3963        }
 3964
 3965        if self.snippet_stack.pop().is_some() {
 3966            return true;
 3967        }
 3968
 3969        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3970            self.dismiss_diagnostics(cx);
 3971            return true;
 3972        }
 3973
 3974        false
 3975    }
 3976
 3977    fn linked_editing_ranges_for(
 3978        &self,
 3979        selection: Range<text::Anchor>,
 3980        cx: &App,
 3981    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3982        if self.linked_edit_ranges.is_empty() {
 3983            return None;
 3984        }
 3985        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3986            selection.end.buffer_id.and_then(|end_buffer_id| {
 3987                if selection.start.buffer_id != Some(end_buffer_id) {
 3988                    return None;
 3989                }
 3990                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3991                let snapshot = buffer.read(cx).snapshot();
 3992                self.linked_edit_ranges
 3993                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3994                    .map(|ranges| (ranges, snapshot, buffer))
 3995            })?;
 3996        use text::ToOffset as TO;
 3997        // find offset from the start of current range to current cursor position
 3998        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3999
 4000        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4001        let start_difference = start_offset - start_byte_offset;
 4002        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4003        let end_difference = end_offset - start_byte_offset;
 4004        // Current range has associated linked ranges.
 4005        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4006        for range in linked_ranges.iter() {
 4007            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4008            let end_offset = start_offset + end_difference;
 4009            let start_offset = start_offset + start_difference;
 4010            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4011                continue;
 4012            }
 4013            if self.selections.disjoint_anchor_ranges().any(|s| {
 4014                if s.start.buffer_id != selection.start.buffer_id
 4015                    || s.end.buffer_id != selection.end.buffer_id
 4016                {
 4017                    return false;
 4018                }
 4019                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4020                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4021            }) {
 4022                continue;
 4023            }
 4024            let start = buffer_snapshot.anchor_after(start_offset);
 4025            let end = buffer_snapshot.anchor_after(end_offset);
 4026            linked_edits
 4027                .entry(buffer.clone())
 4028                .or_default()
 4029                .push(start..end);
 4030        }
 4031        Some(linked_edits)
 4032    }
 4033
 4034    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4035        let text: Arc<str> = text.into();
 4036
 4037        if self.read_only(cx) {
 4038            return;
 4039        }
 4040
 4041        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4042
 4043        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4044        let mut bracket_inserted = false;
 4045        let mut edits = Vec::new();
 4046        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4047        let mut new_selections = Vec::with_capacity(selections.len());
 4048        let mut new_autoclose_regions = Vec::new();
 4049        let snapshot = self.buffer.read(cx).read(cx);
 4050        let mut clear_linked_edit_ranges = false;
 4051
 4052        for (selection, autoclose_region) in
 4053            self.selections_with_autoclose_regions(selections, &snapshot)
 4054        {
 4055            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4056                // Determine if the inserted text matches the opening or closing
 4057                // bracket of any of this language's bracket pairs.
 4058                let mut bracket_pair = None;
 4059                let mut is_bracket_pair_start = false;
 4060                let mut is_bracket_pair_end = false;
 4061                if !text.is_empty() {
 4062                    let mut bracket_pair_matching_end = None;
 4063                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4064                    //  and they are removing the character that triggered IME popup.
 4065                    for (pair, enabled) in scope.brackets() {
 4066                        if !pair.close && !pair.surround {
 4067                            continue;
 4068                        }
 4069
 4070                        if enabled && pair.start.ends_with(text.as_ref()) {
 4071                            let prefix_len = pair.start.len() - text.len();
 4072                            let preceding_text_matches_prefix = prefix_len == 0
 4073                                || (selection.start.column >= (prefix_len as u32)
 4074                                    && snapshot.contains_str_at(
 4075                                        Point::new(
 4076                                            selection.start.row,
 4077                                            selection.start.column - (prefix_len as u32),
 4078                                        ),
 4079                                        &pair.start[..prefix_len],
 4080                                    ));
 4081                            if preceding_text_matches_prefix {
 4082                                bracket_pair = Some(pair.clone());
 4083                                is_bracket_pair_start = true;
 4084                                break;
 4085                            }
 4086                        }
 4087                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4088                        {
 4089                            // take first bracket pair matching end, but don't break in case a later bracket
 4090                            // pair matches start
 4091                            bracket_pair_matching_end = Some(pair.clone());
 4092                        }
 4093                    }
 4094                    if let Some(end) = bracket_pair_matching_end
 4095                        && bracket_pair.is_none()
 4096                    {
 4097                        bracket_pair = Some(end);
 4098                        is_bracket_pair_end = true;
 4099                    }
 4100                }
 4101
 4102                if let Some(bracket_pair) = bracket_pair {
 4103                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4104                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4105                    let auto_surround =
 4106                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4107                    if selection.is_empty() {
 4108                        if is_bracket_pair_start {
 4109                            // If the inserted text is a suffix of an opening bracket and the
 4110                            // selection is preceded by the rest of the opening bracket, then
 4111                            // insert the closing bracket.
 4112                            let following_text_allows_autoclose = snapshot
 4113                                .chars_at(selection.start)
 4114                                .next()
 4115                                .is_none_or(|c| scope.should_autoclose_before(c));
 4116
 4117                            let preceding_text_allows_autoclose = selection.start.column == 0
 4118                                || snapshot
 4119                                    .reversed_chars_at(selection.start)
 4120                                    .next()
 4121                                    .is_none_or(|c| {
 4122                                        bracket_pair.start != bracket_pair.end
 4123                                            || !snapshot
 4124                                                .char_classifier_at(selection.start)
 4125                                                .is_word(c)
 4126                                    });
 4127
 4128                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4129                                && bracket_pair.start.len() == 1
 4130                            {
 4131                                let target = bracket_pair.start.chars().next().unwrap();
 4132                                let current_line_count = snapshot
 4133                                    .reversed_chars_at(selection.start)
 4134                                    .take_while(|&c| c != '\n')
 4135                                    .filter(|&c| c == target)
 4136                                    .count();
 4137                                current_line_count % 2 == 1
 4138                            } else {
 4139                                false
 4140                            };
 4141
 4142                            if autoclose
 4143                                && bracket_pair.close
 4144                                && following_text_allows_autoclose
 4145                                && preceding_text_allows_autoclose
 4146                                && !is_closing_quote
 4147                            {
 4148                                let anchor = snapshot.anchor_before(selection.end);
 4149                                new_selections.push((selection.map(|_| anchor), text.len()));
 4150                                new_autoclose_regions.push((
 4151                                    anchor,
 4152                                    text.len(),
 4153                                    selection.id,
 4154                                    bracket_pair.clone(),
 4155                                ));
 4156                                edits.push((
 4157                                    selection.range(),
 4158                                    format!("{}{}", text, bracket_pair.end).into(),
 4159                                ));
 4160                                bracket_inserted = true;
 4161                                continue;
 4162                            }
 4163                        }
 4164
 4165                        if let Some(region) = autoclose_region {
 4166                            // If the selection is followed by an auto-inserted closing bracket,
 4167                            // then don't insert that closing bracket again; just move the selection
 4168                            // past the closing bracket.
 4169                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4170                                && text.as_ref() == region.pair.end.as_str()
 4171                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4172                            if should_skip {
 4173                                let anchor = snapshot.anchor_after(selection.end);
 4174                                new_selections
 4175                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4176                                continue;
 4177                            }
 4178                        }
 4179
 4180                        let always_treat_brackets_as_autoclosed = snapshot
 4181                            .language_settings_at(selection.start, cx)
 4182                            .always_treat_brackets_as_autoclosed;
 4183                        if always_treat_brackets_as_autoclosed
 4184                            && is_bracket_pair_end
 4185                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4186                        {
 4187                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4188                            // and the inserted text is a closing bracket and the selection is followed
 4189                            // by the closing bracket then move the selection past the closing bracket.
 4190                            let anchor = snapshot.anchor_after(selection.end);
 4191                            new_selections.push((selection.map(|_| anchor), text.len()));
 4192                            continue;
 4193                        }
 4194                    }
 4195                    // If an opening bracket is 1 character long and is typed while
 4196                    // text is selected, then surround that text with the bracket pair.
 4197                    else if auto_surround
 4198                        && bracket_pair.surround
 4199                        && is_bracket_pair_start
 4200                        && bracket_pair.start.chars().count() == 1
 4201                    {
 4202                        edits.push((selection.start..selection.start, text.clone()));
 4203                        edits.push((
 4204                            selection.end..selection.end,
 4205                            bracket_pair.end.as_str().into(),
 4206                        ));
 4207                        bracket_inserted = true;
 4208                        new_selections.push((
 4209                            Selection {
 4210                                id: selection.id,
 4211                                start: snapshot.anchor_after(selection.start),
 4212                                end: snapshot.anchor_before(selection.end),
 4213                                reversed: selection.reversed,
 4214                                goal: selection.goal,
 4215                            },
 4216                            0,
 4217                        ));
 4218                        continue;
 4219                    }
 4220                }
 4221            }
 4222
 4223            if self.auto_replace_emoji_shortcode
 4224                && selection.is_empty()
 4225                && text.as_ref().ends_with(':')
 4226                && let Some(possible_emoji_short_code) =
 4227                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4228                && !possible_emoji_short_code.is_empty()
 4229                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4230            {
 4231                let emoji_shortcode_start = Point::new(
 4232                    selection.start.row,
 4233                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4234                );
 4235
 4236                // Remove shortcode from buffer
 4237                edits.push((
 4238                    emoji_shortcode_start..selection.start,
 4239                    "".to_string().into(),
 4240                ));
 4241                new_selections.push((
 4242                    Selection {
 4243                        id: selection.id,
 4244                        start: snapshot.anchor_after(emoji_shortcode_start),
 4245                        end: snapshot.anchor_before(selection.start),
 4246                        reversed: selection.reversed,
 4247                        goal: selection.goal,
 4248                    },
 4249                    0,
 4250                ));
 4251
 4252                // Insert emoji
 4253                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4254                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4255                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4256
 4257                continue;
 4258            }
 4259
 4260            // If not handling any auto-close operation, then just replace the selected
 4261            // text with the given input and move the selection to the end of the
 4262            // newly inserted text.
 4263            let anchor = snapshot.anchor_after(selection.end);
 4264            if !self.linked_edit_ranges.is_empty() {
 4265                let start_anchor = snapshot.anchor_before(selection.start);
 4266
 4267                let is_word_char = text.chars().next().is_none_or(|char| {
 4268                    let classifier = snapshot
 4269                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4270                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4271                    classifier.is_word(char)
 4272                });
 4273
 4274                if is_word_char {
 4275                    if let Some(ranges) = self
 4276                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4277                    {
 4278                        for (buffer, edits) in ranges {
 4279                            linked_edits
 4280                                .entry(buffer.clone())
 4281                                .or_default()
 4282                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4283                        }
 4284                    }
 4285                } else {
 4286                    clear_linked_edit_ranges = true;
 4287                }
 4288            }
 4289
 4290            new_selections.push((selection.map(|_| anchor), 0));
 4291            edits.push((selection.start..selection.end, text.clone()));
 4292        }
 4293
 4294        drop(snapshot);
 4295
 4296        self.transact(window, cx, |this, window, cx| {
 4297            if clear_linked_edit_ranges {
 4298                this.linked_edit_ranges.clear();
 4299            }
 4300            let initial_buffer_versions =
 4301                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4302
 4303            this.buffer.update(cx, |buffer, cx| {
 4304                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4305            });
 4306            for (buffer, edits) in linked_edits {
 4307                buffer.update(cx, |buffer, cx| {
 4308                    let snapshot = buffer.snapshot();
 4309                    let edits = edits
 4310                        .into_iter()
 4311                        .map(|(range, text)| {
 4312                            use text::ToPoint as TP;
 4313                            let end_point = TP::to_point(&range.end, &snapshot);
 4314                            let start_point = TP::to_point(&range.start, &snapshot);
 4315                            (start_point..end_point, text)
 4316                        })
 4317                        .sorted_by_key(|(range, _)| range.start);
 4318                    buffer.edit(edits, None, cx);
 4319                })
 4320            }
 4321            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4322            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4323            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4324            let new_selections =
 4325                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4326                    .zip(new_selection_deltas)
 4327                    .map(|(selection, delta)| Selection {
 4328                        id: selection.id,
 4329                        start: selection.start + delta,
 4330                        end: selection.end + delta,
 4331                        reversed: selection.reversed,
 4332                        goal: SelectionGoal::None,
 4333                    })
 4334                    .collect::<Vec<_>>();
 4335
 4336            let mut i = 0;
 4337            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4338                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4339                let start = map.buffer_snapshot().anchor_before(position);
 4340                let end = map.buffer_snapshot().anchor_after(position);
 4341                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4342                    match existing_state
 4343                        .range
 4344                        .start
 4345                        .cmp(&start, map.buffer_snapshot())
 4346                    {
 4347                        Ordering::Less => i += 1,
 4348                        Ordering::Greater => break,
 4349                        Ordering::Equal => {
 4350                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4351                                Ordering::Less => i += 1,
 4352                                Ordering::Equal => break,
 4353                                Ordering::Greater => break,
 4354                            }
 4355                        }
 4356                    }
 4357                }
 4358                this.autoclose_regions.insert(
 4359                    i,
 4360                    AutocloseRegion {
 4361                        selection_id,
 4362                        range: start..end,
 4363                        pair,
 4364                    },
 4365                );
 4366            }
 4367
 4368            let had_active_edit_prediction = this.has_active_edit_prediction();
 4369            this.change_selections(
 4370                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4371                window,
 4372                cx,
 4373                |s| s.select(new_selections),
 4374            );
 4375
 4376            if !bracket_inserted
 4377                && let Some(on_type_format_task) =
 4378                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4379            {
 4380                on_type_format_task.detach_and_log_err(cx);
 4381            }
 4382
 4383            let editor_settings = EditorSettings::get_global(cx);
 4384            if bracket_inserted
 4385                && (editor_settings.auto_signature_help
 4386                    || editor_settings.show_signature_help_after_edits)
 4387            {
 4388                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4389            }
 4390
 4391            let trigger_in_words =
 4392                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4393            if this.hard_wrap.is_some() {
 4394                let latest: Range<Point> = this.selections.newest(&map).range();
 4395                if latest.is_empty()
 4396                    && this
 4397                        .buffer()
 4398                        .read(cx)
 4399                        .snapshot(cx)
 4400                        .line_len(MultiBufferRow(latest.start.row))
 4401                        == latest.start.column
 4402                {
 4403                    this.rewrap_impl(
 4404                        RewrapOptions {
 4405                            override_language_settings: true,
 4406                            preserve_existing_whitespace: true,
 4407                        },
 4408                        cx,
 4409                    )
 4410                }
 4411            }
 4412            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4413            refresh_linked_ranges(this, window, cx);
 4414            this.refresh_edit_prediction(true, false, window, cx);
 4415            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4416        });
 4417    }
 4418
 4419    fn find_possible_emoji_shortcode_at_position(
 4420        snapshot: &MultiBufferSnapshot,
 4421        position: Point,
 4422    ) -> Option<String> {
 4423        let mut chars = Vec::new();
 4424        let mut found_colon = false;
 4425        for char in snapshot.reversed_chars_at(position).take(100) {
 4426            // Found a possible emoji shortcode in the middle of the buffer
 4427            if found_colon {
 4428                if char.is_whitespace() {
 4429                    chars.reverse();
 4430                    return Some(chars.iter().collect());
 4431                }
 4432                // If the previous character is not a whitespace, we are in the middle of a word
 4433                // and we only want to complete the shortcode if the word is made up of other emojis
 4434                let mut containing_word = String::new();
 4435                for ch in snapshot
 4436                    .reversed_chars_at(position)
 4437                    .skip(chars.len() + 1)
 4438                    .take(100)
 4439                {
 4440                    if ch.is_whitespace() {
 4441                        break;
 4442                    }
 4443                    containing_word.push(ch);
 4444                }
 4445                let containing_word = containing_word.chars().rev().collect::<String>();
 4446                if util::word_consists_of_emojis(containing_word.as_str()) {
 4447                    chars.reverse();
 4448                    return Some(chars.iter().collect());
 4449                }
 4450            }
 4451
 4452            if char.is_whitespace() || !char.is_ascii() {
 4453                return None;
 4454            }
 4455            if char == ':' {
 4456                found_colon = true;
 4457            } else {
 4458                chars.push(char);
 4459            }
 4460        }
 4461        // Found a possible emoji shortcode at the beginning of the buffer
 4462        chars.reverse();
 4463        Some(chars.iter().collect())
 4464    }
 4465
 4466    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4467        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4468        self.transact(window, cx, |this, window, cx| {
 4469            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4470                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4471                let multi_buffer = this.buffer.read(cx);
 4472                let buffer = multi_buffer.snapshot(cx);
 4473                selections
 4474                    .iter()
 4475                    .map(|selection| {
 4476                        let start_point = selection.start.to_point(&buffer);
 4477                        let mut existing_indent =
 4478                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4479                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4480                        let start = selection.start;
 4481                        let end = selection.end;
 4482                        let selection_is_empty = start == end;
 4483                        let language_scope = buffer.language_scope_at(start);
 4484                        let (
 4485                            comment_delimiter,
 4486                            doc_delimiter,
 4487                            insert_extra_newline,
 4488                            indent_on_newline,
 4489                            indent_on_extra_newline,
 4490                        ) = if let Some(language) = &language_scope {
 4491                            let mut insert_extra_newline =
 4492                                insert_extra_newline_brackets(&buffer, start..end, language)
 4493                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4494
 4495                            // Comment extension on newline is allowed only for cursor selections
 4496                            let comment_delimiter = maybe!({
 4497                                if !selection_is_empty {
 4498                                    return None;
 4499                                }
 4500
 4501                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4502                                    return None;
 4503                                }
 4504
 4505                                let delimiters = language.line_comment_prefixes();
 4506                                let max_len_of_delimiter =
 4507                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4508                                let (snapshot, range) =
 4509                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4510
 4511                                let num_of_whitespaces = snapshot
 4512                                    .chars_for_range(range.clone())
 4513                                    .take_while(|c| c.is_whitespace())
 4514                                    .count();
 4515                                let comment_candidate = snapshot
 4516                                    .chars_for_range(range.clone())
 4517                                    .skip(num_of_whitespaces)
 4518                                    .take(max_len_of_delimiter)
 4519                                    .collect::<String>();
 4520                                let (delimiter, trimmed_len) = delimiters
 4521                                    .iter()
 4522                                    .filter_map(|delimiter| {
 4523                                        let prefix = delimiter.trim_end();
 4524                                        if comment_candidate.starts_with(prefix) {
 4525                                            Some((delimiter, prefix.len()))
 4526                                        } else {
 4527                                            None
 4528                                        }
 4529                                    })
 4530                                    .max_by_key(|(_, len)| *len)?;
 4531
 4532                                if let Some(BlockCommentConfig {
 4533                                    start: block_start, ..
 4534                                }) = language.block_comment()
 4535                                {
 4536                                    let block_start_trimmed = block_start.trim_end();
 4537                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4538                                        let line_content = snapshot
 4539                                            .chars_for_range(range)
 4540                                            .skip(num_of_whitespaces)
 4541                                            .take(block_start_trimmed.len())
 4542                                            .collect::<String>();
 4543
 4544                                        if line_content.starts_with(block_start_trimmed) {
 4545                                            return None;
 4546                                        }
 4547                                    }
 4548                                }
 4549
 4550                                let cursor_is_placed_after_comment_marker =
 4551                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4552                                if cursor_is_placed_after_comment_marker {
 4553                                    Some(delimiter.clone())
 4554                                } else {
 4555                                    None
 4556                                }
 4557                            });
 4558
 4559                            let mut indent_on_newline = IndentSize::spaces(0);
 4560                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4561
 4562                            let doc_delimiter = maybe!({
 4563                                if !selection_is_empty {
 4564                                    return None;
 4565                                }
 4566
 4567                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4568                                    return None;
 4569                                }
 4570
 4571                                let BlockCommentConfig {
 4572                                    start: start_tag,
 4573                                    end: end_tag,
 4574                                    prefix: delimiter,
 4575                                    tab_size: len,
 4576                                } = language.documentation_comment()?;
 4577                                let is_within_block_comment = buffer
 4578                                    .language_scope_at(start_point)
 4579                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4580                                if !is_within_block_comment {
 4581                                    return None;
 4582                                }
 4583
 4584                                let (snapshot, range) =
 4585                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4586
 4587                                let num_of_whitespaces = snapshot
 4588                                    .chars_for_range(range.clone())
 4589                                    .take_while(|c| c.is_whitespace())
 4590                                    .count();
 4591
 4592                                // 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.
 4593                                let column = start_point.column;
 4594                                let cursor_is_after_start_tag = {
 4595                                    let start_tag_len = start_tag.len();
 4596                                    let start_tag_line = snapshot
 4597                                        .chars_for_range(range.clone())
 4598                                        .skip(num_of_whitespaces)
 4599                                        .take(start_tag_len)
 4600                                        .collect::<String>();
 4601                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4602                                        num_of_whitespaces + start_tag_len <= column as usize
 4603                                    } else {
 4604                                        false
 4605                                    }
 4606                                };
 4607
 4608                                let cursor_is_after_delimiter = {
 4609                                    let delimiter_trim = delimiter.trim_end();
 4610                                    let delimiter_line = snapshot
 4611                                        .chars_for_range(range.clone())
 4612                                        .skip(num_of_whitespaces)
 4613                                        .take(delimiter_trim.len())
 4614                                        .collect::<String>();
 4615                                    if delimiter_line.starts_with(delimiter_trim) {
 4616                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4617                                    } else {
 4618                                        false
 4619                                    }
 4620                                };
 4621
 4622                                let cursor_is_before_end_tag_if_exists = {
 4623                                    let mut char_position = 0u32;
 4624                                    let mut end_tag_offset = None;
 4625
 4626                                    'outer: for chunk in snapshot.text_for_range(range) {
 4627                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4628                                            let chars_before_match =
 4629                                                chunk[..byte_pos].chars().count() as u32;
 4630                                            end_tag_offset =
 4631                                                Some(char_position + chars_before_match);
 4632                                            break 'outer;
 4633                                        }
 4634                                        char_position += chunk.chars().count() as u32;
 4635                                    }
 4636
 4637                                    if let Some(end_tag_offset) = end_tag_offset {
 4638                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4639                                        if cursor_is_after_start_tag {
 4640                                            if cursor_is_before_end_tag {
 4641                                                insert_extra_newline = true;
 4642                                            }
 4643                                            let cursor_is_at_start_of_end_tag =
 4644                                                column == end_tag_offset;
 4645                                            if cursor_is_at_start_of_end_tag {
 4646                                                indent_on_extra_newline.len = *len;
 4647                                            }
 4648                                        }
 4649                                        cursor_is_before_end_tag
 4650                                    } else {
 4651                                        true
 4652                                    }
 4653                                };
 4654
 4655                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4656                                    && cursor_is_before_end_tag_if_exists
 4657                                {
 4658                                    if cursor_is_after_start_tag {
 4659                                        indent_on_newline.len = *len;
 4660                                    }
 4661                                    Some(delimiter.clone())
 4662                                } else {
 4663                                    None
 4664                                }
 4665                            });
 4666
 4667                            (
 4668                                comment_delimiter,
 4669                                doc_delimiter,
 4670                                insert_extra_newline,
 4671                                indent_on_newline,
 4672                                indent_on_extra_newline,
 4673                            )
 4674                        } else {
 4675                            (
 4676                                None,
 4677                                None,
 4678                                false,
 4679                                IndentSize::default(),
 4680                                IndentSize::default(),
 4681                            )
 4682                        };
 4683
 4684                        let prevent_auto_indent = doc_delimiter.is_some();
 4685                        let delimiter = comment_delimiter.or(doc_delimiter);
 4686
 4687                        let capacity_for_delimiter =
 4688                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4689                        let mut new_text = String::with_capacity(
 4690                            1 + capacity_for_delimiter
 4691                                + existing_indent.len as usize
 4692                                + indent_on_newline.len as usize
 4693                                + indent_on_extra_newline.len as usize,
 4694                        );
 4695                        new_text.push('\n');
 4696                        new_text.extend(existing_indent.chars());
 4697                        new_text.extend(indent_on_newline.chars());
 4698
 4699                        if let Some(delimiter) = &delimiter {
 4700                            new_text.push_str(delimiter);
 4701                        }
 4702
 4703                        if insert_extra_newline {
 4704                            new_text.push('\n');
 4705                            new_text.extend(existing_indent.chars());
 4706                            new_text.extend(indent_on_extra_newline.chars());
 4707                        }
 4708
 4709                        let anchor = buffer.anchor_after(end);
 4710                        let new_selection = selection.map(|_| anchor);
 4711                        (
 4712                            ((start..end, new_text), prevent_auto_indent),
 4713                            (insert_extra_newline, new_selection),
 4714                        )
 4715                    })
 4716                    .unzip()
 4717            };
 4718
 4719            let mut auto_indent_edits = Vec::new();
 4720            let mut edits = Vec::new();
 4721            for (edit, prevent_auto_indent) in edits_with_flags {
 4722                if prevent_auto_indent {
 4723                    edits.push(edit);
 4724                } else {
 4725                    auto_indent_edits.push(edit);
 4726                }
 4727            }
 4728            if !edits.is_empty() {
 4729                this.edit(edits, cx);
 4730            }
 4731            if !auto_indent_edits.is_empty() {
 4732                this.edit_with_autoindent(auto_indent_edits, cx);
 4733            }
 4734
 4735            let buffer = this.buffer.read(cx).snapshot(cx);
 4736            let new_selections = selection_info
 4737                .into_iter()
 4738                .map(|(extra_newline_inserted, new_selection)| {
 4739                    let mut cursor = new_selection.end.to_point(&buffer);
 4740                    if extra_newline_inserted {
 4741                        cursor.row -= 1;
 4742                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4743                    }
 4744                    new_selection.map(|_| cursor)
 4745                })
 4746                .collect();
 4747
 4748            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4749            this.refresh_edit_prediction(true, false, window, cx);
 4750        });
 4751    }
 4752
 4753    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4754        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4755
 4756        let buffer = self.buffer.read(cx);
 4757        let snapshot = buffer.snapshot(cx);
 4758
 4759        let mut edits = Vec::new();
 4760        let mut rows = Vec::new();
 4761
 4762        for (rows_inserted, selection) in self
 4763            .selections
 4764            .all_adjusted(&self.display_snapshot(cx))
 4765            .into_iter()
 4766            .enumerate()
 4767        {
 4768            let cursor = selection.head();
 4769            let row = cursor.row;
 4770
 4771            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4772
 4773            let newline = "\n".to_string();
 4774            edits.push((start_of_line..start_of_line, newline));
 4775
 4776            rows.push(row + rows_inserted as u32);
 4777        }
 4778
 4779        self.transact(window, cx, |editor, window, cx| {
 4780            editor.edit(edits, cx);
 4781
 4782            editor.change_selections(Default::default(), window, cx, |s| {
 4783                let mut index = 0;
 4784                s.move_cursors_with(|map, _, _| {
 4785                    let row = rows[index];
 4786                    index += 1;
 4787
 4788                    let point = Point::new(row, 0);
 4789                    let boundary = map.next_line_boundary(point).1;
 4790                    let clipped = map.clip_point(boundary, Bias::Left);
 4791
 4792                    (clipped, SelectionGoal::None)
 4793                });
 4794            });
 4795
 4796            let mut indent_edits = Vec::new();
 4797            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4798            for row in rows {
 4799                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4800                for (row, indent) in indents {
 4801                    if indent.len == 0 {
 4802                        continue;
 4803                    }
 4804
 4805                    let text = match indent.kind {
 4806                        IndentKind::Space => " ".repeat(indent.len as usize),
 4807                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4808                    };
 4809                    let point = Point::new(row.0, 0);
 4810                    indent_edits.push((point..point, text));
 4811                }
 4812            }
 4813            editor.edit(indent_edits, cx);
 4814        });
 4815    }
 4816
 4817    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4818        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4819
 4820        let buffer = self.buffer.read(cx);
 4821        let snapshot = buffer.snapshot(cx);
 4822
 4823        let mut edits = Vec::new();
 4824        let mut rows = Vec::new();
 4825        let mut rows_inserted = 0;
 4826
 4827        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4828            let cursor = selection.head();
 4829            let row = cursor.row;
 4830
 4831            let point = Point::new(row + 1, 0);
 4832            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4833
 4834            let newline = "\n".to_string();
 4835            edits.push((start_of_line..start_of_line, newline));
 4836
 4837            rows_inserted += 1;
 4838            rows.push(row + rows_inserted);
 4839        }
 4840
 4841        self.transact(window, cx, |editor, window, cx| {
 4842            editor.edit(edits, cx);
 4843
 4844            editor.change_selections(Default::default(), window, cx, |s| {
 4845                let mut index = 0;
 4846                s.move_cursors_with(|map, _, _| {
 4847                    let row = rows[index];
 4848                    index += 1;
 4849
 4850                    let point = Point::new(row, 0);
 4851                    let boundary = map.next_line_boundary(point).1;
 4852                    let clipped = map.clip_point(boundary, Bias::Left);
 4853
 4854                    (clipped, SelectionGoal::None)
 4855                });
 4856            });
 4857
 4858            let mut indent_edits = Vec::new();
 4859            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4860            for row in rows {
 4861                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4862                for (row, indent) in indents {
 4863                    if indent.len == 0 {
 4864                        continue;
 4865                    }
 4866
 4867                    let text = match indent.kind {
 4868                        IndentKind::Space => " ".repeat(indent.len as usize),
 4869                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4870                    };
 4871                    let point = Point::new(row.0, 0);
 4872                    indent_edits.push((point..point, text));
 4873                }
 4874            }
 4875            editor.edit(indent_edits, cx);
 4876        });
 4877    }
 4878
 4879    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4880        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4881            original_indent_columns: Vec::new(),
 4882        });
 4883        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4884    }
 4885
 4886    fn insert_with_autoindent_mode(
 4887        &mut self,
 4888        text: &str,
 4889        autoindent_mode: Option<AutoindentMode>,
 4890        window: &mut Window,
 4891        cx: &mut Context<Self>,
 4892    ) {
 4893        if self.read_only(cx) {
 4894            return;
 4895        }
 4896
 4897        let text: Arc<str> = text.into();
 4898        self.transact(window, cx, |this, window, cx| {
 4899            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 4900            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4901                let anchors = {
 4902                    let snapshot = buffer.read(cx);
 4903                    old_selections
 4904                        .iter()
 4905                        .map(|s| {
 4906                            let anchor = snapshot.anchor_after(s.head());
 4907                            s.map(|_| anchor)
 4908                        })
 4909                        .collect::<Vec<_>>()
 4910                };
 4911                buffer.edit(
 4912                    old_selections
 4913                        .iter()
 4914                        .map(|s| (s.start..s.end, text.clone())),
 4915                    autoindent_mode,
 4916                    cx,
 4917                );
 4918                anchors
 4919            });
 4920
 4921            this.change_selections(Default::default(), window, cx, |s| {
 4922                s.select_anchors(selection_anchors);
 4923            });
 4924
 4925            cx.notify();
 4926        });
 4927    }
 4928
 4929    fn trigger_completion_on_input(
 4930        &mut self,
 4931        text: &str,
 4932        trigger_in_words: bool,
 4933        window: &mut Window,
 4934        cx: &mut Context<Self>,
 4935    ) {
 4936        let completions_source = self
 4937            .context_menu
 4938            .borrow()
 4939            .as_ref()
 4940            .and_then(|menu| match menu {
 4941                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4942                CodeContextMenu::CodeActions(_) => None,
 4943            });
 4944
 4945        match completions_source {
 4946            Some(CompletionsMenuSource::Words { .. }) => {
 4947                self.open_or_update_completions_menu(
 4948                    Some(CompletionsMenuSource::Words {
 4949                        ignore_threshold: false,
 4950                    }),
 4951                    None,
 4952                    window,
 4953                    cx,
 4954                );
 4955            }
 4956            Some(CompletionsMenuSource::Normal)
 4957            | Some(CompletionsMenuSource::SnippetChoices)
 4958            | None
 4959                if self.is_completion_trigger(
 4960                    text,
 4961                    trigger_in_words,
 4962                    completions_source.is_some(),
 4963                    cx,
 4964                ) =>
 4965            {
 4966                self.show_completions(
 4967                    &ShowCompletions {
 4968                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4969                    },
 4970                    window,
 4971                    cx,
 4972                )
 4973            }
 4974            _ => {
 4975                self.hide_context_menu(window, cx);
 4976            }
 4977        }
 4978    }
 4979
 4980    fn is_completion_trigger(
 4981        &self,
 4982        text: &str,
 4983        trigger_in_words: bool,
 4984        menu_is_open: bool,
 4985        cx: &mut Context<Self>,
 4986    ) -> bool {
 4987        let position = self.selections.newest_anchor().head();
 4988        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4989            return false;
 4990        };
 4991
 4992        if let Some(completion_provider) = &self.completion_provider {
 4993            completion_provider.is_completion_trigger(
 4994                &buffer,
 4995                position.text_anchor,
 4996                text,
 4997                trigger_in_words,
 4998                menu_is_open,
 4999                cx,
 5000            )
 5001        } else {
 5002            false
 5003        }
 5004    }
 5005
 5006    /// If any empty selections is touching the start of its innermost containing autoclose
 5007    /// region, expand it to select the brackets.
 5008    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5009        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5010        let buffer = self.buffer.read(cx).read(cx);
 5011        let new_selections = self
 5012            .selections_with_autoclose_regions(selections, &buffer)
 5013            .map(|(mut selection, region)| {
 5014                if !selection.is_empty() {
 5015                    return selection;
 5016                }
 5017
 5018                if let Some(region) = region {
 5019                    let mut range = region.range.to_offset(&buffer);
 5020                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5021                        range.start -= region.pair.start.len();
 5022                        if buffer.contains_str_at(range.start, ®ion.pair.start)
 5023                            && buffer.contains_str_at(range.end, ®ion.pair.end)
 5024                        {
 5025                            range.end += region.pair.end.len();
 5026                            selection.start = range.start;
 5027                            selection.end = range.end;
 5028
 5029                            return selection;
 5030                        }
 5031                    }
 5032                }
 5033
 5034                let always_treat_brackets_as_autoclosed = buffer
 5035                    .language_settings_at(selection.start, cx)
 5036                    .always_treat_brackets_as_autoclosed;
 5037
 5038                if !always_treat_brackets_as_autoclosed {
 5039                    return selection;
 5040                }
 5041
 5042                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5043                    for (pair, enabled) in scope.brackets() {
 5044                        if !enabled || !pair.close {
 5045                            continue;
 5046                        }
 5047
 5048                        if buffer.contains_str_at(selection.start, &pair.end) {
 5049                            let pair_start_len = pair.start.len();
 5050                            if buffer.contains_str_at(
 5051                                selection.start.saturating_sub(pair_start_len),
 5052                                &pair.start,
 5053                            ) {
 5054                                selection.start -= pair_start_len;
 5055                                selection.end += pair.end.len();
 5056
 5057                                return selection;
 5058                            }
 5059                        }
 5060                    }
 5061                }
 5062
 5063                selection
 5064            })
 5065            .collect();
 5066
 5067        drop(buffer);
 5068        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5069            selections.select(new_selections)
 5070        });
 5071    }
 5072
 5073    /// Iterate the given selections, and for each one, find the smallest surrounding
 5074    /// autoclose region. This uses the ordering of the selections and the autoclose
 5075    /// regions to avoid repeated comparisons.
 5076    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5077        &'a self,
 5078        selections: impl IntoIterator<Item = Selection<D>>,
 5079        buffer: &'a MultiBufferSnapshot,
 5080    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5081        let mut i = 0;
 5082        let mut regions = self.autoclose_regions.as_slice();
 5083        selections.into_iter().map(move |selection| {
 5084            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5085
 5086            let mut enclosing = None;
 5087            while let Some(pair_state) = regions.get(i) {
 5088                if pair_state.range.end.to_offset(buffer) < range.start {
 5089                    regions = ®ions[i + 1..];
 5090                    i = 0;
 5091                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5092                    break;
 5093                } else {
 5094                    if pair_state.selection_id == selection.id {
 5095                        enclosing = Some(pair_state);
 5096                    }
 5097                    i += 1;
 5098                }
 5099            }
 5100
 5101            (selection, enclosing)
 5102        })
 5103    }
 5104
 5105    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5106    fn invalidate_autoclose_regions(
 5107        &mut self,
 5108        mut selections: &[Selection<Anchor>],
 5109        buffer: &MultiBufferSnapshot,
 5110    ) {
 5111        self.autoclose_regions.retain(|state| {
 5112            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5113                return false;
 5114            }
 5115
 5116            let mut i = 0;
 5117            while let Some(selection) = selections.get(i) {
 5118                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5119                    selections = &selections[1..];
 5120                    continue;
 5121                }
 5122                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5123                    break;
 5124                }
 5125                if selection.id == state.selection_id {
 5126                    return true;
 5127                } else {
 5128                    i += 1;
 5129                }
 5130            }
 5131            false
 5132        });
 5133    }
 5134
 5135    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5136        let offset = position.to_offset(buffer);
 5137        let (word_range, kind) =
 5138            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5139        if offset > word_range.start && kind == Some(CharKind::Word) {
 5140            Some(
 5141                buffer
 5142                    .text_for_range(word_range.start..offset)
 5143                    .collect::<String>(),
 5144            )
 5145        } else {
 5146            None
 5147        }
 5148    }
 5149
 5150    pub fn visible_excerpts(
 5151        &self,
 5152        cx: &mut Context<Editor>,
 5153    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5154        let Some(project) = self.project() else {
 5155            return HashMap::default();
 5156        };
 5157        let project = project.read(cx);
 5158        let multi_buffer = self.buffer().read(cx);
 5159        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5160        let multi_buffer_visible_start = self
 5161            .scroll_manager
 5162            .anchor()
 5163            .anchor
 5164            .to_point(&multi_buffer_snapshot);
 5165        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5166            multi_buffer_visible_start
 5167                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5168            Bias::Left,
 5169        );
 5170        multi_buffer_snapshot
 5171            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5172            .into_iter()
 5173            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5174            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5175                let buffer_file = project::File::from_dyn(buffer.file())?;
 5176                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5177                let worktree_entry = buffer_worktree
 5178                    .read(cx)
 5179                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5180                if worktree_entry.is_ignored {
 5181                    None
 5182                } else {
 5183                    Some((
 5184                        excerpt_id,
 5185                        (
 5186                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5187                            buffer.version().clone(),
 5188                            excerpt_visible_range,
 5189                        ),
 5190                    ))
 5191                }
 5192            })
 5193            .collect()
 5194    }
 5195
 5196    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5197        TextLayoutDetails {
 5198            text_system: window.text_system().clone(),
 5199            editor_style: self.style.clone().unwrap(),
 5200            rem_size: window.rem_size(),
 5201            scroll_anchor: self.scroll_manager.anchor(),
 5202            visible_rows: self.visible_line_count(),
 5203            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5204        }
 5205    }
 5206
 5207    fn trigger_on_type_formatting(
 5208        &self,
 5209        input: String,
 5210        window: &mut Window,
 5211        cx: &mut Context<Self>,
 5212    ) -> Option<Task<Result<()>>> {
 5213        if input.len() != 1 {
 5214            return None;
 5215        }
 5216
 5217        let project = self.project()?;
 5218        let position = self.selections.newest_anchor().head();
 5219        let (buffer, buffer_position) = self
 5220            .buffer
 5221            .read(cx)
 5222            .text_anchor_for_position(position, cx)?;
 5223
 5224        let settings = language_settings::language_settings(
 5225            buffer
 5226                .read(cx)
 5227                .language_at(buffer_position)
 5228                .map(|l| l.name()),
 5229            buffer.read(cx).file(),
 5230            cx,
 5231        );
 5232        if !settings.use_on_type_format {
 5233            return None;
 5234        }
 5235
 5236        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5237        // hence we do LSP request & edit on host side only — add formats to host's history.
 5238        let push_to_lsp_host_history = true;
 5239        // If this is not the host, append its history with new edits.
 5240        let push_to_client_history = project.read(cx).is_via_collab();
 5241
 5242        let on_type_formatting = project.update(cx, |project, cx| {
 5243            project.on_type_format(
 5244                buffer.clone(),
 5245                buffer_position,
 5246                input,
 5247                push_to_lsp_host_history,
 5248                cx,
 5249            )
 5250        });
 5251        Some(cx.spawn_in(window, async move |editor, cx| {
 5252            if let Some(transaction) = on_type_formatting.await? {
 5253                if push_to_client_history {
 5254                    buffer
 5255                        .update(cx, |buffer, _| {
 5256                            buffer.push_transaction(transaction, Instant::now());
 5257                            buffer.finalize_last_transaction();
 5258                        })
 5259                        .ok();
 5260                }
 5261                editor.update(cx, |editor, cx| {
 5262                    editor.refresh_document_highlights(cx);
 5263                })?;
 5264            }
 5265            Ok(())
 5266        }))
 5267    }
 5268
 5269    pub fn show_word_completions(
 5270        &mut self,
 5271        _: &ShowWordCompletions,
 5272        window: &mut Window,
 5273        cx: &mut Context<Self>,
 5274    ) {
 5275        self.open_or_update_completions_menu(
 5276            Some(CompletionsMenuSource::Words {
 5277                ignore_threshold: true,
 5278            }),
 5279            None,
 5280            window,
 5281            cx,
 5282        );
 5283    }
 5284
 5285    pub fn show_completions(
 5286        &mut self,
 5287        options: &ShowCompletions,
 5288        window: &mut Window,
 5289        cx: &mut Context<Self>,
 5290    ) {
 5291        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5292    }
 5293
 5294    fn open_or_update_completions_menu(
 5295        &mut self,
 5296        requested_source: Option<CompletionsMenuSource>,
 5297        trigger: Option<&str>,
 5298        window: &mut Window,
 5299        cx: &mut Context<Self>,
 5300    ) {
 5301        if self.pending_rename.is_some() {
 5302            return;
 5303        }
 5304
 5305        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5306
 5307        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5308        // inserted and selected. To handle that case, the start of the selection is used so that
 5309        // the menu starts with all choices.
 5310        let position = self
 5311            .selections
 5312            .newest_anchor()
 5313            .start
 5314            .bias_right(&multibuffer_snapshot);
 5315        if position.diff_base_anchor.is_some() {
 5316            return;
 5317        }
 5318        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5319        let Some(buffer) = buffer_position
 5320            .buffer_id
 5321            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5322        else {
 5323            return;
 5324        };
 5325        let buffer_snapshot = buffer.read(cx).snapshot();
 5326
 5327        let query: Option<Arc<String>> =
 5328            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5329                .map(|query| query.into());
 5330
 5331        drop(multibuffer_snapshot);
 5332
 5333        // Hide the current completions menu when query is empty. Without this, cached
 5334        // completions from before the trigger char may be reused (#32774).
 5335        if query.is_none() {
 5336            let menu_is_open = matches!(
 5337                self.context_menu.borrow().as_ref(),
 5338                Some(CodeContextMenu::Completions(_))
 5339            );
 5340            if menu_is_open {
 5341                self.hide_context_menu(window, cx);
 5342            }
 5343        }
 5344
 5345        let mut ignore_word_threshold = false;
 5346        let provider = match requested_source {
 5347            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5348            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5349                ignore_word_threshold = ignore_threshold;
 5350                None
 5351            }
 5352            Some(CompletionsMenuSource::SnippetChoices) => {
 5353                log::error!("bug: SnippetChoices requested_source is not handled");
 5354                None
 5355            }
 5356        };
 5357
 5358        let sort_completions = provider
 5359            .as_ref()
 5360            .is_some_and(|provider| provider.sort_completions());
 5361
 5362        let filter_completions = provider
 5363            .as_ref()
 5364            .is_none_or(|provider| provider.filter_completions());
 5365
 5366        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5367            if filter_completions {
 5368                menu.filter(query.clone(), provider.clone(), window, cx);
 5369            }
 5370            // When `is_incomplete` is false, no need to re-query completions when the current query
 5371            // is a suffix of the initial query.
 5372            if !menu.is_incomplete {
 5373                // If the new query is a suffix of the old query (typing more characters) and
 5374                // the previous result was complete, the existing completions can be filtered.
 5375                //
 5376                // Note that this is always true for snippet completions.
 5377                let query_matches = match (&menu.initial_query, &query) {
 5378                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5379                    (None, _) => true,
 5380                    _ => false,
 5381                };
 5382                if query_matches {
 5383                    let position_matches = if menu.initial_position == position {
 5384                        true
 5385                    } else {
 5386                        let snapshot = self.buffer.read(cx).read(cx);
 5387                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5388                    };
 5389                    if position_matches {
 5390                        return;
 5391                    }
 5392                }
 5393            }
 5394        };
 5395
 5396        let trigger_kind = match trigger {
 5397            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5398                CompletionTriggerKind::TRIGGER_CHARACTER
 5399            }
 5400            _ => CompletionTriggerKind::INVOKED,
 5401        };
 5402        let completion_context = CompletionContext {
 5403            trigger_character: trigger.and_then(|trigger| {
 5404                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5405                    Some(String::from(trigger))
 5406                } else {
 5407                    None
 5408                }
 5409            }),
 5410            trigger_kind,
 5411        };
 5412
 5413        let Anchor {
 5414            excerpt_id: buffer_excerpt_id,
 5415            text_anchor: buffer_position,
 5416            ..
 5417        } = buffer_position;
 5418
 5419        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5420            buffer_snapshot.surrounding_word(buffer_position, None)
 5421        {
 5422            let word_to_exclude = buffer_snapshot
 5423                .text_for_range(word_range.clone())
 5424                .collect::<String>();
 5425            (
 5426                buffer_snapshot.anchor_before(word_range.start)
 5427                    ..buffer_snapshot.anchor_after(buffer_position),
 5428                Some(word_to_exclude),
 5429            )
 5430        } else {
 5431            (buffer_position..buffer_position, None)
 5432        };
 5433
 5434        let language = buffer_snapshot
 5435            .language_at(buffer_position)
 5436            .map(|language| language.name());
 5437
 5438        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5439            .completions
 5440            .clone();
 5441
 5442        let show_completion_documentation = buffer_snapshot
 5443            .settings_at(buffer_position, cx)
 5444            .show_completion_documentation;
 5445
 5446        // The document can be large, so stay in reasonable bounds when searching for words,
 5447        // otherwise completion pop-up might be slow to appear.
 5448        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5449        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5450        let min_word_search = buffer_snapshot.clip_point(
 5451            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5452            Bias::Left,
 5453        );
 5454        let max_word_search = buffer_snapshot.clip_point(
 5455            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5456            Bias::Right,
 5457        );
 5458        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5459            ..buffer_snapshot.point_to_offset(max_word_search);
 5460
 5461        let skip_digits = query
 5462            .as_ref()
 5463            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5464
 5465        let omit_word_completions = !self.word_completions_enabled
 5466            || (!ignore_word_threshold
 5467                && match &query {
 5468                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5469                    None => completion_settings.words_min_length != 0,
 5470                });
 5471
 5472        let (mut words, provider_responses) = match &provider {
 5473            Some(provider) => {
 5474                let provider_responses = provider.completions(
 5475                    buffer_excerpt_id,
 5476                    &buffer,
 5477                    buffer_position,
 5478                    completion_context,
 5479                    window,
 5480                    cx,
 5481                );
 5482
 5483                let words = match (omit_word_completions, completion_settings.words) {
 5484                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5485                        Task::ready(BTreeMap::default())
 5486                    }
 5487                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5488                        .background_spawn(async move {
 5489                            buffer_snapshot.words_in_range(WordsQuery {
 5490                                fuzzy_contents: None,
 5491                                range: word_search_range,
 5492                                skip_digits,
 5493                            })
 5494                        }),
 5495                };
 5496
 5497                (words, provider_responses)
 5498            }
 5499            None => {
 5500                let words = if omit_word_completions {
 5501                    Task::ready(BTreeMap::default())
 5502                } else {
 5503                    cx.background_spawn(async move {
 5504                        buffer_snapshot.words_in_range(WordsQuery {
 5505                            fuzzy_contents: None,
 5506                            range: word_search_range,
 5507                            skip_digits,
 5508                        })
 5509                    })
 5510                };
 5511                (words, Task::ready(Ok(Vec::new())))
 5512            }
 5513        };
 5514
 5515        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5516
 5517        let id = post_inc(&mut self.next_completion_id);
 5518        let task = cx.spawn_in(window, async move |editor, cx| {
 5519            let Ok(()) = editor.update(cx, |this, _| {
 5520                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5521            }) else {
 5522                return;
 5523            };
 5524
 5525            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5526            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5527            let mut completions = Vec::new();
 5528            let mut is_incomplete = false;
 5529            let mut display_options: Option<CompletionDisplayOptions> = None;
 5530            if let Some(provider_responses) = provider_responses.await.log_err()
 5531                && !provider_responses.is_empty()
 5532            {
 5533                for response in provider_responses {
 5534                    completions.extend(response.completions);
 5535                    is_incomplete = is_incomplete || response.is_incomplete;
 5536                    match display_options.as_mut() {
 5537                        None => {
 5538                            display_options = Some(response.display_options);
 5539                        }
 5540                        Some(options) => options.merge(&response.display_options),
 5541                    }
 5542                }
 5543                if completion_settings.words == WordsCompletionMode::Fallback {
 5544                    words = Task::ready(BTreeMap::default());
 5545                }
 5546            }
 5547            let display_options = display_options.unwrap_or_default();
 5548
 5549            let mut words = words.await;
 5550            if let Some(word_to_exclude) = &word_to_exclude {
 5551                words.remove(word_to_exclude);
 5552            }
 5553            for lsp_completion in &completions {
 5554                words.remove(&lsp_completion.new_text);
 5555            }
 5556            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5557                replace_range: word_replace_range.clone(),
 5558                new_text: word.clone(),
 5559                label: CodeLabel::plain(word, None),
 5560                icon_path: None,
 5561                documentation: None,
 5562                source: CompletionSource::BufferWord {
 5563                    word_range,
 5564                    resolved: false,
 5565                },
 5566                insert_text_mode: Some(InsertTextMode::AS_IS),
 5567                confirm: None,
 5568            }));
 5569
 5570            let menu = if completions.is_empty() {
 5571                None
 5572            } else {
 5573                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5574                    let languages = editor
 5575                        .workspace
 5576                        .as_ref()
 5577                        .and_then(|(workspace, _)| workspace.upgrade())
 5578                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5579                    let menu = CompletionsMenu::new(
 5580                        id,
 5581                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5582                        sort_completions,
 5583                        show_completion_documentation,
 5584                        position,
 5585                        query.clone(),
 5586                        is_incomplete,
 5587                        buffer.clone(),
 5588                        completions.into(),
 5589                        display_options,
 5590                        snippet_sort_order,
 5591                        languages,
 5592                        language,
 5593                        cx,
 5594                    );
 5595
 5596                    let query = if filter_completions { query } else { None };
 5597                    let matches_task = if let Some(query) = query {
 5598                        menu.do_async_filtering(query, cx)
 5599                    } else {
 5600                        Task::ready(menu.unfiltered_matches())
 5601                    };
 5602                    (menu, matches_task)
 5603                }) else {
 5604                    return;
 5605                };
 5606
 5607                let matches = matches_task.await;
 5608
 5609                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5610                    // Newer menu already set, so exit.
 5611                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5612                        editor.context_menu.borrow().as_ref()
 5613                        && prev_menu.id > id
 5614                    {
 5615                        return;
 5616                    };
 5617
 5618                    // Only valid to take prev_menu because it the new menu is immediately set
 5619                    // below, or the menu is hidden.
 5620                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5621                        editor.context_menu.borrow_mut().take()
 5622                    {
 5623                        let position_matches =
 5624                            if prev_menu.initial_position == menu.initial_position {
 5625                                true
 5626                            } else {
 5627                                let snapshot = editor.buffer.read(cx).read(cx);
 5628                                prev_menu.initial_position.to_offset(&snapshot)
 5629                                    == menu.initial_position.to_offset(&snapshot)
 5630                            };
 5631                        if position_matches {
 5632                            // Preserve markdown cache before `set_filter_results` because it will
 5633                            // try to populate the documentation cache.
 5634                            menu.preserve_markdown_cache(prev_menu);
 5635                        }
 5636                    };
 5637
 5638                    menu.set_filter_results(matches, provider, window, cx);
 5639                }) else {
 5640                    return;
 5641                };
 5642
 5643                menu.visible().then_some(menu)
 5644            };
 5645
 5646            editor
 5647                .update_in(cx, |editor, window, cx| {
 5648                    if editor.focus_handle.is_focused(window)
 5649                        && let Some(menu) = menu
 5650                    {
 5651                        *editor.context_menu.borrow_mut() =
 5652                            Some(CodeContextMenu::Completions(menu));
 5653
 5654                        crate::hover_popover::hide_hover(editor, cx);
 5655                        if editor.show_edit_predictions_in_menu() {
 5656                            editor.update_visible_edit_prediction(window, cx);
 5657                        } else {
 5658                            editor.discard_edit_prediction(false, cx);
 5659                        }
 5660
 5661                        cx.notify();
 5662                        return;
 5663                    }
 5664
 5665                    if editor.completion_tasks.len() <= 1 {
 5666                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5667                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5668                        // If it was already hidden and we don't show edit predictions in the menu,
 5669                        // we should also show the edit prediction when available.
 5670                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5671                            editor.update_visible_edit_prediction(window, cx);
 5672                        }
 5673                    }
 5674                })
 5675                .ok();
 5676        });
 5677
 5678        self.completion_tasks.push((id, task));
 5679    }
 5680
 5681    #[cfg(feature = "test-support")]
 5682    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5683        let menu = self.context_menu.borrow();
 5684        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5685            let completions = menu.completions.borrow();
 5686            Some(completions.to_vec())
 5687        } else {
 5688            None
 5689        }
 5690    }
 5691
 5692    pub fn with_completions_menu_matching_id<R>(
 5693        &self,
 5694        id: CompletionId,
 5695        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5696    ) -> R {
 5697        let mut context_menu = self.context_menu.borrow_mut();
 5698        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5699            return f(None);
 5700        };
 5701        if completions_menu.id != id {
 5702            return f(None);
 5703        }
 5704        f(Some(completions_menu))
 5705    }
 5706
 5707    pub fn confirm_completion(
 5708        &mut self,
 5709        action: &ConfirmCompletion,
 5710        window: &mut Window,
 5711        cx: &mut Context<Self>,
 5712    ) -> Option<Task<Result<()>>> {
 5713        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5714        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5715    }
 5716
 5717    pub fn confirm_completion_insert(
 5718        &mut self,
 5719        _: &ConfirmCompletionInsert,
 5720        window: &mut Window,
 5721        cx: &mut Context<Self>,
 5722    ) -> Option<Task<Result<()>>> {
 5723        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5724        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5725    }
 5726
 5727    pub fn confirm_completion_replace(
 5728        &mut self,
 5729        _: &ConfirmCompletionReplace,
 5730        window: &mut Window,
 5731        cx: &mut Context<Self>,
 5732    ) -> Option<Task<Result<()>>> {
 5733        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5734        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5735    }
 5736
 5737    pub fn compose_completion(
 5738        &mut self,
 5739        action: &ComposeCompletion,
 5740        window: &mut Window,
 5741        cx: &mut Context<Self>,
 5742    ) -> Option<Task<Result<()>>> {
 5743        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5744        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5745    }
 5746
 5747    fn do_completion(
 5748        &mut self,
 5749        item_ix: Option<usize>,
 5750        intent: CompletionIntent,
 5751        window: &mut Window,
 5752        cx: &mut Context<Editor>,
 5753    ) -> Option<Task<Result<()>>> {
 5754        use language::ToOffset as _;
 5755
 5756        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5757        else {
 5758            return None;
 5759        };
 5760
 5761        let candidate_id = {
 5762            let entries = completions_menu.entries.borrow();
 5763            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5764            if self.show_edit_predictions_in_menu() {
 5765                self.discard_edit_prediction(true, cx);
 5766            }
 5767            mat.candidate_id
 5768        };
 5769
 5770        let completion = completions_menu
 5771            .completions
 5772            .borrow()
 5773            .get(candidate_id)?
 5774            .clone();
 5775        cx.stop_propagation();
 5776
 5777        let buffer_handle = completions_menu.buffer.clone();
 5778
 5779        let CompletionEdit {
 5780            new_text,
 5781            snippet,
 5782            replace_range,
 5783        } = process_completion_for_edit(
 5784            &completion,
 5785            intent,
 5786            &buffer_handle,
 5787            &completions_menu.initial_position.text_anchor,
 5788            cx,
 5789        );
 5790
 5791        let buffer = buffer_handle.read(cx);
 5792        let snapshot = self.buffer.read(cx).snapshot(cx);
 5793        let newest_anchor = self.selections.newest_anchor();
 5794        let replace_range_multibuffer = {
 5795            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5796            excerpt.map_range_from_buffer(replace_range.clone())
 5797        };
 5798        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5799            return None;
 5800        }
 5801
 5802        let old_text = buffer
 5803            .text_for_range(replace_range.clone())
 5804            .collect::<String>();
 5805        let lookbehind = newest_anchor
 5806            .start
 5807            .text_anchor
 5808            .to_offset(buffer)
 5809            .saturating_sub(replace_range.start);
 5810        let lookahead = replace_range
 5811            .end
 5812            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5813        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5814        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5815
 5816        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5817        let mut ranges = Vec::new();
 5818        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5819
 5820        for selection in &selections {
 5821            let range = if selection.id == newest_anchor.id {
 5822                replace_range_multibuffer.clone()
 5823            } else {
 5824                let mut range = selection.range();
 5825
 5826                // if prefix is present, don't duplicate it
 5827                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5828                    range.start = range.start.saturating_sub(lookbehind);
 5829
 5830                    // if suffix is also present, mimic the newest cursor and replace it
 5831                    if selection.id != newest_anchor.id
 5832                        && snapshot.contains_str_at(range.end, suffix)
 5833                    {
 5834                        range.end += lookahead;
 5835                    }
 5836                }
 5837                range
 5838            };
 5839
 5840            ranges.push(range.clone());
 5841
 5842            if !self.linked_edit_ranges.is_empty() {
 5843                let start_anchor = snapshot.anchor_before(range.start);
 5844                let end_anchor = snapshot.anchor_after(range.end);
 5845                if let Some(ranges) = self
 5846                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5847                {
 5848                    for (buffer, edits) in ranges {
 5849                        linked_edits
 5850                            .entry(buffer.clone())
 5851                            .or_default()
 5852                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5853                    }
 5854                }
 5855            }
 5856        }
 5857
 5858        let common_prefix_len = old_text
 5859            .chars()
 5860            .zip(new_text.chars())
 5861            .take_while(|(a, b)| a == b)
 5862            .map(|(a, _)| a.len_utf8())
 5863            .sum::<usize>();
 5864
 5865        cx.emit(EditorEvent::InputHandled {
 5866            utf16_range_to_replace: None,
 5867            text: new_text[common_prefix_len..].into(),
 5868        });
 5869
 5870        self.transact(window, cx, |editor, window, cx| {
 5871            if let Some(mut snippet) = snippet {
 5872                snippet.text = new_text.to_string();
 5873                editor
 5874                    .insert_snippet(&ranges, snippet, window, cx)
 5875                    .log_err();
 5876            } else {
 5877                editor.buffer.update(cx, |multi_buffer, cx| {
 5878                    let auto_indent = match completion.insert_text_mode {
 5879                        Some(InsertTextMode::AS_IS) => None,
 5880                        _ => editor.autoindent_mode.clone(),
 5881                    };
 5882                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5883                    multi_buffer.edit(edits, auto_indent, cx);
 5884                });
 5885            }
 5886            for (buffer, edits) in linked_edits {
 5887                buffer.update(cx, |buffer, cx| {
 5888                    let snapshot = buffer.snapshot();
 5889                    let edits = edits
 5890                        .into_iter()
 5891                        .map(|(range, text)| {
 5892                            use text::ToPoint as TP;
 5893                            let end_point = TP::to_point(&range.end, &snapshot);
 5894                            let start_point = TP::to_point(&range.start, &snapshot);
 5895                            (start_point..end_point, text)
 5896                        })
 5897                        .sorted_by_key(|(range, _)| range.start);
 5898                    buffer.edit(edits, None, cx);
 5899                })
 5900            }
 5901
 5902            editor.refresh_edit_prediction(true, false, window, cx);
 5903        });
 5904        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 5905
 5906        let show_new_completions_on_confirm = completion
 5907            .confirm
 5908            .as_ref()
 5909            .is_some_and(|confirm| confirm(intent, window, cx));
 5910        if show_new_completions_on_confirm {
 5911            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5912        }
 5913
 5914        let provider = self.completion_provider.as_ref()?;
 5915        drop(completion);
 5916        let apply_edits = provider.apply_additional_edits_for_completion(
 5917            buffer_handle,
 5918            completions_menu.completions.clone(),
 5919            candidate_id,
 5920            true,
 5921            cx,
 5922        );
 5923
 5924        let editor_settings = EditorSettings::get_global(cx);
 5925        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5926            // After the code completion is finished, users often want to know what signatures are needed.
 5927            // so we should automatically call signature_help
 5928            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5929        }
 5930
 5931        Some(cx.foreground_executor().spawn(async move {
 5932            apply_edits.await?;
 5933            Ok(())
 5934        }))
 5935    }
 5936
 5937    pub fn toggle_code_actions(
 5938        &mut self,
 5939        action: &ToggleCodeActions,
 5940        window: &mut Window,
 5941        cx: &mut Context<Self>,
 5942    ) {
 5943        let quick_launch = action.quick_launch;
 5944        let mut context_menu = self.context_menu.borrow_mut();
 5945        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5946            if code_actions.deployed_from == action.deployed_from {
 5947                // Toggle if we're selecting the same one
 5948                *context_menu = None;
 5949                cx.notify();
 5950                return;
 5951            } else {
 5952                // Otherwise, clear it and start a new one
 5953                *context_menu = None;
 5954                cx.notify();
 5955            }
 5956        }
 5957        drop(context_menu);
 5958        let snapshot = self.snapshot(window, cx);
 5959        let deployed_from = action.deployed_from.clone();
 5960        let action = action.clone();
 5961        self.completion_tasks.clear();
 5962        self.discard_edit_prediction(false, cx);
 5963
 5964        let multibuffer_point = match &action.deployed_from {
 5965            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5966                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5967            }
 5968            _ => self
 5969                .selections
 5970                .newest::<Point>(&snapshot.display_snapshot)
 5971                .head(),
 5972        };
 5973        let Some((buffer, buffer_row)) = snapshot
 5974            .buffer_snapshot()
 5975            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5976            .and_then(|(buffer_snapshot, range)| {
 5977                self.buffer()
 5978                    .read(cx)
 5979                    .buffer(buffer_snapshot.remote_id())
 5980                    .map(|buffer| (buffer, range.start.row))
 5981            })
 5982        else {
 5983            return;
 5984        };
 5985        let buffer_id = buffer.read(cx).remote_id();
 5986        let tasks = self
 5987            .tasks
 5988            .get(&(buffer_id, buffer_row))
 5989            .map(|t| Arc::new(t.to_owned()));
 5990
 5991        if !self.focus_handle.is_focused(window) {
 5992            return;
 5993        }
 5994        let project = self.project.clone();
 5995
 5996        let code_actions_task = match deployed_from {
 5997            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5998            _ => self.code_actions(buffer_row, window, cx),
 5999        };
 6000
 6001        let runnable_task = match deployed_from {
 6002            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6003            _ => {
 6004                let mut task_context_task = Task::ready(None);
 6005                if let Some(tasks) = &tasks
 6006                    && let Some(project) = project
 6007                {
 6008                    task_context_task =
 6009                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6010                }
 6011
 6012                cx.spawn_in(window, {
 6013                    let buffer = buffer.clone();
 6014                    async move |editor, cx| {
 6015                        let task_context = task_context_task.await;
 6016
 6017                        let resolved_tasks =
 6018                            tasks
 6019                                .zip(task_context.clone())
 6020                                .map(|(tasks, task_context)| ResolvedTasks {
 6021                                    templates: tasks.resolve(&task_context).collect(),
 6022                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6023                                        multibuffer_point.row,
 6024                                        tasks.column,
 6025                                    )),
 6026                                });
 6027                        let debug_scenarios = editor
 6028                            .update(cx, |editor, cx| {
 6029                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6030                            })?
 6031                            .await;
 6032                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6033                    }
 6034                })
 6035            }
 6036        };
 6037
 6038        cx.spawn_in(window, async move |editor, cx| {
 6039            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6040            let code_actions = code_actions_task.await;
 6041            let spawn_straight_away = quick_launch
 6042                && resolved_tasks
 6043                    .as_ref()
 6044                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6045                && code_actions
 6046                    .as_ref()
 6047                    .is_none_or(|actions| actions.is_empty())
 6048                && debug_scenarios.is_empty();
 6049
 6050            editor.update_in(cx, |editor, window, cx| {
 6051                crate::hover_popover::hide_hover(editor, cx);
 6052                let actions = CodeActionContents::new(
 6053                    resolved_tasks,
 6054                    code_actions,
 6055                    debug_scenarios,
 6056                    task_context.unwrap_or_default(),
 6057                );
 6058
 6059                // Don't show the menu if there are no actions available
 6060                if actions.is_empty() {
 6061                    cx.notify();
 6062                    return Task::ready(Ok(()));
 6063                }
 6064
 6065                *editor.context_menu.borrow_mut() =
 6066                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6067                        buffer,
 6068                        actions,
 6069                        selected_item: Default::default(),
 6070                        scroll_handle: UniformListScrollHandle::default(),
 6071                        deployed_from,
 6072                    }));
 6073                cx.notify();
 6074                if spawn_straight_away
 6075                    && let Some(task) = editor.confirm_code_action(
 6076                        &ConfirmCodeAction { item_ix: Some(0) },
 6077                        window,
 6078                        cx,
 6079                    )
 6080                {
 6081                    return task;
 6082                }
 6083
 6084                Task::ready(Ok(()))
 6085            })
 6086        })
 6087        .detach_and_log_err(cx);
 6088    }
 6089
 6090    fn debug_scenarios(
 6091        &mut self,
 6092        resolved_tasks: &Option<ResolvedTasks>,
 6093        buffer: &Entity<Buffer>,
 6094        cx: &mut App,
 6095    ) -> Task<Vec<task::DebugScenario>> {
 6096        maybe!({
 6097            let project = self.project()?;
 6098            let dap_store = project.read(cx).dap_store();
 6099            let mut scenarios = vec![];
 6100            let resolved_tasks = resolved_tasks.as_ref()?;
 6101            let buffer = buffer.read(cx);
 6102            let language = buffer.language()?;
 6103            let file = buffer.file();
 6104            let debug_adapter = language_settings(language.name().into(), file, cx)
 6105                .debuggers
 6106                .first()
 6107                .map(SharedString::from)
 6108                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6109
 6110            dap_store.update(cx, |dap_store, cx| {
 6111                for (_, task) in &resolved_tasks.templates {
 6112                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6113                        task.original_task().clone(),
 6114                        debug_adapter.clone().into(),
 6115                        task.display_label().to_owned().into(),
 6116                        cx,
 6117                    );
 6118                    scenarios.push(maybe_scenario);
 6119                }
 6120            });
 6121            Some(cx.background_spawn(async move {
 6122                futures::future::join_all(scenarios)
 6123                    .await
 6124                    .into_iter()
 6125                    .flatten()
 6126                    .collect::<Vec<_>>()
 6127            }))
 6128        })
 6129        .unwrap_or_else(|| Task::ready(vec![]))
 6130    }
 6131
 6132    fn code_actions(
 6133        &mut self,
 6134        buffer_row: u32,
 6135        window: &mut Window,
 6136        cx: &mut Context<Self>,
 6137    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6138        let mut task = self.code_actions_task.take();
 6139        cx.spawn_in(window, async move |editor, cx| {
 6140            while let Some(prev_task) = task {
 6141                prev_task.await.log_err();
 6142                task = editor
 6143                    .update(cx, |this, _| this.code_actions_task.take())
 6144                    .ok()?;
 6145            }
 6146
 6147            editor
 6148                .update(cx, |editor, cx| {
 6149                    editor
 6150                        .available_code_actions
 6151                        .clone()
 6152                        .and_then(|(location, code_actions)| {
 6153                            let snapshot = location.buffer.read(cx).snapshot();
 6154                            let point_range = location.range.to_point(&snapshot);
 6155                            let point_range = point_range.start.row..=point_range.end.row;
 6156                            if point_range.contains(&buffer_row) {
 6157                                Some(code_actions)
 6158                            } else {
 6159                                None
 6160                            }
 6161                        })
 6162                })
 6163                .ok()
 6164                .flatten()
 6165        })
 6166    }
 6167
 6168    pub fn confirm_code_action(
 6169        &mut self,
 6170        action: &ConfirmCodeAction,
 6171        window: &mut Window,
 6172        cx: &mut Context<Self>,
 6173    ) -> Option<Task<Result<()>>> {
 6174        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6175
 6176        let actions_menu =
 6177            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6178                menu
 6179            } else {
 6180                return None;
 6181            };
 6182
 6183        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6184        let action = actions_menu.actions.get(action_ix)?;
 6185        let title = action.label();
 6186        let buffer = actions_menu.buffer;
 6187        let workspace = self.workspace()?;
 6188
 6189        match action {
 6190            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6191                workspace.update(cx, |workspace, cx| {
 6192                    workspace.schedule_resolved_task(
 6193                        task_source_kind,
 6194                        resolved_task,
 6195                        false,
 6196                        window,
 6197                        cx,
 6198                    );
 6199
 6200                    Some(Task::ready(Ok(())))
 6201                })
 6202            }
 6203            CodeActionsItem::CodeAction {
 6204                excerpt_id,
 6205                action,
 6206                provider,
 6207            } => {
 6208                let apply_code_action =
 6209                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6210                let workspace = workspace.downgrade();
 6211                Some(cx.spawn_in(window, async move |editor, cx| {
 6212                    let project_transaction = apply_code_action.await?;
 6213                    Self::open_project_transaction(
 6214                        &editor,
 6215                        workspace,
 6216                        project_transaction,
 6217                        title,
 6218                        cx,
 6219                    )
 6220                    .await
 6221                }))
 6222            }
 6223            CodeActionsItem::DebugScenario(scenario) => {
 6224                let context = actions_menu.actions.context;
 6225
 6226                workspace.update(cx, |workspace, cx| {
 6227                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6228                    workspace.start_debug_session(
 6229                        scenario,
 6230                        context,
 6231                        Some(buffer),
 6232                        None,
 6233                        window,
 6234                        cx,
 6235                    );
 6236                });
 6237                Some(Task::ready(Ok(())))
 6238            }
 6239        }
 6240    }
 6241
 6242    pub async fn open_project_transaction(
 6243        editor: &WeakEntity<Editor>,
 6244        workspace: WeakEntity<Workspace>,
 6245        transaction: ProjectTransaction,
 6246        title: String,
 6247        cx: &mut AsyncWindowContext,
 6248    ) -> Result<()> {
 6249        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6250        cx.update(|_, cx| {
 6251            entries.sort_unstable_by_key(|(buffer, _)| {
 6252                buffer.read(cx).file().map(|f| f.path().clone())
 6253            });
 6254        })?;
 6255        if entries.is_empty() {
 6256            return Ok(());
 6257        }
 6258
 6259        // If the project transaction's edits are all contained within this editor, then
 6260        // avoid opening a new editor to display them.
 6261
 6262        if let [(buffer, transaction)] = &*entries {
 6263            let excerpt = editor.update(cx, |editor, cx| {
 6264                editor
 6265                    .buffer()
 6266                    .read(cx)
 6267                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6268            })?;
 6269            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6270                && excerpted_buffer == *buffer
 6271            {
 6272                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6273                    let excerpt_range = excerpt_range.to_offset(buffer);
 6274                    buffer
 6275                        .edited_ranges_for_transaction::<usize>(transaction)
 6276                        .all(|range| {
 6277                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6278                        })
 6279                })?;
 6280
 6281                if all_edits_within_excerpt {
 6282                    return Ok(());
 6283                }
 6284            }
 6285        }
 6286
 6287        let mut ranges_to_highlight = Vec::new();
 6288        let excerpt_buffer = cx.new(|cx| {
 6289            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6290            for (buffer_handle, transaction) in &entries {
 6291                let edited_ranges = buffer_handle
 6292                    .read(cx)
 6293                    .edited_ranges_for_transaction::<Point>(transaction)
 6294                    .collect::<Vec<_>>();
 6295                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6296                    PathKey::for_buffer(buffer_handle, cx),
 6297                    buffer_handle.clone(),
 6298                    edited_ranges,
 6299                    multibuffer_context_lines(cx),
 6300                    cx,
 6301                );
 6302
 6303                ranges_to_highlight.extend(ranges);
 6304            }
 6305            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6306            multibuffer
 6307        })?;
 6308
 6309        workspace.update_in(cx, |workspace, window, cx| {
 6310            let project = workspace.project().clone();
 6311            let editor =
 6312                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6313            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6314            editor.update(cx, |editor, cx| {
 6315                editor.highlight_background::<Self>(
 6316                    &ranges_to_highlight,
 6317                    |theme| theme.colors().editor_highlighted_line_background,
 6318                    cx,
 6319                );
 6320            });
 6321        })?;
 6322
 6323        Ok(())
 6324    }
 6325
 6326    pub fn clear_code_action_providers(&mut self) {
 6327        self.code_action_providers.clear();
 6328        self.available_code_actions.take();
 6329    }
 6330
 6331    pub fn add_code_action_provider(
 6332        &mut self,
 6333        provider: Rc<dyn CodeActionProvider>,
 6334        window: &mut Window,
 6335        cx: &mut Context<Self>,
 6336    ) {
 6337        if self
 6338            .code_action_providers
 6339            .iter()
 6340            .any(|existing_provider| existing_provider.id() == provider.id())
 6341        {
 6342            return;
 6343        }
 6344
 6345        self.code_action_providers.push(provider);
 6346        self.refresh_code_actions(window, cx);
 6347    }
 6348
 6349    pub fn remove_code_action_provider(
 6350        &mut self,
 6351        id: Arc<str>,
 6352        window: &mut Window,
 6353        cx: &mut Context<Self>,
 6354    ) {
 6355        self.code_action_providers
 6356            .retain(|provider| provider.id() != id);
 6357        self.refresh_code_actions(window, cx);
 6358    }
 6359
 6360    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6361        !self.code_action_providers.is_empty()
 6362            && EditorSettings::get_global(cx).toolbar.code_actions
 6363    }
 6364
 6365    pub fn has_available_code_actions(&self) -> bool {
 6366        self.available_code_actions
 6367            .as_ref()
 6368            .is_some_and(|(_, actions)| !actions.is_empty())
 6369    }
 6370
 6371    fn render_inline_code_actions(
 6372        &self,
 6373        icon_size: ui::IconSize,
 6374        display_row: DisplayRow,
 6375        is_active: bool,
 6376        cx: &mut Context<Self>,
 6377    ) -> AnyElement {
 6378        let show_tooltip = !self.context_menu_visible();
 6379        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6380            .icon_size(icon_size)
 6381            .shape(ui::IconButtonShape::Square)
 6382            .icon_color(ui::Color::Hidden)
 6383            .toggle_state(is_active)
 6384            .when(show_tooltip, |this| {
 6385                this.tooltip({
 6386                    let focus_handle = self.focus_handle.clone();
 6387                    move |_window, cx| {
 6388                        Tooltip::for_action_in(
 6389                            "Toggle Code Actions",
 6390                            &ToggleCodeActions {
 6391                                deployed_from: None,
 6392                                quick_launch: false,
 6393                            },
 6394                            &focus_handle,
 6395                            cx,
 6396                        )
 6397                    }
 6398                })
 6399            })
 6400            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6401                window.focus(&editor.focus_handle(cx));
 6402                editor.toggle_code_actions(
 6403                    &crate::actions::ToggleCodeActions {
 6404                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6405                            display_row,
 6406                        )),
 6407                        quick_launch: false,
 6408                    },
 6409                    window,
 6410                    cx,
 6411                );
 6412            }))
 6413            .into_any_element()
 6414    }
 6415
 6416    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6417        &self.context_menu
 6418    }
 6419
 6420    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6421        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6422            cx.background_executor()
 6423                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6424                .await;
 6425
 6426            let (start_buffer, start, _, end, newest_selection) = this
 6427                .update(cx, |this, cx| {
 6428                    let newest_selection = this.selections.newest_anchor().clone();
 6429                    if newest_selection.head().diff_base_anchor.is_some() {
 6430                        return None;
 6431                    }
 6432                    let display_snapshot = this.display_snapshot(cx);
 6433                    let newest_selection_adjusted =
 6434                        this.selections.newest_adjusted(&display_snapshot);
 6435                    let buffer = this.buffer.read(cx);
 6436
 6437                    let (start_buffer, start) =
 6438                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6439                    let (end_buffer, end) =
 6440                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6441
 6442                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6443                })?
 6444                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6445                .context(
 6446                    "Expected selection to lie in a single buffer when refreshing code actions",
 6447                )?;
 6448            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6449                let providers = this.code_action_providers.clone();
 6450                let tasks = this
 6451                    .code_action_providers
 6452                    .iter()
 6453                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6454                    .collect::<Vec<_>>();
 6455                (providers, tasks)
 6456            })?;
 6457
 6458            let mut actions = Vec::new();
 6459            for (provider, provider_actions) in
 6460                providers.into_iter().zip(future::join_all(tasks).await)
 6461            {
 6462                if let Some(provider_actions) = provider_actions.log_err() {
 6463                    actions.extend(provider_actions.into_iter().map(|action| {
 6464                        AvailableCodeAction {
 6465                            excerpt_id: newest_selection.start.excerpt_id,
 6466                            action,
 6467                            provider: provider.clone(),
 6468                        }
 6469                    }));
 6470                }
 6471            }
 6472
 6473            this.update(cx, |this, cx| {
 6474                this.available_code_actions = if actions.is_empty() {
 6475                    None
 6476                } else {
 6477                    Some((
 6478                        Location {
 6479                            buffer: start_buffer,
 6480                            range: start..end,
 6481                        },
 6482                        actions.into(),
 6483                    ))
 6484                };
 6485                cx.notify();
 6486            })
 6487        }));
 6488    }
 6489
 6490    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6491        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6492            self.show_git_blame_inline = false;
 6493
 6494            self.show_git_blame_inline_delay_task =
 6495                Some(cx.spawn_in(window, async move |this, cx| {
 6496                    cx.background_executor().timer(delay).await;
 6497
 6498                    this.update(cx, |this, cx| {
 6499                        this.show_git_blame_inline = true;
 6500                        cx.notify();
 6501                    })
 6502                    .log_err();
 6503                }));
 6504        }
 6505    }
 6506
 6507    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6508        let snapshot = self.snapshot(window, cx);
 6509        let cursor = self
 6510            .selections
 6511            .newest::<Point>(&snapshot.display_snapshot)
 6512            .head();
 6513        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6514        else {
 6515            return;
 6516        };
 6517
 6518        let Some(blame) = self.blame.as_ref() else {
 6519            return;
 6520        };
 6521
 6522        let row_info = RowInfo {
 6523            buffer_id: Some(buffer.remote_id()),
 6524            buffer_row: Some(point.row),
 6525            ..Default::default()
 6526        };
 6527        let Some((buffer, blame_entry)) = blame
 6528            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6529            .flatten()
 6530        else {
 6531            return;
 6532        };
 6533
 6534        let anchor = self.selections.newest_anchor().head();
 6535        let position = self.to_pixel_point(anchor, &snapshot, window);
 6536        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6537            self.show_blame_popover(
 6538                buffer,
 6539                &blame_entry,
 6540                position + last_bounds.origin,
 6541                true,
 6542                cx,
 6543            );
 6544        };
 6545    }
 6546
 6547    fn show_blame_popover(
 6548        &mut self,
 6549        buffer: BufferId,
 6550        blame_entry: &BlameEntry,
 6551        position: gpui::Point<Pixels>,
 6552        ignore_timeout: bool,
 6553        cx: &mut Context<Self>,
 6554    ) {
 6555        if let Some(state) = &mut self.inline_blame_popover {
 6556            state.hide_task.take();
 6557        } else {
 6558            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6559            let blame_entry = blame_entry.clone();
 6560            let show_task = cx.spawn(async move |editor, cx| {
 6561                if !ignore_timeout {
 6562                    cx.background_executor()
 6563                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6564                        .await;
 6565                }
 6566                editor
 6567                    .update(cx, |editor, cx| {
 6568                        editor.inline_blame_popover_show_task.take();
 6569                        let Some(blame) = editor.blame.as_ref() else {
 6570                            return;
 6571                        };
 6572                        let blame = blame.read(cx);
 6573                        let details = blame.details_for_entry(buffer, &blame_entry);
 6574                        let markdown = cx.new(|cx| {
 6575                            Markdown::new(
 6576                                details
 6577                                    .as_ref()
 6578                                    .map(|message| message.message.clone())
 6579                                    .unwrap_or_default(),
 6580                                None,
 6581                                None,
 6582                                cx,
 6583                            )
 6584                        });
 6585                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6586                            position,
 6587                            hide_task: None,
 6588                            popover_bounds: None,
 6589                            popover_state: InlineBlamePopoverState {
 6590                                scroll_handle: ScrollHandle::new(),
 6591                                commit_message: details,
 6592                                markdown,
 6593                            },
 6594                            keyboard_grace: ignore_timeout,
 6595                        });
 6596                        cx.notify();
 6597                    })
 6598                    .ok();
 6599            });
 6600            self.inline_blame_popover_show_task = Some(show_task);
 6601        }
 6602    }
 6603
 6604    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6605        self.inline_blame_popover_show_task.take();
 6606        if let Some(state) = &mut self.inline_blame_popover {
 6607            let hide_task = cx.spawn(async move |editor, cx| {
 6608                if !ignore_timeout {
 6609                    cx.background_executor()
 6610                        .timer(std::time::Duration::from_millis(100))
 6611                        .await;
 6612                }
 6613                editor
 6614                    .update(cx, |editor, cx| {
 6615                        editor.inline_blame_popover.take();
 6616                        cx.notify();
 6617                    })
 6618                    .ok();
 6619            });
 6620            state.hide_task = Some(hide_task);
 6621            true
 6622        } else {
 6623            false
 6624        }
 6625    }
 6626
 6627    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6628        if self.pending_rename.is_some() {
 6629            return None;
 6630        }
 6631
 6632        let provider = self.semantics_provider.clone()?;
 6633        let buffer = self.buffer.read(cx);
 6634        let newest_selection = self.selections.newest_anchor().clone();
 6635        let cursor_position = newest_selection.head();
 6636        let (cursor_buffer, cursor_buffer_position) =
 6637            buffer.text_anchor_for_position(cursor_position, cx)?;
 6638        let (tail_buffer, tail_buffer_position) =
 6639            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6640        if cursor_buffer != tail_buffer {
 6641            return None;
 6642        }
 6643
 6644        let snapshot = cursor_buffer.read(cx).snapshot();
 6645        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6646        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6647        if start_word_range != end_word_range {
 6648            self.document_highlights_task.take();
 6649            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6650            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6651            return None;
 6652        }
 6653
 6654        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6655        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6656            cx.background_executor()
 6657                .timer(Duration::from_millis(debounce))
 6658                .await;
 6659
 6660            let highlights = if let Some(highlights) = cx
 6661                .update(|cx| {
 6662                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6663                })
 6664                .ok()
 6665                .flatten()
 6666            {
 6667                highlights.await.log_err()
 6668            } else {
 6669                None
 6670            };
 6671
 6672            if let Some(highlights) = highlights {
 6673                this.update(cx, |this, cx| {
 6674                    if this.pending_rename.is_some() {
 6675                        return;
 6676                    }
 6677
 6678                    let buffer = this.buffer.read(cx);
 6679                    if buffer
 6680                        .text_anchor_for_position(cursor_position, cx)
 6681                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6682                    {
 6683                        return;
 6684                    }
 6685
 6686                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6687                    let mut write_ranges = Vec::new();
 6688                    let mut read_ranges = Vec::new();
 6689                    for highlight in highlights {
 6690                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6691                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6692                        {
 6693                            let start = highlight
 6694                                .range
 6695                                .start
 6696                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6697                            let end = highlight
 6698                                .range
 6699                                .end
 6700                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6701                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6702                                continue;
 6703                            }
 6704
 6705                            let range =
 6706                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6707                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6708                                write_ranges.push(range);
 6709                            } else {
 6710                                read_ranges.push(range);
 6711                            }
 6712                        }
 6713                    }
 6714
 6715                    this.highlight_background::<DocumentHighlightRead>(
 6716                        &read_ranges,
 6717                        |theme| theme.colors().editor_document_highlight_read_background,
 6718                        cx,
 6719                    );
 6720                    this.highlight_background::<DocumentHighlightWrite>(
 6721                        &write_ranges,
 6722                        |theme| theme.colors().editor_document_highlight_write_background,
 6723                        cx,
 6724                    );
 6725                    cx.notify();
 6726                })
 6727                .log_err();
 6728            }
 6729        }));
 6730        None
 6731    }
 6732
 6733    fn prepare_highlight_query_from_selection(
 6734        &mut self,
 6735        window: &Window,
 6736        cx: &mut Context<Editor>,
 6737    ) -> Option<(String, Range<Anchor>)> {
 6738        if matches!(self.mode, EditorMode::SingleLine) {
 6739            return None;
 6740        }
 6741        if !EditorSettings::get_global(cx).selection_highlight {
 6742            return None;
 6743        }
 6744        if self.selections.count() != 1 || self.selections.line_mode() {
 6745            return None;
 6746        }
 6747        let snapshot = self.snapshot(window, cx);
 6748        let selection = self.selections.newest::<Point>(&snapshot);
 6749        // If the selection spans multiple rows OR it is empty
 6750        if selection.start.row != selection.end.row
 6751            || selection.start.column == selection.end.column
 6752        {
 6753            return None;
 6754        }
 6755        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6756        let query = snapshot
 6757            .buffer_snapshot()
 6758            .text_for_range(selection_anchor_range.clone())
 6759            .collect::<String>();
 6760        if query.trim().is_empty() {
 6761            return None;
 6762        }
 6763        Some((query, selection_anchor_range))
 6764    }
 6765
 6766    fn update_selection_occurrence_highlights(
 6767        &mut self,
 6768        query_text: String,
 6769        query_range: Range<Anchor>,
 6770        multi_buffer_range_to_query: Range<Point>,
 6771        use_debounce: bool,
 6772        window: &mut Window,
 6773        cx: &mut Context<Editor>,
 6774    ) -> Task<()> {
 6775        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6776        cx.spawn_in(window, async move |editor, cx| {
 6777            if use_debounce {
 6778                cx.background_executor()
 6779                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6780                    .await;
 6781            }
 6782            let match_task = cx.background_spawn(async move {
 6783                let buffer_ranges = multi_buffer_snapshot
 6784                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6785                    .into_iter()
 6786                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6787                let mut match_ranges = Vec::new();
 6788                let Ok(regex) = project::search::SearchQuery::text(
 6789                    query_text.clone(),
 6790                    false,
 6791                    false,
 6792                    false,
 6793                    Default::default(),
 6794                    Default::default(),
 6795                    false,
 6796                    None,
 6797                ) else {
 6798                    return Vec::default();
 6799                };
 6800                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6801                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6802                    match_ranges.extend(
 6803                        regex
 6804                            .search(buffer_snapshot, Some(search_range.clone()))
 6805                            .await
 6806                            .into_iter()
 6807                            .filter_map(|match_range| {
 6808                                let match_start = buffer_snapshot
 6809                                    .anchor_after(search_range.start + match_range.start);
 6810                                let match_end = buffer_snapshot
 6811                                    .anchor_before(search_range.start + match_range.end);
 6812                                let match_anchor_range = Anchor::range_in_buffer(
 6813                                    excerpt_id,
 6814                                    buffer_snapshot.remote_id(),
 6815                                    match_start..match_end,
 6816                                );
 6817                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6818                            }),
 6819                    );
 6820                }
 6821                match_ranges
 6822            });
 6823            let match_ranges = match_task.await;
 6824            editor
 6825                .update_in(cx, |editor, _, cx| {
 6826                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6827                    if !match_ranges.is_empty() {
 6828                        editor.highlight_background::<SelectedTextHighlight>(
 6829                            &match_ranges,
 6830                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6831                            cx,
 6832                        )
 6833                    }
 6834                })
 6835                .log_err();
 6836        })
 6837    }
 6838
 6839    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6840        struct NewlineFold;
 6841        let type_id = std::any::TypeId::of::<NewlineFold>();
 6842        if !self.mode.is_single_line() {
 6843            return;
 6844        }
 6845        let snapshot = self.snapshot(window, cx);
 6846        if snapshot.buffer_snapshot().max_point().row == 0 {
 6847            return;
 6848        }
 6849        let task = cx.background_spawn(async move {
 6850            let new_newlines = snapshot
 6851                .buffer_chars_at(0)
 6852                .filter_map(|(c, i)| {
 6853                    if c == '\n' {
 6854                        Some(
 6855                            snapshot.buffer_snapshot().anchor_after(i)
 6856                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 6857                        )
 6858                    } else {
 6859                        None
 6860                    }
 6861                })
 6862                .collect::<Vec<_>>();
 6863            let existing_newlines = snapshot
 6864                .folds_in_range(0..snapshot.buffer_snapshot().len())
 6865                .filter_map(|fold| {
 6866                    if fold.placeholder.type_tag == Some(type_id) {
 6867                        Some(fold.range.start..fold.range.end)
 6868                    } else {
 6869                        None
 6870                    }
 6871                })
 6872                .collect::<Vec<_>>();
 6873
 6874            (new_newlines, existing_newlines)
 6875        });
 6876        self.folding_newlines = cx.spawn(async move |this, cx| {
 6877            let (new_newlines, existing_newlines) = task.await;
 6878            if new_newlines == existing_newlines {
 6879                return;
 6880            }
 6881            let placeholder = FoldPlaceholder {
 6882                render: Arc::new(move |_, _, cx| {
 6883                    div()
 6884                        .bg(cx.theme().status().hint_background)
 6885                        .border_b_1()
 6886                        .size_full()
 6887                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6888                        .border_color(cx.theme().status().hint)
 6889                        .child("\\n")
 6890                        .into_any()
 6891                }),
 6892                constrain_width: false,
 6893                merge_adjacent: false,
 6894                type_tag: Some(type_id),
 6895            };
 6896            let creases = new_newlines
 6897                .into_iter()
 6898                .map(|range| Crease::simple(range, placeholder.clone()))
 6899                .collect();
 6900            this.update(cx, |this, cx| {
 6901                this.display_map.update(cx, |display_map, cx| {
 6902                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6903                    display_map.fold(creases, cx);
 6904                });
 6905            })
 6906            .ok();
 6907        });
 6908    }
 6909
 6910    fn refresh_selected_text_highlights(
 6911        &mut self,
 6912        on_buffer_edit: bool,
 6913        window: &mut Window,
 6914        cx: &mut Context<Editor>,
 6915    ) {
 6916        let Some((query_text, query_range)) =
 6917            self.prepare_highlight_query_from_selection(window, cx)
 6918        else {
 6919            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6920            self.quick_selection_highlight_task.take();
 6921            self.debounced_selection_highlight_task.take();
 6922            return;
 6923        };
 6924        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6925        if on_buffer_edit
 6926            || self
 6927                .quick_selection_highlight_task
 6928                .as_ref()
 6929                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6930        {
 6931            let multi_buffer_visible_start = self
 6932                .scroll_manager
 6933                .anchor()
 6934                .anchor
 6935                .to_point(&multi_buffer_snapshot);
 6936            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6937                multi_buffer_visible_start
 6938                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6939                Bias::Left,
 6940            );
 6941            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6942            self.quick_selection_highlight_task = Some((
 6943                query_range.clone(),
 6944                self.update_selection_occurrence_highlights(
 6945                    query_text.clone(),
 6946                    query_range.clone(),
 6947                    multi_buffer_visible_range,
 6948                    false,
 6949                    window,
 6950                    cx,
 6951                ),
 6952            ));
 6953        }
 6954        if on_buffer_edit
 6955            || self
 6956                .debounced_selection_highlight_task
 6957                .as_ref()
 6958                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6959        {
 6960            let multi_buffer_start = multi_buffer_snapshot
 6961                .anchor_before(0)
 6962                .to_point(&multi_buffer_snapshot);
 6963            let multi_buffer_end = multi_buffer_snapshot
 6964                .anchor_after(multi_buffer_snapshot.len())
 6965                .to_point(&multi_buffer_snapshot);
 6966            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6967            self.debounced_selection_highlight_task = Some((
 6968                query_range.clone(),
 6969                self.update_selection_occurrence_highlights(
 6970                    query_text,
 6971                    query_range,
 6972                    multi_buffer_full_range,
 6973                    true,
 6974                    window,
 6975                    cx,
 6976                ),
 6977            ));
 6978        }
 6979    }
 6980
 6981    pub fn refresh_edit_prediction(
 6982        &mut self,
 6983        debounce: bool,
 6984        user_requested: bool,
 6985        window: &mut Window,
 6986        cx: &mut Context<Self>,
 6987    ) -> Option<()> {
 6988        if DisableAiSettings::get_global(cx).disable_ai {
 6989            return None;
 6990        }
 6991
 6992        let provider = self.edit_prediction_provider()?;
 6993        let cursor = self.selections.newest_anchor().head();
 6994        let (buffer, cursor_buffer_position) =
 6995            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6996
 6997        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6998            self.discard_edit_prediction(false, cx);
 6999            return None;
 7000        }
 7001
 7002        self.update_visible_edit_prediction(window, cx);
 7003
 7004        if !user_requested
 7005            && (!self.should_show_edit_predictions()
 7006                || !self.is_focused(window)
 7007                || buffer.read(cx).is_empty())
 7008        {
 7009            self.discard_edit_prediction(false, cx);
 7010            return None;
 7011        }
 7012
 7013        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7014        Some(())
 7015    }
 7016
 7017    fn show_edit_predictions_in_menu(&self) -> bool {
 7018        match self.edit_prediction_settings {
 7019            EditPredictionSettings::Disabled => false,
 7020            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7021        }
 7022    }
 7023
 7024    pub fn edit_predictions_enabled(&self) -> bool {
 7025        match self.edit_prediction_settings {
 7026            EditPredictionSettings::Disabled => false,
 7027            EditPredictionSettings::Enabled { .. } => true,
 7028        }
 7029    }
 7030
 7031    fn edit_prediction_requires_modifier(&self) -> bool {
 7032        match self.edit_prediction_settings {
 7033            EditPredictionSettings::Disabled => false,
 7034            EditPredictionSettings::Enabled {
 7035                preview_requires_modifier,
 7036                ..
 7037            } => preview_requires_modifier,
 7038        }
 7039    }
 7040
 7041    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7042        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7043            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7044            self.discard_edit_prediction(false, cx);
 7045        } else {
 7046            let selection = self.selections.newest_anchor();
 7047            let cursor = selection.head();
 7048
 7049            if let Some((buffer, cursor_buffer_position)) =
 7050                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7051            {
 7052                self.edit_prediction_settings =
 7053                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7054            }
 7055        }
 7056    }
 7057
 7058    fn edit_prediction_settings_at_position(
 7059        &self,
 7060        buffer: &Entity<Buffer>,
 7061        buffer_position: language::Anchor,
 7062        cx: &App,
 7063    ) -> EditPredictionSettings {
 7064        if !self.mode.is_full()
 7065            || !self.show_edit_predictions_override.unwrap_or(true)
 7066            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7067        {
 7068            return EditPredictionSettings::Disabled;
 7069        }
 7070
 7071        let buffer = buffer.read(cx);
 7072
 7073        let file = buffer.file();
 7074
 7075        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7076            return EditPredictionSettings::Disabled;
 7077        };
 7078
 7079        let by_provider = matches!(
 7080            self.menu_edit_predictions_policy,
 7081            MenuEditPredictionsPolicy::ByProvider
 7082        );
 7083
 7084        let show_in_menu = by_provider
 7085            && self
 7086                .edit_prediction_provider
 7087                .as_ref()
 7088                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7089
 7090        let preview_requires_modifier =
 7091            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7092
 7093        EditPredictionSettings::Enabled {
 7094            show_in_menu,
 7095            preview_requires_modifier,
 7096        }
 7097    }
 7098
 7099    fn should_show_edit_predictions(&self) -> bool {
 7100        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7101    }
 7102
 7103    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7104        matches!(
 7105            self.edit_prediction_preview,
 7106            EditPredictionPreview::Active { .. }
 7107        )
 7108    }
 7109
 7110    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7111        let cursor = self.selections.newest_anchor().head();
 7112        if let Some((buffer, cursor_position)) =
 7113            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7114        {
 7115            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7116        } else {
 7117            false
 7118        }
 7119    }
 7120
 7121    pub fn supports_minimap(&self, cx: &App) -> bool {
 7122        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7123    }
 7124
 7125    fn edit_predictions_enabled_in_buffer(
 7126        &self,
 7127        buffer: &Entity<Buffer>,
 7128        buffer_position: language::Anchor,
 7129        cx: &App,
 7130    ) -> bool {
 7131        maybe!({
 7132            if self.read_only(cx) {
 7133                return Some(false);
 7134            }
 7135            let provider = self.edit_prediction_provider()?;
 7136            if !provider.is_enabled(buffer, buffer_position, cx) {
 7137                return Some(false);
 7138            }
 7139            let buffer = buffer.read(cx);
 7140            let Some(file) = buffer.file() else {
 7141                return Some(true);
 7142            };
 7143            let settings = all_language_settings(Some(file), cx);
 7144            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7145        })
 7146        .unwrap_or(false)
 7147    }
 7148
 7149    fn cycle_edit_prediction(
 7150        &mut self,
 7151        direction: Direction,
 7152        window: &mut Window,
 7153        cx: &mut Context<Self>,
 7154    ) -> Option<()> {
 7155        let provider = self.edit_prediction_provider()?;
 7156        let cursor = self.selections.newest_anchor().head();
 7157        let (buffer, cursor_buffer_position) =
 7158            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7159        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7160            return None;
 7161        }
 7162
 7163        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7164        self.update_visible_edit_prediction(window, cx);
 7165
 7166        Some(())
 7167    }
 7168
 7169    pub fn show_edit_prediction(
 7170        &mut self,
 7171        _: &ShowEditPrediction,
 7172        window: &mut Window,
 7173        cx: &mut Context<Self>,
 7174    ) {
 7175        if !self.has_active_edit_prediction() {
 7176            self.refresh_edit_prediction(false, true, window, cx);
 7177            return;
 7178        }
 7179
 7180        self.update_visible_edit_prediction(window, cx);
 7181    }
 7182
 7183    pub fn display_cursor_names(
 7184        &mut self,
 7185        _: &DisplayCursorNames,
 7186        window: &mut Window,
 7187        cx: &mut Context<Self>,
 7188    ) {
 7189        self.show_cursor_names(window, cx);
 7190    }
 7191
 7192    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7193        self.show_cursor_names = true;
 7194        cx.notify();
 7195        cx.spawn_in(window, async move |this, cx| {
 7196            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7197            this.update(cx, |this, cx| {
 7198                this.show_cursor_names = false;
 7199                cx.notify()
 7200            })
 7201            .ok()
 7202        })
 7203        .detach();
 7204    }
 7205
 7206    pub fn next_edit_prediction(
 7207        &mut self,
 7208        _: &NextEditPrediction,
 7209        window: &mut Window,
 7210        cx: &mut Context<Self>,
 7211    ) {
 7212        if self.has_active_edit_prediction() {
 7213            self.cycle_edit_prediction(Direction::Next, window, cx);
 7214        } else {
 7215            let is_copilot_disabled = self
 7216                .refresh_edit_prediction(false, true, window, cx)
 7217                .is_none();
 7218            if is_copilot_disabled {
 7219                cx.propagate();
 7220            }
 7221        }
 7222    }
 7223
 7224    pub fn previous_edit_prediction(
 7225        &mut self,
 7226        _: &PreviousEditPrediction,
 7227        window: &mut Window,
 7228        cx: &mut Context<Self>,
 7229    ) {
 7230        if self.has_active_edit_prediction() {
 7231            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7232        } else {
 7233            let is_copilot_disabled = self
 7234                .refresh_edit_prediction(false, true, window, cx)
 7235                .is_none();
 7236            if is_copilot_disabled {
 7237                cx.propagate();
 7238            }
 7239        }
 7240    }
 7241
 7242    pub fn accept_edit_prediction(
 7243        &mut self,
 7244        _: &AcceptEditPrediction,
 7245        window: &mut Window,
 7246        cx: &mut Context<Self>,
 7247    ) {
 7248        if self.show_edit_predictions_in_menu() {
 7249            self.hide_context_menu(window, cx);
 7250        }
 7251
 7252        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7253            return;
 7254        };
 7255
 7256        match &active_edit_prediction.completion {
 7257            EditPrediction::MoveWithin { target, .. } => {
 7258                let target = *target;
 7259
 7260                if let Some(position_map) = &self.last_position_map {
 7261                    if position_map
 7262                        .visible_row_range
 7263                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7264                        || !self.edit_prediction_requires_modifier()
 7265                    {
 7266                        self.unfold_ranges(&[target..target], true, false, cx);
 7267                        // Note that this is also done in vim's handler of the Tab action.
 7268                        self.change_selections(
 7269                            SelectionEffects::scroll(Autoscroll::newest()),
 7270                            window,
 7271                            cx,
 7272                            |selections| {
 7273                                selections.select_anchor_ranges([target..target]);
 7274                            },
 7275                        );
 7276                        self.clear_row_highlights::<EditPredictionPreview>();
 7277
 7278                        self.edit_prediction_preview
 7279                            .set_previous_scroll_position(None);
 7280                    } else {
 7281                        self.edit_prediction_preview
 7282                            .set_previous_scroll_position(Some(
 7283                                position_map.snapshot.scroll_anchor,
 7284                            ));
 7285
 7286                        self.highlight_rows::<EditPredictionPreview>(
 7287                            target..target,
 7288                            cx.theme().colors().editor_highlighted_line_background,
 7289                            RowHighlightOptions {
 7290                                autoscroll: true,
 7291                                ..Default::default()
 7292                            },
 7293                            cx,
 7294                        );
 7295                        self.request_autoscroll(Autoscroll::fit(), cx);
 7296                    }
 7297                }
 7298            }
 7299            EditPrediction::MoveOutside { snapshot, target } => {
 7300                if let Some(workspace) = self.workspace() {
 7301                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7302                        .detach_and_log_err(cx);
 7303                }
 7304            }
 7305            EditPrediction::Edit { edits, .. } => {
 7306                self.report_edit_prediction_event(
 7307                    active_edit_prediction.completion_id.clone(),
 7308                    true,
 7309                    cx,
 7310                );
 7311
 7312                if let Some(provider) = self.edit_prediction_provider() {
 7313                    provider.accept(cx);
 7314                }
 7315
 7316                // Store the transaction ID and selections before applying the edit
 7317                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7318
 7319                let snapshot = self.buffer.read(cx).snapshot(cx);
 7320                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7321
 7322                self.buffer.update(cx, |buffer, cx| {
 7323                    buffer.edit(edits.iter().cloned(), None, cx)
 7324                });
 7325
 7326                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7327                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7328                });
 7329
 7330                let selections = self.selections.disjoint_anchors_arc();
 7331                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7332                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7333                    if has_new_transaction {
 7334                        self.selection_history
 7335                            .insert_transaction(transaction_id_now, selections);
 7336                    }
 7337                }
 7338
 7339                self.update_visible_edit_prediction(window, cx);
 7340                if self.active_edit_prediction.is_none() {
 7341                    self.refresh_edit_prediction(true, true, window, cx);
 7342                }
 7343
 7344                cx.notify();
 7345            }
 7346        }
 7347
 7348        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7349    }
 7350
 7351    pub fn accept_partial_edit_prediction(
 7352        &mut self,
 7353        _: &AcceptPartialEditPrediction,
 7354        window: &mut Window,
 7355        cx: &mut Context<Self>,
 7356    ) {
 7357        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7358            return;
 7359        };
 7360        if self.selections.count() != 1 {
 7361            return;
 7362        }
 7363
 7364        match &active_edit_prediction.completion {
 7365            EditPrediction::MoveWithin { target, .. } => {
 7366                let target = *target;
 7367                self.change_selections(
 7368                    SelectionEffects::scroll(Autoscroll::newest()),
 7369                    window,
 7370                    cx,
 7371                    |selections| {
 7372                        selections.select_anchor_ranges([target..target]);
 7373                    },
 7374                );
 7375            }
 7376            EditPrediction::MoveOutside { snapshot, target } => {
 7377                if let Some(workspace) = self.workspace() {
 7378                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7379                        .detach_and_log_err(cx);
 7380                }
 7381            }
 7382            EditPrediction::Edit { edits, .. } => {
 7383                self.report_edit_prediction_event(
 7384                    active_edit_prediction.completion_id.clone(),
 7385                    true,
 7386                    cx,
 7387                );
 7388
 7389                // Find an insertion that starts at the cursor position.
 7390                let snapshot = self.buffer.read(cx).snapshot(cx);
 7391                let cursor_offset = self
 7392                    .selections
 7393                    .newest::<usize>(&self.display_snapshot(cx))
 7394                    .head();
 7395                let insertion = edits.iter().find_map(|(range, text)| {
 7396                    let range = range.to_offset(&snapshot);
 7397                    if range.is_empty() && range.start == cursor_offset {
 7398                        Some(text)
 7399                    } else {
 7400                        None
 7401                    }
 7402                });
 7403
 7404                if let Some(text) = insertion {
 7405                    let mut partial_completion = text
 7406                        .chars()
 7407                        .by_ref()
 7408                        .take_while(|c| c.is_alphabetic())
 7409                        .collect::<String>();
 7410                    if partial_completion.is_empty() {
 7411                        partial_completion = text
 7412                            .chars()
 7413                            .by_ref()
 7414                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7415                            .collect::<String>();
 7416                    }
 7417
 7418                    cx.emit(EditorEvent::InputHandled {
 7419                        utf16_range_to_replace: None,
 7420                        text: partial_completion.clone().into(),
 7421                    });
 7422
 7423                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7424
 7425                    self.refresh_edit_prediction(true, true, window, cx);
 7426                    cx.notify();
 7427                } else {
 7428                    self.accept_edit_prediction(&Default::default(), window, cx);
 7429                }
 7430            }
 7431        }
 7432    }
 7433
 7434    fn discard_edit_prediction(
 7435        &mut self,
 7436        should_report_edit_prediction_event: bool,
 7437        cx: &mut Context<Self>,
 7438    ) -> bool {
 7439        if should_report_edit_prediction_event {
 7440            let completion_id = self
 7441                .active_edit_prediction
 7442                .as_ref()
 7443                .and_then(|active_completion| active_completion.completion_id.clone());
 7444
 7445            self.report_edit_prediction_event(completion_id, false, cx);
 7446        }
 7447
 7448        if let Some(provider) = self.edit_prediction_provider() {
 7449            provider.discard(cx);
 7450        }
 7451
 7452        self.take_active_edit_prediction(cx)
 7453    }
 7454
 7455    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7456        let Some(provider) = self.edit_prediction_provider() else {
 7457            return;
 7458        };
 7459
 7460        let Some((_, buffer, _)) = self
 7461            .buffer
 7462            .read(cx)
 7463            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7464        else {
 7465            return;
 7466        };
 7467
 7468        let extension = buffer
 7469            .read(cx)
 7470            .file()
 7471            .and_then(|file| Some(file.path().extension()?.to_string()));
 7472
 7473        let event_type = match accepted {
 7474            true => "Edit Prediction Accepted",
 7475            false => "Edit Prediction Discarded",
 7476        };
 7477        telemetry::event!(
 7478            event_type,
 7479            provider = provider.name(),
 7480            prediction_id = id,
 7481            suggestion_accepted = accepted,
 7482            file_extension = extension,
 7483        );
 7484    }
 7485
 7486    fn open_editor_at_anchor(
 7487        snapshot: &language::BufferSnapshot,
 7488        target: language::Anchor,
 7489        workspace: &Entity<Workspace>,
 7490        window: &mut Window,
 7491        cx: &mut App,
 7492    ) -> Task<Result<()>> {
 7493        workspace.update(cx, |workspace, cx| {
 7494            let path = snapshot.file().map(|file| file.full_path(cx));
 7495            let Some(path) =
 7496                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7497            else {
 7498                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7499            };
 7500            let target = text::ToPoint::to_point(&target, snapshot);
 7501            let item = workspace.open_path(path, None, true, window, cx);
 7502            window.spawn(cx, async move |cx| {
 7503                let Some(editor) = item.await?.downcast::<Editor>() else {
 7504                    return Ok(());
 7505                };
 7506                editor
 7507                    .update_in(cx, |editor, window, cx| {
 7508                        editor.go_to_singleton_buffer_point(target, window, cx);
 7509                    })
 7510                    .ok();
 7511                anyhow::Ok(())
 7512            })
 7513        })
 7514    }
 7515
 7516    pub fn has_active_edit_prediction(&self) -> bool {
 7517        self.active_edit_prediction.is_some()
 7518    }
 7519
 7520    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7521        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7522            return false;
 7523        };
 7524
 7525        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7526        self.clear_highlights::<EditPredictionHighlight>(cx);
 7527        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7528        true
 7529    }
 7530
 7531    /// Returns true when we're displaying the edit prediction popover below the cursor
 7532    /// like we are not previewing and the LSP autocomplete menu is visible
 7533    /// or we are in `when_holding_modifier` mode.
 7534    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7535        if self.edit_prediction_preview_is_active()
 7536            || !self.show_edit_predictions_in_menu()
 7537            || !self.edit_predictions_enabled()
 7538        {
 7539            return false;
 7540        }
 7541
 7542        if self.has_visible_completions_menu() {
 7543            return true;
 7544        }
 7545
 7546        has_completion && self.edit_prediction_requires_modifier()
 7547    }
 7548
 7549    fn handle_modifiers_changed(
 7550        &mut self,
 7551        modifiers: Modifiers,
 7552        position_map: &PositionMap,
 7553        window: &mut Window,
 7554        cx: &mut Context<Self>,
 7555    ) {
 7556        if self.show_edit_predictions_in_menu() {
 7557            self.update_edit_prediction_preview(&modifiers, window, cx);
 7558        }
 7559
 7560        self.update_selection_mode(&modifiers, position_map, window, cx);
 7561
 7562        let mouse_position = window.mouse_position();
 7563        if !position_map.text_hitbox.is_hovered(window) {
 7564            return;
 7565        }
 7566
 7567        self.update_hovered_link(
 7568            position_map.point_for_position(mouse_position),
 7569            &position_map.snapshot,
 7570            modifiers,
 7571            window,
 7572            cx,
 7573        )
 7574    }
 7575
 7576    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7577        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7578        if invert {
 7579            match multi_cursor_setting {
 7580                MultiCursorModifier::Alt => modifiers.alt,
 7581                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7582            }
 7583        } else {
 7584            match multi_cursor_setting {
 7585                MultiCursorModifier::Alt => modifiers.secondary(),
 7586                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7587            }
 7588        }
 7589    }
 7590
 7591    fn columnar_selection_mode(
 7592        modifiers: &Modifiers,
 7593        cx: &mut Context<Self>,
 7594    ) -> Option<ColumnarMode> {
 7595        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7596            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7597                Some(ColumnarMode::FromMouse)
 7598            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7599                Some(ColumnarMode::FromSelection)
 7600            } else {
 7601                None
 7602            }
 7603        } else {
 7604            None
 7605        }
 7606    }
 7607
 7608    fn update_selection_mode(
 7609        &mut self,
 7610        modifiers: &Modifiers,
 7611        position_map: &PositionMap,
 7612        window: &mut Window,
 7613        cx: &mut Context<Self>,
 7614    ) {
 7615        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7616            return;
 7617        };
 7618        if self.selections.pending_anchor().is_none() {
 7619            return;
 7620        }
 7621
 7622        let mouse_position = window.mouse_position();
 7623        let point_for_position = position_map.point_for_position(mouse_position);
 7624        let position = point_for_position.previous_valid;
 7625
 7626        self.select(
 7627            SelectPhase::BeginColumnar {
 7628                position,
 7629                reset: false,
 7630                mode,
 7631                goal_column: point_for_position.exact_unclipped.column(),
 7632            },
 7633            window,
 7634            cx,
 7635        );
 7636    }
 7637
 7638    fn update_edit_prediction_preview(
 7639        &mut self,
 7640        modifiers: &Modifiers,
 7641        window: &mut Window,
 7642        cx: &mut Context<Self>,
 7643    ) {
 7644        let mut modifiers_held = false;
 7645        if let Some(accept_keystroke) = self
 7646            .accept_edit_prediction_keybind(false, window, cx)
 7647            .keystroke()
 7648        {
 7649            modifiers_held = modifiers_held
 7650                || (accept_keystroke.modifiers() == modifiers
 7651                    && accept_keystroke.modifiers().modified());
 7652        };
 7653        if let Some(accept_partial_keystroke) = self
 7654            .accept_edit_prediction_keybind(true, window, cx)
 7655            .keystroke()
 7656        {
 7657            modifiers_held = modifiers_held
 7658                || (accept_partial_keystroke.modifiers() == modifiers
 7659                    && accept_partial_keystroke.modifiers().modified());
 7660        }
 7661
 7662        if modifiers_held {
 7663            if matches!(
 7664                self.edit_prediction_preview,
 7665                EditPredictionPreview::Inactive { .. }
 7666            ) {
 7667                self.edit_prediction_preview = EditPredictionPreview::Active {
 7668                    previous_scroll_position: None,
 7669                    since: Instant::now(),
 7670                };
 7671
 7672                self.update_visible_edit_prediction(window, cx);
 7673                cx.notify();
 7674            }
 7675        } else if let EditPredictionPreview::Active {
 7676            previous_scroll_position,
 7677            since,
 7678        } = self.edit_prediction_preview
 7679        {
 7680            if let (Some(previous_scroll_position), Some(position_map)) =
 7681                (previous_scroll_position, self.last_position_map.as_ref())
 7682            {
 7683                self.set_scroll_position(
 7684                    previous_scroll_position
 7685                        .scroll_position(&position_map.snapshot.display_snapshot),
 7686                    window,
 7687                    cx,
 7688                );
 7689            }
 7690
 7691            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7692                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7693            };
 7694            self.clear_row_highlights::<EditPredictionPreview>();
 7695            self.update_visible_edit_prediction(window, cx);
 7696            cx.notify();
 7697        }
 7698    }
 7699
 7700    fn update_visible_edit_prediction(
 7701        &mut self,
 7702        _window: &mut Window,
 7703        cx: &mut Context<Self>,
 7704    ) -> Option<()> {
 7705        if DisableAiSettings::get_global(cx).disable_ai {
 7706            return None;
 7707        }
 7708
 7709        if self.ime_transaction.is_some() {
 7710            self.discard_edit_prediction(false, cx);
 7711            return None;
 7712        }
 7713
 7714        let selection = self.selections.newest_anchor();
 7715        let cursor = selection.head();
 7716        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7717        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7718        let excerpt_id = cursor.excerpt_id;
 7719
 7720        let show_in_menu = self.show_edit_predictions_in_menu();
 7721        let completions_menu_has_precedence = !show_in_menu
 7722            && (self.context_menu.borrow().is_some()
 7723                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7724
 7725        if completions_menu_has_precedence
 7726            || !offset_selection.is_empty()
 7727            || self
 7728                .active_edit_prediction
 7729                .as_ref()
 7730                .is_some_and(|completion| {
 7731                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7732                        return false;
 7733                    };
 7734                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7735                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7736                    !invalidation_range.contains(&offset_selection.head())
 7737                })
 7738        {
 7739            self.discard_edit_prediction(false, cx);
 7740            return None;
 7741        }
 7742
 7743        self.take_active_edit_prediction(cx);
 7744        let Some(provider) = self.edit_prediction_provider() else {
 7745            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7746            return None;
 7747        };
 7748
 7749        let (buffer, cursor_buffer_position) =
 7750            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7751
 7752        self.edit_prediction_settings =
 7753            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7754
 7755        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7756
 7757        if self.edit_prediction_indent_conflict {
 7758            let cursor_point = cursor.to_point(&multibuffer);
 7759
 7760            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7761
 7762            if let Some((_, indent)) = indents.iter().next()
 7763                && indent.len == cursor_point.column
 7764            {
 7765                self.edit_prediction_indent_conflict = false;
 7766            }
 7767        }
 7768
 7769        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7770
 7771        let (completion_id, edits, edit_preview) = match edit_prediction {
 7772            edit_prediction::EditPrediction::Local {
 7773                id,
 7774                edits,
 7775                edit_preview,
 7776            } => (id, edits, edit_preview),
 7777            edit_prediction::EditPrediction::Jump {
 7778                id,
 7779                snapshot,
 7780                target,
 7781            } => {
 7782                self.stale_edit_prediction_in_menu = None;
 7783                self.active_edit_prediction = Some(EditPredictionState {
 7784                    inlay_ids: vec![],
 7785                    completion: EditPrediction::MoveOutside { snapshot, target },
 7786                    completion_id: id,
 7787                    invalidation_range: None,
 7788                });
 7789                cx.notify();
 7790                return Some(());
 7791            }
 7792        };
 7793
 7794        let edits = edits
 7795            .into_iter()
 7796            .flat_map(|(range, new_text)| {
 7797                Some((
 7798                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7799                    new_text,
 7800                ))
 7801            })
 7802            .collect::<Vec<_>>();
 7803        if edits.is_empty() {
 7804            return None;
 7805        }
 7806
 7807        let first_edit_start = edits.first().unwrap().0.start;
 7808        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7809        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7810
 7811        let last_edit_end = edits.last().unwrap().0.end;
 7812        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7813        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7814
 7815        let cursor_row = cursor.to_point(&multibuffer).row;
 7816
 7817        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7818
 7819        let mut inlay_ids = Vec::new();
 7820        let invalidation_row_range;
 7821        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7822            Some(cursor_row..edit_end_row)
 7823        } else if cursor_row > edit_end_row {
 7824            Some(edit_start_row..cursor_row)
 7825        } else {
 7826            None
 7827        };
 7828        let supports_jump = self
 7829            .edit_prediction_provider
 7830            .as_ref()
 7831            .map(|provider| provider.provider.supports_jump_to_edit())
 7832            .unwrap_or(true);
 7833
 7834        let is_move = supports_jump
 7835            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7836        let completion = if is_move {
 7837            invalidation_row_range =
 7838                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7839            let target = first_edit_start;
 7840            EditPrediction::MoveWithin { target, snapshot }
 7841        } else {
 7842            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7843                && !self.edit_predictions_hidden_for_vim_mode;
 7844
 7845            if show_completions_in_buffer {
 7846                if edits
 7847                    .iter()
 7848                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7849                {
 7850                    let mut inlays = Vec::new();
 7851                    for (range, new_text) in &edits {
 7852                        let inlay = Inlay::edit_prediction(
 7853                            post_inc(&mut self.next_inlay_id),
 7854                            range.start,
 7855                            new_text.as_str(),
 7856                        );
 7857                        inlay_ids.push(inlay.id);
 7858                        inlays.push(inlay);
 7859                    }
 7860
 7861                    self.splice_inlays(&[], inlays, cx);
 7862                } else {
 7863                    let background_color = cx.theme().status().deleted_background;
 7864                    self.highlight_text::<EditPredictionHighlight>(
 7865                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7866                        HighlightStyle {
 7867                            background_color: Some(background_color),
 7868                            ..Default::default()
 7869                        },
 7870                        cx,
 7871                    );
 7872                }
 7873            }
 7874
 7875            invalidation_row_range = edit_start_row..edit_end_row;
 7876
 7877            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7878                if provider.show_tab_accept_marker() {
 7879                    EditDisplayMode::TabAccept
 7880                } else {
 7881                    EditDisplayMode::Inline
 7882                }
 7883            } else {
 7884                EditDisplayMode::DiffPopover
 7885            };
 7886
 7887            EditPrediction::Edit {
 7888                edits,
 7889                edit_preview,
 7890                display_mode,
 7891                snapshot,
 7892            }
 7893        };
 7894
 7895        let invalidation_range = multibuffer
 7896            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7897            ..multibuffer.anchor_after(Point::new(
 7898                invalidation_row_range.end,
 7899                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7900            ));
 7901
 7902        self.stale_edit_prediction_in_menu = None;
 7903        self.active_edit_prediction = Some(EditPredictionState {
 7904            inlay_ids,
 7905            completion,
 7906            completion_id,
 7907            invalidation_range: Some(invalidation_range),
 7908        });
 7909
 7910        cx.notify();
 7911
 7912        Some(())
 7913    }
 7914
 7915    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7916        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7917    }
 7918
 7919    fn clear_tasks(&mut self) {
 7920        self.tasks.clear()
 7921    }
 7922
 7923    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7924        if self.tasks.insert(key, value).is_some() {
 7925            // This case should hopefully be rare, but just in case...
 7926            log::error!(
 7927                "multiple different run targets found on a single line, only the last target will be rendered"
 7928            )
 7929        }
 7930    }
 7931
 7932    /// Get all display points of breakpoints that will be rendered within editor
 7933    ///
 7934    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7935    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7936    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7937    fn active_breakpoints(
 7938        &self,
 7939        range: Range<DisplayRow>,
 7940        window: &mut Window,
 7941        cx: &mut Context<Self>,
 7942    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7943        let mut breakpoint_display_points = HashMap::default();
 7944
 7945        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7946            return breakpoint_display_points;
 7947        };
 7948
 7949        let snapshot = self.snapshot(window, cx);
 7950
 7951        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 7952        let Some(project) = self.project() else {
 7953            return breakpoint_display_points;
 7954        };
 7955
 7956        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7957            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7958
 7959        for (buffer_snapshot, range, excerpt_id) in
 7960            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7961        {
 7962            let Some(buffer) = project
 7963                .read(cx)
 7964                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7965            else {
 7966                continue;
 7967            };
 7968            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7969                &buffer,
 7970                Some(
 7971                    buffer_snapshot.anchor_before(range.start)
 7972                        ..buffer_snapshot.anchor_after(range.end),
 7973                ),
 7974                buffer_snapshot,
 7975                cx,
 7976            );
 7977            for (breakpoint, state) in breakpoints {
 7978                let multi_buffer_anchor =
 7979                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7980                let position = multi_buffer_anchor
 7981                    .to_point(&multi_buffer_snapshot)
 7982                    .to_display_point(&snapshot);
 7983
 7984                breakpoint_display_points.insert(
 7985                    position.row(),
 7986                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7987                );
 7988            }
 7989        }
 7990
 7991        breakpoint_display_points
 7992    }
 7993
 7994    fn breakpoint_context_menu(
 7995        &self,
 7996        anchor: Anchor,
 7997        window: &mut Window,
 7998        cx: &mut Context<Self>,
 7999    ) -> Entity<ui::ContextMenu> {
 8000        let weak_editor = cx.weak_entity();
 8001        let focus_handle = self.focus_handle(cx);
 8002
 8003        let row = self
 8004            .buffer
 8005            .read(cx)
 8006            .snapshot(cx)
 8007            .summary_for_anchor::<Point>(&anchor)
 8008            .row;
 8009
 8010        let breakpoint = self
 8011            .breakpoint_at_row(row, window, cx)
 8012            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8013
 8014        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8015            "Edit Log Breakpoint"
 8016        } else {
 8017            "Set Log Breakpoint"
 8018        };
 8019
 8020        let condition_breakpoint_msg = if breakpoint
 8021            .as_ref()
 8022            .is_some_and(|bp| bp.1.condition.is_some())
 8023        {
 8024            "Edit Condition Breakpoint"
 8025        } else {
 8026            "Set Condition Breakpoint"
 8027        };
 8028
 8029        let hit_condition_breakpoint_msg = if breakpoint
 8030            .as_ref()
 8031            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8032        {
 8033            "Edit Hit Condition Breakpoint"
 8034        } else {
 8035            "Set Hit Condition Breakpoint"
 8036        };
 8037
 8038        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8039            "Unset Breakpoint"
 8040        } else {
 8041            "Set Breakpoint"
 8042        };
 8043
 8044        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8045
 8046        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8047            BreakpointState::Enabled => Some("Disable"),
 8048            BreakpointState::Disabled => Some("Enable"),
 8049        });
 8050
 8051        let (anchor, breakpoint) =
 8052            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8053
 8054        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8055            menu.on_blur_subscription(Subscription::new(|| {}))
 8056                .context(focus_handle)
 8057                .when(run_to_cursor, |this| {
 8058                    let weak_editor = weak_editor.clone();
 8059                    this.entry("Run to cursor", None, move |window, cx| {
 8060                        weak_editor
 8061                            .update(cx, |editor, cx| {
 8062                                editor.change_selections(
 8063                                    SelectionEffects::no_scroll(),
 8064                                    window,
 8065                                    cx,
 8066                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8067                                );
 8068                            })
 8069                            .ok();
 8070
 8071                        window.dispatch_action(Box::new(RunToCursor), cx);
 8072                    })
 8073                    .separator()
 8074                })
 8075                .when_some(toggle_state_msg, |this, msg| {
 8076                    this.entry(msg, None, {
 8077                        let weak_editor = weak_editor.clone();
 8078                        let breakpoint = breakpoint.clone();
 8079                        move |_window, cx| {
 8080                            weak_editor
 8081                                .update(cx, |this, cx| {
 8082                                    this.edit_breakpoint_at_anchor(
 8083                                        anchor,
 8084                                        breakpoint.as_ref().clone(),
 8085                                        BreakpointEditAction::InvertState,
 8086                                        cx,
 8087                                    );
 8088                                })
 8089                                .log_err();
 8090                        }
 8091                    })
 8092                })
 8093                .entry(set_breakpoint_msg, None, {
 8094                    let weak_editor = weak_editor.clone();
 8095                    let breakpoint = breakpoint.clone();
 8096                    move |_window, cx| {
 8097                        weak_editor
 8098                            .update(cx, |this, cx| {
 8099                                this.edit_breakpoint_at_anchor(
 8100                                    anchor,
 8101                                    breakpoint.as_ref().clone(),
 8102                                    BreakpointEditAction::Toggle,
 8103                                    cx,
 8104                                );
 8105                            })
 8106                            .log_err();
 8107                    }
 8108                })
 8109                .entry(log_breakpoint_msg, None, {
 8110                    let breakpoint = breakpoint.clone();
 8111                    let weak_editor = weak_editor.clone();
 8112                    move |window, cx| {
 8113                        weak_editor
 8114                            .update(cx, |this, cx| {
 8115                                this.add_edit_breakpoint_block(
 8116                                    anchor,
 8117                                    breakpoint.as_ref(),
 8118                                    BreakpointPromptEditAction::Log,
 8119                                    window,
 8120                                    cx,
 8121                                );
 8122                            })
 8123                            .log_err();
 8124                    }
 8125                })
 8126                .entry(condition_breakpoint_msg, None, {
 8127                    let breakpoint = breakpoint.clone();
 8128                    let weak_editor = weak_editor.clone();
 8129                    move |window, cx| {
 8130                        weak_editor
 8131                            .update(cx, |this, cx| {
 8132                                this.add_edit_breakpoint_block(
 8133                                    anchor,
 8134                                    breakpoint.as_ref(),
 8135                                    BreakpointPromptEditAction::Condition,
 8136                                    window,
 8137                                    cx,
 8138                                );
 8139                            })
 8140                            .log_err();
 8141                    }
 8142                })
 8143                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8144                    weak_editor
 8145                        .update(cx, |this, cx| {
 8146                            this.add_edit_breakpoint_block(
 8147                                anchor,
 8148                                breakpoint.as_ref(),
 8149                                BreakpointPromptEditAction::HitCondition,
 8150                                window,
 8151                                cx,
 8152                            );
 8153                        })
 8154                        .log_err();
 8155                })
 8156        })
 8157    }
 8158
 8159    fn render_breakpoint(
 8160        &self,
 8161        position: Anchor,
 8162        row: DisplayRow,
 8163        breakpoint: &Breakpoint,
 8164        state: Option<BreakpointSessionState>,
 8165        cx: &mut Context<Self>,
 8166    ) -> IconButton {
 8167        let is_rejected = state.is_some_and(|s| !s.verified);
 8168        // Is it a breakpoint that shows up when hovering over gutter?
 8169        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8170            (false, false),
 8171            |PhantomBreakpointIndicator {
 8172                 is_active,
 8173                 display_row,
 8174                 collides_with_existing_breakpoint,
 8175             }| {
 8176                (
 8177                    is_active && display_row == row,
 8178                    collides_with_existing_breakpoint,
 8179                )
 8180            },
 8181        );
 8182
 8183        let (color, icon) = {
 8184            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8185                (false, false) => ui::IconName::DebugBreakpoint,
 8186                (true, false) => ui::IconName::DebugLogBreakpoint,
 8187                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8188                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8189            };
 8190
 8191            let color = if is_phantom {
 8192                Color::Hint
 8193            } else if is_rejected {
 8194                Color::Disabled
 8195            } else {
 8196                Color::Debugger
 8197            };
 8198
 8199            (color, icon)
 8200        };
 8201
 8202        let breakpoint = Arc::from(breakpoint.clone());
 8203
 8204        let alt_as_text = gpui::Keystroke {
 8205            modifiers: Modifiers::secondary_key(),
 8206            ..Default::default()
 8207        };
 8208        let primary_action_text = if breakpoint.is_disabled() {
 8209            "Enable breakpoint"
 8210        } else if is_phantom && !collides_with_existing {
 8211            "Set breakpoint"
 8212        } else {
 8213            "Unset breakpoint"
 8214        };
 8215        let focus_handle = self.focus_handle.clone();
 8216
 8217        let meta = if is_rejected {
 8218            SharedString::from("No executable code is associated with this line.")
 8219        } else if collides_with_existing && !breakpoint.is_disabled() {
 8220            SharedString::from(format!(
 8221                "{alt_as_text}-click to disable,\nright-click for more options."
 8222            ))
 8223        } else {
 8224            SharedString::from("Right-click for more options.")
 8225        };
 8226        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8227            .icon_size(IconSize::XSmall)
 8228            .size(ui::ButtonSize::None)
 8229            .when(is_rejected, |this| {
 8230                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8231            })
 8232            .icon_color(color)
 8233            .style(ButtonStyle::Transparent)
 8234            .on_click(cx.listener({
 8235                move |editor, event: &ClickEvent, window, cx| {
 8236                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8237                        BreakpointEditAction::InvertState
 8238                    } else {
 8239                        BreakpointEditAction::Toggle
 8240                    };
 8241
 8242                    window.focus(&editor.focus_handle(cx));
 8243                    editor.edit_breakpoint_at_anchor(
 8244                        position,
 8245                        breakpoint.as_ref().clone(),
 8246                        edit_action,
 8247                        cx,
 8248                    );
 8249                }
 8250            }))
 8251            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8252                editor.set_breakpoint_context_menu(
 8253                    row,
 8254                    Some(position),
 8255                    event.position(),
 8256                    window,
 8257                    cx,
 8258                );
 8259            }))
 8260            .tooltip(move |_window, cx| {
 8261                Tooltip::with_meta_in(
 8262                    primary_action_text,
 8263                    Some(&ToggleBreakpoint),
 8264                    meta.clone(),
 8265                    &focus_handle,
 8266                    cx,
 8267                )
 8268            })
 8269    }
 8270
 8271    fn build_tasks_context(
 8272        project: &Entity<Project>,
 8273        buffer: &Entity<Buffer>,
 8274        buffer_row: u32,
 8275        tasks: &Arc<RunnableTasks>,
 8276        cx: &mut Context<Self>,
 8277    ) -> Task<Option<task::TaskContext>> {
 8278        let position = Point::new(buffer_row, tasks.column);
 8279        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8280        let location = Location {
 8281            buffer: buffer.clone(),
 8282            range: range_start..range_start,
 8283        };
 8284        // Fill in the environmental variables from the tree-sitter captures
 8285        let mut captured_task_variables = TaskVariables::default();
 8286        for (capture_name, value) in tasks.extra_variables.clone() {
 8287            captured_task_variables.insert(
 8288                task::VariableName::Custom(capture_name.into()),
 8289                value.clone(),
 8290            );
 8291        }
 8292        project.update(cx, |project, cx| {
 8293            project.task_store().update(cx, |task_store, cx| {
 8294                task_store.task_context_for_location(captured_task_variables, location, cx)
 8295            })
 8296        })
 8297    }
 8298
 8299    pub fn spawn_nearest_task(
 8300        &mut self,
 8301        action: &SpawnNearestTask,
 8302        window: &mut Window,
 8303        cx: &mut Context<Self>,
 8304    ) {
 8305        let Some((workspace, _)) = self.workspace.clone() else {
 8306            return;
 8307        };
 8308        let Some(project) = self.project.clone() else {
 8309            return;
 8310        };
 8311
 8312        // Try to find a closest, enclosing node using tree-sitter that has a task
 8313        let Some((buffer, buffer_row, tasks)) = self
 8314            .find_enclosing_node_task(cx)
 8315            // Or find the task that's closest in row-distance.
 8316            .or_else(|| self.find_closest_task(cx))
 8317        else {
 8318            return;
 8319        };
 8320
 8321        let reveal_strategy = action.reveal;
 8322        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8323        cx.spawn_in(window, async move |_, cx| {
 8324            let context = task_context.await?;
 8325            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8326
 8327            let resolved = &mut resolved_task.resolved;
 8328            resolved.reveal = reveal_strategy;
 8329
 8330            workspace
 8331                .update_in(cx, |workspace, window, cx| {
 8332                    workspace.schedule_resolved_task(
 8333                        task_source_kind,
 8334                        resolved_task,
 8335                        false,
 8336                        window,
 8337                        cx,
 8338                    );
 8339                })
 8340                .ok()
 8341        })
 8342        .detach();
 8343    }
 8344
 8345    fn find_closest_task(
 8346        &mut self,
 8347        cx: &mut Context<Self>,
 8348    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8349        let cursor_row = self
 8350            .selections
 8351            .newest_adjusted(&self.display_snapshot(cx))
 8352            .head()
 8353            .row;
 8354
 8355        let ((buffer_id, row), tasks) = self
 8356            .tasks
 8357            .iter()
 8358            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8359
 8360        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8361        let tasks = Arc::new(tasks.to_owned());
 8362        Some((buffer, *row, tasks))
 8363    }
 8364
 8365    fn find_enclosing_node_task(
 8366        &mut self,
 8367        cx: &mut Context<Self>,
 8368    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8369        let snapshot = self.buffer.read(cx).snapshot(cx);
 8370        let offset = self
 8371            .selections
 8372            .newest::<usize>(&self.display_snapshot(cx))
 8373            .head();
 8374        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8375        let buffer_id = excerpt.buffer().remote_id();
 8376
 8377        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8378        let mut cursor = layer.node().walk();
 8379
 8380        while cursor.goto_first_child_for_byte(offset).is_some() {
 8381            if cursor.node().end_byte() == offset {
 8382                cursor.goto_next_sibling();
 8383            }
 8384        }
 8385
 8386        // Ascend to the smallest ancestor that contains the range and has a task.
 8387        loop {
 8388            let node = cursor.node();
 8389            let node_range = node.byte_range();
 8390            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8391
 8392            // Check if this node contains our offset
 8393            if node_range.start <= offset && node_range.end >= offset {
 8394                // If it contains offset, check for task
 8395                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8396                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8397                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8398                }
 8399            }
 8400
 8401            if !cursor.goto_parent() {
 8402                break;
 8403            }
 8404        }
 8405        None
 8406    }
 8407
 8408    fn render_run_indicator(
 8409        &self,
 8410        _style: &EditorStyle,
 8411        is_active: bool,
 8412        row: DisplayRow,
 8413        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8414        cx: &mut Context<Self>,
 8415    ) -> IconButton {
 8416        let color = Color::Muted;
 8417        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8418
 8419        IconButton::new(
 8420            ("run_indicator", row.0 as usize),
 8421            ui::IconName::PlayOutlined,
 8422        )
 8423        .shape(ui::IconButtonShape::Square)
 8424        .icon_size(IconSize::XSmall)
 8425        .icon_color(color)
 8426        .toggle_state(is_active)
 8427        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8428            let quick_launch = match e {
 8429                ClickEvent::Keyboard(_) => true,
 8430                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8431            };
 8432
 8433            window.focus(&editor.focus_handle(cx));
 8434            editor.toggle_code_actions(
 8435                &ToggleCodeActions {
 8436                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8437                    quick_launch,
 8438                },
 8439                window,
 8440                cx,
 8441            );
 8442        }))
 8443        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8444            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8445        }))
 8446    }
 8447
 8448    pub fn context_menu_visible(&self) -> bool {
 8449        !self.edit_prediction_preview_is_active()
 8450            && self
 8451                .context_menu
 8452                .borrow()
 8453                .as_ref()
 8454                .is_some_and(|menu| menu.visible())
 8455    }
 8456
 8457    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8458        self.context_menu
 8459            .borrow()
 8460            .as_ref()
 8461            .map(|menu| menu.origin())
 8462    }
 8463
 8464    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8465        self.context_menu_options = Some(options);
 8466    }
 8467
 8468    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8469    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8470
 8471    fn render_edit_prediction_popover(
 8472        &mut self,
 8473        text_bounds: &Bounds<Pixels>,
 8474        content_origin: gpui::Point<Pixels>,
 8475        right_margin: Pixels,
 8476        editor_snapshot: &EditorSnapshot,
 8477        visible_row_range: Range<DisplayRow>,
 8478        scroll_top: ScrollOffset,
 8479        scroll_bottom: ScrollOffset,
 8480        line_layouts: &[LineWithInvisibles],
 8481        line_height: Pixels,
 8482        scroll_position: gpui::Point<ScrollOffset>,
 8483        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8484        newest_selection_head: Option<DisplayPoint>,
 8485        editor_width: Pixels,
 8486        style: &EditorStyle,
 8487        window: &mut Window,
 8488        cx: &mut App,
 8489    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8490        if self.mode().is_minimap() {
 8491            return None;
 8492        }
 8493        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8494
 8495        if self.edit_prediction_visible_in_cursor_popover(true) {
 8496            return None;
 8497        }
 8498
 8499        match &active_edit_prediction.completion {
 8500            EditPrediction::MoveWithin { target, .. } => {
 8501                let target_display_point = target.to_display_point(editor_snapshot);
 8502
 8503                if self.edit_prediction_requires_modifier() {
 8504                    if !self.edit_prediction_preview_is_active() {
 8505                        return None;
 8506                    }
 8507
 8508                    self.render_edit_prediction_modifier_jump_popover(
 8509                        text_bounds,
 8510                        content_origin,
 8511                        visible_row_range,
 8512                        line_layouts,
 8513                        line_height,
 8514                        scroll_pixel_position,
 8515                        newest_selection_head,
 8516                        target_display_point,
 8517                        window,
 8518                        cx,
 8519                    )
 8520                } else {
 8521                    self.render_edit_prediction_eager_jump_popover(
 8522                        text_bounds,
 8523                        content_origin,
 8524                        editor_snapshot,
 8525                        visible_row_range,
 8526                        scroll_top,
 8527                        scroll_bottom,
 8528                        line_height,
 8529                        scroll_pixel_position,
 8530                        target_display_point,
 8531                        editor_width,
 8532                        window,
 8533                        cx,
 8534                    )
 8535                }
 8536            }
 8537            EditPrediction::Edit {
 8538                display_mode: EditDisplayMode::Inline,
 8539                ..
 8540            } => None,
 8541            EditPrediction::Edit {
 8542                display_mode: EditDisplayMode::TabAccept,
 8543                edits,
 8544                ..
 8545            } => {
 8546                let range = &edits.first()?.0;
 8547                let target_display_point = range.end.to_display_point(editor_snapshot);
 8548
 8549                self.render_edit_prediction_end_of_line_popover(
 8550                    "Accept",
 8551                    editor_snapshot,
 8552                    visible_row_range,
 8553                    target_display_point,
 8554                    line_height,
 8555                    scroll_pixel_position,
 8556                    content_origin,
 8557                    editor_width,
 8558                    window,
 8559                    cx,
 8560                )
 8561            }
 8562            EditPrediction::Edit {
 8563                edits,
 8564                edit_preview,
 8565                display_mode: EditDisplayMode::DiffPopover,
 8566                snapshot,
 8567            } => self.render_edit_prediction_diff_popover(
 8568                text_bounds,
 8569                content_origin,
 8570                right_margin,
 8571                editor_snapshot,
 8572                visible_row_range,
 8573                line_layouts,
 8574                line_height,
 8575                scroll_position,
 8576                scroll_pixel_position,
 8577                newest_selection_head,
 8578                editor_width,
 8579                style,
 8580                edits,
 8581                edit_preview,
 8582                snapshot,
 8583                window,
 8584                cx,
 8585            ),
 8586            EditPrediction::MoveOutside { snapshot, .. } => {
 8587                let file_name = snapshot
 8588                    .file()
 8589                    .map(|file| file.file_name(cx))
 8590                    .unwrap_or("untitled");
 8591                let mut element = self
 8592                    .render_edit_prediction_line_popover(
 8593                        format!("Jump to {file_name}"),
 8594                        Some(IconName::ZedPredict),
 8595                        window,
 8596                        cx,
 8597                    )
 8598                    .into_any();
 8599
 8600                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8601                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8602                let origin_y = text_bounds.size.height - size.height - px(30.);
 8603                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8604                element.prepaint_at(origin, window, cx);
 8605
 8606                Some((element, origin))
 8607            }
 8608        }
 8609    }
 8610
 8611    fn render_edit_prediction_modifier_jump_popover(
 8612        &mut self,
 8613        text_bounds: &Bounds<Pixels>,
 8614        content_origin: gpui::Point<Pixels>,
 8615        visible_row_range: Range<DisplayRow>,
 8616        line_layouts: &[LineWithInvisibles],
 8617        line_height: Pixels,
 8618        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8619        newest_selection_head: Option<DisplayPoint>,
 8620        target_display_point: DisplayPoint,
 8621        window: &mut Window,
 8622        cx: &mut App,
 8623    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8624        let scrolled_content_origin =
 8625            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8626
 8627        const SCROLL_PADDING_Y: Pixels = px(12.);
 8628
 8629        if target_display_point.row() < visible_row_range.start {
 8630            return self.render_edit_prediction_scroll_popover(
 8631                |_| SCROLL_PADDING_Y,
 8632                IconName::ArrowUp,
 8633                visible_row_range,
 8634                line_layouts,
 8635                newest_selection_head,
 8636                scrolled_content_origin,
 8637                window,
 8638                cx,
 8639            );
 8640        } else if target_display_point.row() >= visible_row_range.end {
 8641            return self.render_edit_prediction_scroll_popover(
 8642                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8643                IconName::ArrowDown,
 8644                visible_row_range,
 8645                line_layouts,
 8646                newest_selection_head,
 8647                scrolled_content_origin,
 8648                window,
 8649                cx,
 8650            );
 8651        }
 8652
 8653        const POLE_WIDTH: Pixels = px(2.);
 8654
 8655        let line_layout =
 8656            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8657        let target_column = target_display_point.column() as usize;
 8658
 8659        let target_x = line_layout.x_for_index(target_column);
 8660        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8661            - scroll_pixel_position.y;
 8662
 8663        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8664
 8665        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8666        border_color.l += 0.001;
 8667
 8668        let mut element = v_flex()
 8669            .items_end()
 8670            .when(flag_on_right, |el| el.items_start())
 8671            .child(if flag_on_right {
 8672                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8673                    .rounded_bl(px(0.))
 8674                    .rounded_tl(px(0.))
 8675                    .border_l_2()
 8676                    .border_color(border_color)
 8677            } else {
 8678                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8679                    .rounded_br(px(0.))
 8680                    .rounded_tr(px(0.))
 8681                    .border_r_2()
 8682                    .border_color(border_color)
 8683            })
 8684            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8685            .into_any();
 8686
 8687        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8688
 8689        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8690            - point(
 8691                if flag_on_right {
 8692                    POLE_WIDTH
 8693                } else {
 8694                    size.width - POLE_WIDTH
 8695                },
 8696                size.height - line_height,
 8697            );
 8698
 8699        origin.x = origin.x.max(content_origin.x);
 8700
 8701        element.prepaint_at(origin, window, cx);
 8702
 8703        Some((element, origin))
 8704    }
 8705
 8706    fn render_edit_prediction_scroll_popover(
 8707        &mut self,
 8708        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8709        scroll_icon: IconName,
 8710        visible_row_range: Range<DisplayRow>,
 8711        line_layouts: &[LineWithInvisibles],
 8712        newest_selection_head: Option<DisplayPoint>,
 8713        scrolled_content_origin: gpui::Point<Pixels>,
 8714        window: &mut Window,
 8715        cx: &mut App,
 8716    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8717        let mut element = self
 8718            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8719            .into_any();
 8720
 8721        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8722
 8723        let cursor = newest_selection_head?;
 8724        let cursor_row_layout =
 8725            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8726        let cursor_column = cursor.column() as usize;
 8727
 8728        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8729
 8730        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8731
 8732        element.prepaint_at(origin, window, cx);
 8733        Some((element, origin))
 8734    }
 8735
 8736    fn render_edit_prediction_eager_jump_popover(
 8737        &mut self,
 8738        text_bounds: &Bounds<Pixels>,
 8739        content_origin: gpui::Point<Pixels>,
 8740        editor_snapshot: &EditorSnapshot,
 8741        visible_row_range: Range<DisplayRow>,
 8742        scroll_top: ScrollOffset,
 8743        scroll_bottom: ScrollOffset,
 8744        line_height: Pixels,
 8745        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8746        target_display_point: DisplayPoint,
 8747        editor_width: Pixels,
 8748        window: &mut Window,
 8749        cx: &mut App,
 8750    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8751        if target_display_point.row().as_f64() < scroll_top {
 8752            let mut element = self
 8753                .render_edit_prediction_line_popover(
 8754                    "Jump to Edit",
 8755                    Some(IconName::ArrowUp),
 8756                    window,
 8757                    cx,
 8758                )
 8759                .into_any();
 8760
 8761            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8762            let offset = point(
 8763                (text_bounds.size.width - size.width) / 2.,
 8764                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8765            );
 8766
 8767            let origin = text_bounds.origin + offset;
 8768            element.prepaint_at(origin, window, cx);
 8769            Some((element, origin))
 8770        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8771            let mut element = self
 8772                .render_edit_prediction_line_popover(
 8773                    "Jump to Edit",
 8774                    Some(IconName::ArrowDown),
 8775                    window,
 8776                    cx,
 8777                )
 8778                .into_any();
 8779
 8780            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8781            let offset = point(
 8782                (text_bounds.size.width - size.width) / 2.,
 8783                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8784            );
 8785
 8786            let origin = text_bounds.origin + offset;
 8787            element.prepaint_at(origin, window, cx);
 8788            Some((element, origin))
 8789        } else {
 8790            self.render_edit_prediction_end_of_line_popover(
 8791                "Jump to Edit",
 8792                editor_snapshot,
 8793                visible_row_range,
 8794                target_display_point,
 8795                line_height,
 8796                scroll_pixel_position,
 8797                content_origin,
 8798                editor_width,
 8799                window,
 8800                cx,
 8801            )
 8802        }
 8803    }
 8804
 8805    fn render_edit_prediction_end_of_line_popover(
 8806        self: &mut Editor,
 8807        label: &'static str,
 8808        editor_snapshot: &EditorSnapshot,
 8809        visible_row_range: Range<DisplayRow>,
 8810        target_display_point: DisplayPoint,
 8811        line_height: Pixels,
 8812        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8813        content_origin: gpui::Point<Pixels>,
 8814        editor_width: Pixels,
 8815        window: &mut Window,
 8816        cx: &mut App,
 8817    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8818        let target_line_end = DisplayPoint::new(
 8819            target_display_point.row(),
 8820            editor_snapshot.line_len(target_display_point.row()),
 8821        );
 8822
 8823        let mut element = self
 8824            .render_edit_prediction_line_popover(label, None, window, cx)
 8825            .into_any();
 8826
 8827        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8828
 8829        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8830
 8831        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8832        let mut origin = start_point
 8833            + line_origin
 8834            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8835        origin.x = origin.x.max(content_origin.x);
 8836
 8837        let max_x = content_origin.x + editor_width - size.width;
 8838
 8839        if origin.x > max_x {
 8840            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8841
 8842            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8843                origin.y += offset;
 8844                IconName::ArrowUp
 8845            } else {
 8846                origin.y -= offset;
 8847                IconName::ArrowDown
 8848            };
 8849
 8850            element = self
 8851                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 8852                .into_any();
 8853
 8854            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8855
 8856            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8857        }
 8858
 8859        element.prepaint_at(origin, window, cx);
 8860        Some((element, origin))
 8861    }
 8862
 8863    fn render_edit_prediction_diff_popover(
 8864        self: &Editor,
 8865        text_bounds: &Bounds<Pixels>,
 8866        content_origin: gpui::Point<Pixels>,
 8867        right_margin: Pixels,
 8868        editor_snapshot: &EditorSnapshot,
 8869        visible_row_range: Range<DisplayRow>,
 8870        line_layouts: &[LineWithInvisibles],
 8871        line_height: Pixels,
 8872        scroll_position: gpui::Point<ScrollOffset>,
 8873        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8874        newest_selection_head: Option<DisplayPoint>,
 8875        editor_width: Pixels,
 8876        style: &EditorStyle,
 8877        edits: &Vec<(Range<Anchor>, String)>,
 8878        edit_preview: &Option<language::EditPreview>,
 8879        snapshot: &language::BufferSnapshot,
 8880        window: &mut Window,
 8881        cx: &mut App,
 8882    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8883        let edit_start = edits
 8884            .first()
 8885            .unwrap()
 8886            .0
 8887            .start
 8888            .to_display_point(editor_snapshot);
 8889        let edit_end = edits
 8890            .last()
 8891            .unwrap()
 8892            .0
 8893            .end
 8894            .to_display_point(editor_snapshot);
 8895
 8896        let is_visible = visible_row_range.contains(&edit_start.row())
 8897            || visible_row_range.contains(&edit_end.row());
 8898        if !is_visible {
 8899            return None;
 8900        }
 8901
 8902        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8903            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8904        } else {
 8905            // Fallback for providers without edit_preview
 8906            crate::edit_prediction_fallback_text(edits, cx)
 8907        };
 8908
 8909        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8910        let line_count = highlighted_edits.text.lines().count();
 8911
 8912        const BORDER_WIDTH: Pixels = px(1.);
 8913
 8914        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8915        let has_keybind = keybind.is_some();
 8916
 8917        let mut element = h_flex()
 8918            .items_start()
 8919            .child(
 8920                h_flex()
 8921                    .bg(cx.theme().colors().editor_background)
 8922                    .border(BORDER_WIDTH)
 8923                    .shadow_xs()
 8924                    .border_color(cx.theme().colors().border)
 8925                    .rounded_l_lg()
 8926                    .when(line_count > 1, |el| el.rounded_br_lg())
 8927                    .pr_1()
 8928                    .child(styled_text),
 8929            )
 8930            .child(
 8931                h_flex()
 8932                    .h(line_height + BORDER_WIDTH * 2.)
 8933                    .px_1p5()
 8934                    .gap_1()
 8935                    // Workaround: For some reason, there's a gap if we don't do this
 8936                    .ml(-BORDER_WIDTH)
 8937                    .shadow(vec![gpui::BoxShadow {
 8938                        color: gpui::black().opacity(0.05),
 8939                        offset: point(px(1.), px(1.)),
 8940                        blur_radius: px(2.),
 8941                        spread_radius: px(0.),
 8942                    }])
 8943                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8944                    .border(BORDER_WIDTH)
 8945                    .border_color(cx.theme().colors().border)
 8946                    .rounded_r_lg()
 8947                    .id("edit_prediction_diff_popover_keybind")
 8948                    .when(!has_keybind, |el| {
 8949                        let status_colors = cx.theme().status();
 8950
 8951                        el.bg(status_colors.error_background)
 8952                            .border_color(status_colors.error.opacity(0.6))
 8953                            .child(Icon::new(IconName::Info).color(Color::Error))
 8954                            .cursor_default()
 8955                            .hoverable_tooltip(move |_window, cx| {
 8956                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8957                            })
 8958                    })
 8959                    .children(keybind),
 8960            )
 8961            .into_any();
 8962
 8963        let longest_row =
 8964            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8965        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8966            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8967        } else {
 8968            layout_line(
 8969                longest_row,
 8970                editor_snapshot,
 8971                style,
 8972                editor_width,
 8973                |_| false,
 8974                window,
 8975                cx,
 8976            )
 8977            .width
 8978        };
 8979
 8980        let viewport_bounds =
 8981            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8982                right: -right_margin,
 8983                ..Default::default()
 8984            });
 8985
 8986        let x_after_longest = Pixels::from(
 8987            ScrollPixelOffset::from(
 8988                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 8989            ) - scroll_pixel_position.x,
 8990        );
 8991
 8992        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8993
 8994        // Fully visible if it can be displayed within the window (allow overlapping other
 8995        // panes). However, this is only allowed if the popover starts within text_bounds.
 8996        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8997            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8998
 8999        let mut origin = if can_position_to_the_right {
 9000            point(
 9001                x_after_longest,
 9002                text_bounds.origin.y
 9003                    + Pixels::from(
 9004                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9005                            - scroll_pixel_position.y,
 9006                    ),
 9007            )
 9008        } else {
 9009            let cursor_row = newest_selection_head.map(|head| head.row());
 9010            let above_edit = edit_start
 9011                .row()
 9012                .0
 9013                .checked_sub(line_count as u32)
 9014                .map(DisplayRow);
 9015            let below_edit = Some(edit_end.row() + 1);
 9016            let above_cursor =
 9017                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9018            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9019
 9020            // Place the edit popover adjacent to the edit if there is a location
 9021            // available that is onscreen and does not obscure the cursor. Otherwise,
 9022            // place it adjacent to the cursor.
 9023            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9024                .into_iter()
 9025                .flatten()
 9026                .find(|&start_row| {
 9027                    let end_row = start_row + line_count as u32;
 9028                    visible_row_range.contains(&start_row)
 9029                        && visible_row_range.contains(&end_row)
 9030                        && cursor_row
 9031                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9032                })?;
 9033
 9034            content_origin
 9035                + point(
 9036                    Pixels::from(-scroll_pixel_position.x),
 9037                    Pixels::from(
 9038                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9039                    ),
 9040                )
 9041        };
 9042
 9043        origin.x -= BORDER_WIDTH;
 9044
 9045        window.defer_draw(element, origin, 1);
 9046
 9047        // Do not return an element, since it will already be drawn due to defer_draw.
 9048        None
 9049    }
 9050
 9051    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9052        px(30.)
 9053    }
 9054
 9055    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9056        if self.read_only(cx) {
 9057            cx.theme().players().read_only()
 9058        } else {
 9059            self.style.as_ref().unwrap().local_player
 9060        }
 9061    }
 9062
 9063    fn render_edit_prediction_accept_keybind(
 9064        &self,
 9065        window: &mut Window,
 9066        cx: &mut App,
 9067    ) -> Option<AnyElement> {
 9068        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9069        let accept_keystroke = accept_binding.keystroke()?;
 9070
 9071        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9072
 9073        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9074            Color::Accent
 9075        } else {
 9076            Color::Muted
 9077        };
 9078
 9079        h_flex()
 9080            .px_0p5()
 9081            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9082            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9083            .text_size(TextSize::XSmall.rems(cx))
 9084            .child(h_flex().children(ui::render_modifiers(
 9085                accept_keystroke.modifiers(),
 9086                PlatformStyle::platform(),
 9087                Some(modifiers_color),
 9088                Some(IconSize::XSmall.rems().into()),
 9089                true,
 9090            )))
 9091            .when(is_platform_style_mac, |parent| {
 9092                parent.child(accept_keystroke.key().to_string())
 9093            })
 9094            .when(!is_platform_style_mac, |parent| {
 9095                parent.child(
 9096                    Key::new(
 9097                        util::capitalize(accept_keystroke.key()),
 9098                        Some(Color::Default),
 9099                    )
 9100                    .size(Some(IconSize::XSmall.rems().into())),
 9101                )
 9102            })
 9103            .into_any()
 9104            .into()
 9105    }
 9106
 9107    fn render_edit_prediction_line_popover(
 9108        &self,
 9109        label: impl Into<SharedString>,
 9110        icon: Option<IconName>,
 9111        window: &mut Window,
 9112        cx: &mut App,
 9113    ) -> Stateful<Div> {
 9114        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9115
 9116        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9117        let has_keybind = keybind.is_some();
 9118
 9119        h_flex()
 9120            .id("ep-line-popover")
 9121            .py_0p5()
 9122            .pl_1()
 9123            .pr(padding_right)
 9124            .gap_1()
 9125            .rounded_md()
 9126            .border_1()
 9127            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9128            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9129            .shadow_xs()
 9130            .when(!has_keybind, |el| {
 9131                let status_colors = cx.theme().status();
 9132
 9133                el.bg(status_colors.error_background)
 9134                    .border_color(status_colors.error.opacity(0.6))
 9135                    .pl_2()
 9136                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9137                    .cursor_default()
 9138                    .hoverable_tooltip(move |_window, cx| {
 9139                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9140                    })
 9141            })
 9142            .children(keybind)
 9143            .child(
 9144                Label::new(label)
 9145                    .size(LabelSize::Small)
 9146                    .when(!has_keybind, |el| {
 9147                        el.color(cx.theme().status().error.into()).strikethrough()
 9148                    }),
 9149            )
 9150            .when(!has_keybind, |el| {
 9151                el.child(
 9152                    h_flex().ml_1().child(
 9153                        Icon::new(IconName::Info)
 9154                            .size(IconSize::Small)
 9155                            .color(cx.theme().status().error.into()),
 9156                    ),
 9157                )
 9158            })
 9159            .when_some(icon, |element, icon| {
 9160                element.child(
 9161                    div()
 9162                        .mt(px(1.5))
 9163                        .child(Icon::new(icon).size(IconSize::Small)),
 9164                )
 9165            })
 9166    }
 9167
 9168    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9169        let accent_color = cx.theme().colors().text_accent;
 9170        let editor_bg_color = cx.theme().colors().editor_background;
 9171        editor_bg_color.blend(accent_color.opacity(0.1))
 9172    }
 9173
 9174    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9175        let accent_color = cx.theme().colors().text_accent;
 9176        let editor_bg_color = cx.theme().colors().editor_background;
 9177        editor_bg_color.blend(accent_color.opacity(0.6))
 9178    }
 9179    fn get_prediction_provider_icon_name(
 9180        provider: &Option<RegisteredEditPredictionProvider>,
 9181    ) -> IconName {
 9182        match provider {
 9183            Some(provider) => match provider.provider.name() {
 9184                "copilot" => IconName::Copilot,
 9185                "supermaven" => IconName::Supermaven,
 9186                _ => IconName::ZedPredict,
 9187            },
 9188            None => IconName::ZedPredict,
 9189        }
 9190    }
 9191
 9192    fn render_edit_prediction_cursor_popover(
 9193        &self,
 9194        min_width: Pixels,
 9195        max_width: Pixels,
 9196        cursor_point: Point,
 9197        style: &EditorStyle,
 9198        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9199        _window: &Window,
 9200        cx: &mut Context<Editor>,
 9201    ) -> Option<AnyElement> {
 9202        let provider = self.edit_prediction_provider.as_ref()?;
 9203        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9204
 9205        let is_refreshing = provider.provider.is_refreshing(cx);
 9206
 9207        fn pending_completion_container(icon: IconName) -> Div {
 9208            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9209        }
 9210
 9211        let completion = match &self.active_edit_prediction {
 9212            Some(prediction) => {
 9213                if !self.has_visible_completions_menu() {
 9214                    const RADIUS: Pixels = px(6.);
 9215                    const BORDER_WIDTH: Pixels = px(1.);
 9216
 9217                    return Some(
 9218                        h_flex()
 9219                            .elevation_2(cx)
 9220                            .border(BORDER_WIDTH)
 9221                            .border_color(cx.theme().colors().border)
 9222                            .when(accept_keystroke.is_none(), |el| {
 9223                                el.border_color(cx.theme().status().error)
 9224                            })
 9225                            .rounded(RADIUS)
 9226                            .rounded_tl(px(0.))
 9227                            .overflow_hidden()
 9228                            .child(div().px_1p5().child(match &prediction.completion {
 9229                                EditPrediction::MoveWithin { target, snapshot } => {
 9230                                    use text::ToPoint as _;
 9231                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9232                                    {
 9233                                        Icon::new(IconName::ZedPredictDown)
 9234                                    } else {
 9235                                        Icon::new(IconName::ZedPredictUp)
 9236                                    }
 9237                                }
 9238                                EditPrediction::MoveOutside { .. } => {
 9239                                    // TODO [zeta2] custom icon for external jump?
 9240                                    Icon::new(provider_icon)
 9241                                }
 9242                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9243                            }))
 9244                            .child(
 9245                                h_flex()
 9246                                    .gap_1()
 9247                                    .py_1()
 9248                                    .px_2()
 9249                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9250                                    .border_l_1()
 9251                                    .border_color(cx.theme().colors().border)
 9252                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9253                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9254                                        el.child(
 9255                                            Label::new("Hold")
 9256                                                .size(LabelSize::Small)
 9257                                                .when(accept_keystroke.is_none(), |el| {
 9258                                                    el.strikethrough()
 9259                                                })
 9260                                                .line_height_style(LineHeightStyle::UiLabel),
 9261                                        )
 9262                                    })
 9263                                    .id("edit_prediction_cursor_popover_keybind")
 9264                                    .when(accept_keystroke.is_none(), |el| {
 9265                                        let status_colors = cx.theme().status();
 9266
 9267                                        el.bg(status_colors.error_background)
 9268                                            .border_color(status_colors.error.opacity(0.6))
 9269                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9270                                            .cursor_default()
 9271                                            .hoverable_tooltip(move |_window, cx| {
 9272                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9273                                                    .into()
 9274                                            })
 9275                                    })
 9276                                    .when_some(
 9277                                        accept_keystroke.as_ref(),
 9278                                        |el, accept_keystroke| {
 9279                                            el.child(h_flex().children(ui::render_modifiers(
 9280                                                accept_keystroke.modifiers(),
 9281                                                PlatformStyle::platform(),
 9282                                                Some(Color::Default),
 9283                                                Some(IconSize::XSmall.rems().into()),
 9284                                                false,
 9285                                            )))
 9286                                        },
 9287                                    ),
 9288                            )
 9289                            .into_any(),
 9290                    );
 9291                }
 9292
 9293                self.render_edit_prediction_cursor_popover_preview(
 9294                    prediction,
 9295                    cursor_point,
 9296                    style,
 9297                    cx,
 9298                )?
 9299            }
 9300
 9301            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9302                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9303                    stale_completion,
 9304                    cursor_point,
 9305                    style,
 9306                    cx,
 9307                )?,
 9308
 9309                None => pending_completion_container(provider_icon)
 9310                    .child(Label::new("...").size(LabelSize::Small)),
 9311            },
 9312
 9313            None => pending_completion_container(provider_icon)
 9314                .child(Label::new("...").size(LabelSize::Small)),
 9315        };
 9316
 9317        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9318            completion
 9319                .with_animation(
 9320                    "loading-completion",
 9321                    Animation::new(Duration::from_secs(2))
 9322                        .repeat()
 9323                        .with_easing(pulsating_between(0.4, 0.8)),
 9324                    |label, delta| label.opacity(delta),
 9325                )
 9326                .into_any_element()
 9327        } else {
 9328            completion.into_any_element()
 9329        };
 9330
 9331        let has_completion = self.active_edit_prediction.is_some();
 9332
 9333        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9334        Some(
 9335            h_flex()
 9336                .min_w(min_width)
 9337                .max_w(max_width)
 9338                .flex_1()
 9339                .elevation_2(cx)
 9340                .border_color(cx.theme().colors().border)
 9341                .child(
 9342                    div()
 9343                        .flex_1()
 9344                        .py_1()
 9345                        .px_2()
 9346                        .overflow_hidden()
 9347                        .child(completion),
 9348                )
 9349                .when_some(accept_keystroke, |el, accept_keystroke| {
 9350                    if !accept_keystroke.modifiers().modified() {
 9351                        return el;
 9352                    }
 9353
 9354                    el.child(
 9355                        h_flex()
 9356                            .h_full()
 9357                            .border_l_1()
 9358                            .rounded_r_lg()
 9359                            .border_color(cx.theme().colors().border)
 9360                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9361                            .gap_1()
 9362                            .py_1()
 9363                            .px_2()
 9364                            .child(
 9365                                h_flex()
 9366                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9367                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9368                                    .child(h_flex().children(ui::render_modifiers(
 9369                                        accept_keystroke.modifiers(),
 9370                                        PlatformStyle::platform(),
 9371                                        Some(if !has_completion {
 9372                                            Color::Muted
 9373                                        } else {
 9374                                            Color::Default
 9375                                        }),
 9376                                        None,
 9377                                        false,
 9378                                    ))),
 9379                            )
 9380                            .child(Label::new("Preview").into_any_element())
 9381                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9382                    )
 9383                })
 9384                .into_any(),
 9385        )
 9386    }
 9387
 9388    fn render_edit_prediction_cursor_popover_preview(
 9389        &self,
 9390        completion: &EditPredictionState,
 9391        cursor_point: Point,
 9392        style: &EditorStyle,
 9393        cx: &mut Context<Editor>,
 9394    ) -> Option<Div> {
 9395        use text::ToPoint as _;
 9396
 9397        fn render_relative_row_jump(
 9398            prefix: impl Into<String>,
 9399            current_row: u32,
 9400            target_row: u32,
 9401        ) -> Div {
 9402            let (row_diff, arrow) = if target_row < current_row {
 9403                (current_row - target_row, IconName::ArrowUp)
 9404            } else {
 9405                (target_row - current_row, IconName::ArrowDown)
 9406            };
 9407
 9408            h_flex()
 9409                .child(
 9410                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9411                        .color(Color::Muted)
 9412                        .size(LabelSize::Small),
 9413                )
 9414                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9415        }
 9416
 9417        let supports_jump = self
 9418            .edit_prediction_provider
 9419            .as_ref()
 9420            .map(|provider| provider.provider.supports_jump_to_edit())
 9421            .unwrap_or(true);
 9422
 9423        match &completion.completion {
 9424            EditPrediction::MoveWithin {
 9425                target, snapshot, ..
 9426            } => {
 9427                if !supports_jump {
 9428                    return None;
 9429                }
 9430
 9431                Some(
 9432                    h_flex()
 9433                        .px_2()
 9434                        .gap_2()
 9435                        .flex_1()
 9436                        .child(
 9437                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9438                                Icon::new(IconName::ZedPredictDown)
 9439                            } else {
 9440                                Icon::new(IconName::ZedPredictUp)
 9441                            },
 9442                        )
 9443                        .child(Label::new("Jump to Edit")),
 9444                )
 9445            }
 9446            EditPrediction::MoveOutside { snapshot, .. } => {
 9447                let file_name = snapshot
 9448                    .file()
 9449                    .map(|file| file.file_name(cx))
 9450                    .unwrap_or("untitled");
 9451                Some(
 9452                    h_flex()
 9453                        .px_2()
 9454                        .gap_2()
 9455                        .flex_1()
 9456                        .child(Icon::new(IconName::ZedPredict))
 9457                        .child(Label::new(format!("Jump to {file_name}"))),
 9458                )
 9459            }
 9460            EditPrediction::Edit {
 9461                edits,
 9462                edit_preview,
 9463                snapshot,
 9464                display_mode: _,
 9465            } => {
 9466                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9467
 9468                let (highlighted_edits, has_more_lines) =
 9469                    if let Some(edit_preview) = edit_preview.as_ref() {
 9470                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9471                            .first_line_preview()
 9472                    } else {
 9473                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9474                    };
 9475
 9476                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9477                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9478
 9479                let preview = h_flex()
 9480                    .gap_1()
 9481                    .min_w_16()
 9482                    .child(styled_text)
 9483                    .when(has_more_lines, |parent| parent.child("…"));
 9484
 9485                let left = if supports_jump && first_edit_row != cursor_point.row {
 9486                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9487                        .into_any_element()
 9488                } else {
 9489                    let icon_name =
 9490                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9491                    Icon::new(icon_name).into_any_element()
 9492                };
 9493
 9494                Some(
 9495                    h_flex()
 9496                        .h_full()
 9497                        .flex_1()
 9498                        .gap_2()
 9499                        .pr_1()
 9500                        .overflow_x_hidden()
 9501                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9502                        .child(left)
 9503                        .child(preview),
 9504                )
 9505            }
 9506        }
 9507    }
 9508
 9509    pub fn render_context_menu(
 9510        &self,
 9511        style: &EditorStyle,
 9512        max_height_in_lines: u32,
 9513        window: &mut Window,
 9514        cx: &mut Context<Editor>,
 9515    ) -> Option<AnyElement> {
 9516        let menu = self.context_menu.borrow();
 9517        let menu = menu.as_ref()?;
 9518        if !menu.visible() {
 9519            return None;
 9520        };
 9521        Some(menu.render(style, max_height_in_lines, window, cx))
 9522    }
 9523
 9524    fn render_context_menu_aside(
 9525        &mut self,
 9526        max_size: Size<Pixels>,
 9527        window: &mut Window,
 9528        cx: &mut Context<Editor>,
 9529    ) -> Option<AnyElement> {
 9530        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9531            if menu.visible() {
 9532                menu.render_aside(max_size, window, cx)
 9533            } else {
 9534                None
 9535            }
 9536        })
 9537    }
 9538
 9539    fn hide_context_menu(
 9540        &mut self,
 9541        window: &mut Window,
 9542        cx: &mut Context<Self>,
 9543    ) -> Option<CodeContextMenu> {
 9544        cx.notify();
 9545        self.completion_tasks.clear();
 9546        let context_menu = self.context_menu.borrow_mut().take();
 9547        self.stale_edit_prediction_in_menu.take();
 9548        self.update_visible_edit_prediction(window, cx);
 9549        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9550            && let Some(completion_provider) = &self.completion_provider
 9551        {
 9552            completion_provider.selection_changed(None, window, cx);
 9553        }
 9554        context_menu
 9555    }
 9556
 9557    fn show_snippet_choices(
 9558        &mut self,
 9559        choices: &Vec<String>,
 9560        selection: Range<Anchor>,
 9561        cx: &mut Context<Self>,
 9562    ) {
 9563        let Some((_, buffer, _)) = self
 9564            .buffer()
 9565            .read(cx)
 9566            .excerpt_containing(selection.start, cx)
 9567        else {
 9568            return;
 9569        };
 9570        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9571        else {
 9572            return;
 9573        };
 9574        if buffer != end_buffer {
 9575            log::error!("expected anchor range to have matching buffer IDs");
 9576            return;
 9577        }
 9578
 9579        let id = post_inc(&mut self.next_completion_id);
 9580        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9581        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9582            CompletionsMenu::new_snippet_choices(
 9583                id,
 9584                true,
 9585                choices,
 9586                selection,
 9587                buffer,
 9588                snippet_sort_order,
 9589            ),
 9590        ));
 9591    }
 9592
 9593    pub fn insert_snippet(
 9594        &mut self,
 9595        insertion_ranges: &[Range<usize>],
 9596        snippet: Snippet,
 9597        window: &mut Window,
 9598        cx: &mut Context<Self>,
 9599    ) -> Result<()> {
 9600        struct Tabstop<T> {
 9601            is_end_tabstop: bool,
 9602            ranges: Vec<Range<T>>,
 9603            choices: Option<Vec<String>>,
 9604        }
 9605
 9606        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9607            let snippet_text: Arc<str> = snippet.text.clone().into();
 9608            let edits = insertion_ranges
 9609                .iter()
 9610                .cloned()
 9611                .map(|range| (range, snippet_text.clone()));
 9612            let autoindent_mode = AutoindentMode::Block {
 9613                original_indent_columns: Vec::new(),
 9614            };
 9615            buffer.edit(edits, Some(autoindent_mode), cx);
 9616
 9617            let snapshot = &*buffer.read(cx);
 9618            let snippet = &snippet;
 9619            snippet
 9620                .tabstops
 9621                .iter()
 9622                .map(|tabstop| {
 9623                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9624                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9625                    });
 9626                    let mut tabstop_ranges = tabstop
 9627                        .ranges
 9628                        .iter()
 9629                        .flat_map(|tabstop_range| {
 9630                            let mut delta = 0_isize;
 9631                            insertion_ranges.iter().map(move |insertion_range| {
 9632                                let insertion_start = insertion_range.start as isize + delta;
 9633                                delta +=
 9634                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9635
 9636                                let start = ((insertion_start + tabstop_range.start) as usize)
 9637                                    .min(snapshot.len());
 9638                                let end = ((insertion_start + tabstop_range.end) as usize)
 9639                                    .min(snapshot.len());
 9640                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9641                            })
 9642                        })
 9643                        .collect::<Vec<_>>();
 9644                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9645
 9646                    Tabstop {
 9647                        is_end_tabstop,
 9648                        ranges: tabstop_ranges,
 9649                        choices: tabstop.choices.clone(),
 9650                    }
 9651                })
 9652                .collect::<Vec<_>>()
 9653        });
 9654        if let Some(tabstop) = tabstops.first() {
 9655            self.change_selections(Default::default(), window, cx, |s| {
 9656                // Reverse order so that the first range is the newest created selection.
 9657                // Completions will use it and autoscroll will prioritize it.
 9658                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9659            });
 9660
 9661            if let Some(choices) = &tabstop.choices
 9662                && let Some(selection) = tabstop.ranges.first()
 9663            {
 9664                self.show_snippet_choices(choices, selection.clone(), cx)
 9665            }
 9666
 9667            // If we're already at the last tabstop and it's at the end of the snippet,
 9668            // we're done, we don't need to keep the state around.
 9669            if !tabstop.is_end_tabstop {
 9670                let choices = tabstops
 9671                    .iter()
 9672                    .map(|tabstop| tabstop.choices.clone())
 9673                    .collect();
 9674
 9675                let ranges = tabstops
 9676                    .into_iter()
 9677                    .map(|tabstop| tabstop.ranges)
 9678                    .collect::<Vec<_>>();
 9679
 9680                self.snippet_stack.push(SnippetState {
 9681                    active_index: 0,
 9682                    ranges,
 9683                    choices,
 9684                });
 9685            }
 9686
 9687            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9688            if self.autoclose_regions.is_empty() {
 9689                let snapshot = self.buffer.read(cx).snapshot(cx);
 9690                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9691                    let selection_head = selection.head();
 9692                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9693                        continue;
 9694                    };
 9695
 9696                    let mut bracket_pair = None;
 9697                    let max_lookup_length = scope
 9698                        .brackets()
 9699                        .map(|(pair, _)| {
 9700                            pair.start
 9701                                .as_str()
 9702                                .chars()
 9703                                .count()
 9704                                .max(pair.end.as_str().chars().count())
 9705                        })
 9706                        .max();
 9707                    if let Some(max_lookup_length) = max_lookup_length {
 9708                        let next_text = snapshot
 9709                            .chars_at(selection_head)
 9710                            .take(max_lookup_length)
 9711                            .collect::<String>();
 9712                        let prev_text = snapshot
 9713                            .reversed_chars_at(selection_head)
 9714                            .take(max_lookup_length)
 9715                            .collect::<String>();
 9716
 9717                        for (pair, enabled) in scope.brackets() {
 9718                            if enabled
 9719                                && pair.close
 9720                                && prev_text.starts_with(pair.start.as_str())
 9721                                && next_text.starts_with(pair.end.as_str())
 9722                            {
 9723                                bracket_pair = Some(pair.clone());
 9724                                break;
 9725                            }
 9726                        }
 9727                    }
 9728
 9729                    if let Some(pair) = bracket_pair {
 9730                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9731                        let autoclose_enabled =
 9732                            self.use_autoclose && snapshot_settings.use_autoclose;
 9733                        if autoclose_enabled {
 9734                            let start = snapshot.anchor_after(selection_head);
 9735                            let end = snapshot.anchor_after(selection_head);
 9736                            self.autoclose_regions.push(AutocloseRegion {
 9737                                selection_id: selection.id,
 9738                                range: start..end,
 9739                                pair,
 9740                            });
 9741                        }
 9742                    }
 9743                }
 9744            }
 9745        }
 9746        Ok(())
 9747    }
 9748
 9749    pub fn move_to_next_snippet_tabstop(
 9750        &mut self,
 9751        window: &mut Window,
 9752        cx: &mut Context<Self>,
 9753    ) -> bool {
 9754        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9755    }
 9756
 9757    pub fn move_to_prev_snippet_tabstop(
 9758        &mut self,
 9759        window: &mut Window,
 9760        cx: &mut Context<Self>,
 9761    ) -> bool {
 9762        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9763    }
 9764
 9765    pub fn move_to_snippet_tabstop(
 9766        &mut self,
 9767        bias: Bias,
 9768        window: &mut Window,
 9769        cx: &mut Context<Self>,
 9770    ) -> bool {
 9771        if let Some(mut snippet) = self.snippet_stack.pop() {
 9772            match bias {
 9773                Bias::Left => {
 9774                    if snippet.active_index > 0 {
 9775                        snippet.active_index -= 1;
 9776                    } else {
 9777                        self.snippet_stack.push(snippet);
 9778                        return false;
 9779                    }
 9780                }
 9781                Bias::Right => {
 9782                    if snippet.active_index + 1 < snippet.ranges.len() {
 9783                        snippet.active_index += 1;
 9784                    } else {
 9785                        self.snippet_stack.push(snippet);
 9786                        return false;
 9787                    }
 9788                }
 9789            }
 9790            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9791                self.change_selections(Default::default(), window, cx, |s| {
 9792                    // Reverse order so that the first range is the newest created selection.
 9793                    // Completions will use it and autoscroll will prioritize it.
 9794                    s.select_ranges(current_ranges.iter().rev().cloned())
 9795                });
 9796
 9797                if let Some(choices) = &snippet.choices[snippet.active_index]
 9798                    && let Some(selection) = current_ranges.first()
 9799                {
 9800                    self.show_snippet_choices(choices, selection.clone(), cx);
 9801                }
 9802
 9803                // If snippet state is not at the last tabstop, push it back on the stack
 9804                if snippet.active_index + 1 < snippet.ranges.len() {
 9805                    self.snippet_stack.push(snippet);
 9806                }
 9807                return true;
 9808            }
 9809        }
 9810
 9811        false
 9812    }
 9813
 9814    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9815        self.transact(window, cx, |this, window, cx| {
 9816            this.select_all(&SelectAll, window, cx);
 9817            this.insert("", window, cx);
 9818        });
 9819    }
 9820
 9821    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9822        if self.read_only(cx) {
 9823            return;
 9824        }
 9825        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9826        self.transact(window, cx, |this, window, cx| {
 9827            this.select_autoclose_pair(window, cx);
 9828
 9829            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9830
 9831            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9832            if !this.linked_edit_ranges.is_empty() {
 9833                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9834                let snapshot = this.buffer.read(cx).snapshot(cx);
 9835
 9836                for selection in selections.iter() {
 9837                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9838                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9839                    if selection_start.buffer_id != selection_end.buffer_id {
 9840                        continue;
 9841                    }
 9842                    if let Some(ranges) =
 9843                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9844                    {
 9845                        for (buffer, entries) in ranges {
 9846                            linked_ranges.entry(buffer).or_default().extend(entries);
 9847                        }
 9848                    }
 9849                }
 9850            }
 9851
 9852            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9853            for selection in &mut selections {
 9854                if selection.is_empty() {
 9855                    let old_head = selection.head();
 9856                    let mut new_head =
 9857                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9858                            .to_point(&display_map);
 9859                    if let Some((buffer, line_buffer_range)) = display_map
 9860                        .buffer_snapshot()
 9861                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9862                    {
 9863                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9864                        let indent_len = match indent_size.kind {
 9865                            IndentKind::Space => {
 9866                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9867                            }
 9868                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9869                        };
 9870                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9871                            let indent_len = indent_len.get();
 9872                            new_head = cmp::min(
 9873                                new_head,
 9874                                MultiBufferPoint::new(
 9875                                    old_head.row,
 9876                                    ((old_head.column - 1) / indent_len) * indent_len,
 9877                                ),
 9878                            );
 9879                        }
 9880                    }
 9881
 9882                    selection.set_head(new_head, SelectionGoal::None);
 9883                }
 9884            }
 9885
 9886            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9887            this.insert("", window, cx);
 9888            let empty_str: Arc<str> = Arc::from("");
 9889            for (buffer, edits) in linked_ranges {
 9890                let snapshot = buffer.read(cx).snapshot();
 9891                use text::ToPoint as TP;
 9892
 9893                let edits = edits
 9894                    .into_iter()
 9895                    .map(|range| {
 9896                        let end_point = TP::to_point(&range.end, &snapshot);
 9897                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9898
 9899                        if end_point == start_point {
 9900                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9901                                .saturating_sub(1);
 9902                            start_point =
 9903                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9904                        };
 9905
 9906                        (start_point..end_point, empty_str.clone())
 9907                    })
 9908                    .sorted_by_key(|(range, _)| range.start)
 9909                    .collect::<Vec<_>>();
 9910                buffer.update(cx, |this, cx| {
 9911                    this.edit(edits, None, cx);
 9912                })
 9913            }
 9914            this.refresh_edit_prediction(true, false, window, cx);
 9915            refresh_linked_ranges(this, window, cx);
 9916        });
 9917    }
 9918
 9919    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9920        if self.read_only(cx) {
 9921            return;
 9922        }
 9923        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9924        self.transact(window, cx, |this, window, cx| {
 9925            this.change_selections(Default::default(), window, cx, |s| {
 9926                s.move_with(|map, selection| {
 9927                    if selection.is_empty() {
 9928                        let cursor = movement::right(map, selection.head());
 9929                        selection.end = cursor;
 9930                        selection.reversed = true;
 9931                        selection.goal = SelectionGoal::None;
 9932                    }
 9933                })
 9934            });
 9935            this.insert("", window, cx);
 9936            this.refresh_edit_prediction(true, false, window, cx);
 9937        });
 9938    }
 9939
 9940    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9941        if self.mode.is_single_line() {
 9942            cx.propagate();
 9943            return;
 9944        }
 9945
 9946        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9947        if self.move_to_prev_snippet_tabstop(window, cx) {
 9948            return;
 9949        }
 9950        self.outdent(&Outdent, window, cx);
 9951    }
 9952
 9953    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9954        if self.mode.is_single_line() {
 9955            cx.propagate();
 9956            return;
 9957        }
 9958
 9959        if self.move_to_next_snippet_tabstop(window, cx) {
 9960            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9961            return;
 9962        }
 9963        if self.read_only(cx) {
 9964            return;
 9965        }
 9966        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9967        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 9968        let buffer = self.buffer.read(cx);
 9969        let snapshot = buffer.snapshot(cx);
 9970        let rows_iter = selections.iter().map(|s| s.head().row);
 9971        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9972
 9973        let has_some_cursor_in_whitespace = selections
 9974            .iter()
 9975            .filter(|selection| selection.is_empty())
 9976            .any(|selection| {
 9977                let cursor = selection.head();
 9978                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9979                cursor.column < current_indent.len
 9980            });
 9981
 9982        let mut edits = Vec::new();
 9983        let mut prev_edited_row = 0;
 9984        let mut row_delta = 0;
 9985        for selection in &mut selections {
 9986            if selection.start.row != prev_edited_row {
 9987                row_delta = 0;
 9988            }
 9989            prev_edited_row = selection.end.row;
 9990
 9991            // If the selection is non-empty, then increase the indentation of the selected lines.
 9992            if !selection.is_empty() {
 9993                row_delta =
 9994                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9995                continue;
 9996            }
 9997
 9998            let cursor = selection.head();
 9999            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10000            if let Some(suggested_indent) =
10001                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10002            {
10003                // Don't do anything if already at suggested indent
10004                // and there is any other cursor which is not
10005                if has_some_cursor_in_whitespace
10006                    && cursor.column == current_indent.len
10007                    && current_indent.len == suggested_indent.len
10008                {
10009                    continue;
10010                }
10011
10012                // Adjust line and move cursor to suggested indent
10013                // if cursor is not at suggested indent
10014                if cursor.column < suggested_indent.len
10015                    && cursor.column <= current_indent.len
10016                    && current_indent.len <= suggested_indent.len
10017                {
10018                    selection.start = Point::new(cursor.row, suggested_indent.len);
10019                    selection.end = selection.start;
10020                    if row_delta == 0 {
10021                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10022                            cursor.row,
10023                            current_indent,
10024                            suggested_indent,
10025                        ));
10026                        row_delta = suggested_indent.len - current_indent.len;
10027                    }
10028                    continue;
10029                }
10030
10031                // If current indent is more than suggested indent
10032                // only move cursor to current indent and skip indent
10033                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10034                    selection.start = Point::new(cursor.row, current_indent.len);
10035                    selection.end = selection.start;
10036                    continue;
10037                }
10038            }
10039
10040            // Otherwise, insert a hard or soft tab.
10041            let settings = buffer.language_settings_at(cursor, cx);
10042            let tab_size = if settings.hard_tabs {
10043                IndentSize::tab()
10044            } else {
10045                let tab_size = settings.tab_size.get();
10046                let indent_remainder = snapshot
10047                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10048                    .flat_map(str::chars)
10049                    .fold(row_delta % tab_size, |counter: u32, c| {
10050                        if c == '\t' {
10051                            0
10052                        } else {
10053                            (counter + 1) % tab_size
10054                        }
10055                    });
10056
10057                let chars_to_next_tab_stop = tab_size - indent_remainder;
10058                IndentSize::spaces(chars_to_next_tab_stop)
10059            };
10060            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10061            selection.end = selection.start;
10062            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10063            row_delta += tab_size.len;
10064        }
10065
10066        self.transact(window, cx, |this, window, cx| {
10067            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10068            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10069            this.refresh_edit_prediction(true, false, window, cx);
10070        });
10071    }
10072
10073    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10074        if self.read_only(cx) {
10075            return;
10076        }
10077        if self.mode.is_single_line() {
10078            cx.propagate();
10079            return;
10080        }
10081
10082        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10083        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10084        let mut prev_edited_row = 0;
10085        let mut row_delta = 0;
10086        let mut edits = Vec::new();
10087        let buffer = self.buffer.read(cx);
10088        let snapshot = buffer.snapshot(cx);
10089        for selection in &mut selections {
10090            if selection.start.row != prev_edited_row {
10091                row_delta = 0;
10092            }
10093            prev_edited_row = selection.end.row;
10094
10095            row_delta =
10096                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10097        }
10098
10099        self.transact(window, cx, |this, window, cx| {
10100            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10101            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10102        });
10103    }
10104
10105    fn indent_selection(
10106        buffer: &MultiBuffer,
10107        snapshot: &MultiBufferSnapshot,
10108        selection: &mut Selection<Point>,
10109        edits: &mut Vec<(Range<Point>, String)>,
10110        delta_for_start_row: u32,
10111        cx: &App,
10112    ) -> u32 {
10113        let settings = buffer.language_settings_at(selection.start, cx);
10114        let tab_size = settings.tab_size.get();
10115        let indent_kind = if settings.hard_tabs {
10116            IndentKind::Tab
10117        } else {
10118            IndentKind::Space
10119        };
10120        let mut start_row = selection.start.row;
10121        let mut end_row = selection.end.row + 1;
10122
10123        // If a selection ends at the beginning of a line, don't indent
10124        // that last line.
10125        if selection.end.column == 0 && selection.end.row > selection.start.row {
10126            end_row -= 1;
10127        }
10128
10129        // Avoid re-indenting a row that has already been indented by a
10130        // previous selection, but still update this selection's column
10131        // to reflect that indentation.
10132        if delta_for_start_row > 0 {
10133            start_row += 1;
10134            selection.start.column += delta_for_start_row;
10135            if selection.end.row == selection.start.row {
10136                selection.end.column += delta_for_start_row;
10137            }
10138        }
10139
10140        let mut delta_for_end_row = 0;
10141        let has_multiple_rows = start_row + 1 != end_row;
10142        for row in start_row..end_row {
10143            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10144            let indent_delta = match (current_indent.kind, indent_kind) {
10145                (IndentKind::Space, IndentKind::Space) => {
10146                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10147                    IndentSize::spaces(columns_to_next_tab_stop)
10148                }
10149                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10150                (_, IndentKind::Tab) => IndentSize::tab(),
10151            };
10152
10153            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10154                0
10155            } else {
10156                selection.start.column
10157            };
10158            let row_start = Point::new(row, start);
10159            edits.push((
10160                row_start..row_start,
10161                indent_delta.chars().collect::<String>(),
10162            ));
10163
10164            // Update this selection's endpoints to reflect the indentation.
10165            if row == selection.start.row {
10166                selection.start.column += indent_delta.len;
10167            }
10168            if row == selection.end.row {
10169                selection.end.column += indent_delta.len;
10170                delta_for_end_row = indent_delta.len;
10171            }
10172        }
10173
10174        if selection.start.row == selection.end.row {
10175            delta_for_start_row + delta_for_end_row
10176        } else {
10177            delta_for_end_row
10178        }
10179    }
10180
10181    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10182        if self.read_only(cx) {
10183            return;
10184        }
10185        if self.mode.is_single_line() {
10186            cx.propagate();
10187            return;
10188        }
10189
10190        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10191        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10192        let selections = self.selections.all::<Point>(&display_map);
10193        let mut deletion_ranges = Vec::new();
10194        let mut last_outdent = None;
10195        {
10196            let buffer = self.buffer.read(cx);
10197            let snapshot = buffer.snapshot(cx);
10198            for selection in &selections {
10199                let settings = buffer.language_settings_at(selection.start, cx);
10200                let tab_size = settings.tab_size.get();
10201                let mut rows = selection.spanned_rows(false, &display_map);
10202
10203                // Avoid re-outdenting a row that has already been outdented by a
10204                // previous selection.
10205                if let Some(last_row) = last_outdent
10206                    && last_row == rows.start
10207                {
10208                    rows.start = rows.start.next_row();
10209                }
10210                let has_multiple_rows = rows.len() > 1;
10211                for row in rows.iter_rows() {
10212                    let indent_size = snapshot.indent_size_for_line(row);
10213                    if indent_size.len > 0 {
10214                        let deletion_len = match indent_size.kind {
10215                            IndentKind::Space => {
10216                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10217                                if columns_to_prev_tab_stop == 0 {
10218                                    tab_size
10219                                } else {
10220                                    columns_to_prev_tab_stop
10221                                }
10222                            }
10223                            IndentKind::Tab => 1,
10224                        };
10225                        let start = if has_multiple_rows
10226                            || deletion_len > selection.start.column
10227                            || indent_size.len < selection.start.column
10228                        {
10229                            0
10230                        } else {
10231                            selection.start.column - deletion_len
10232                        };
10233                        deletion_ranges.push(
10234                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10235                        );
10236                        last_outdent = Some(row);
10237                    }
10238                }
10239            }
10240        }
10241
10242        self.transact(window, cx, |this, window, cx| {
10243            this.buffer.update(cx, |buffer, cx| {
10244                let empty_str: Arc<str> = Arc::default();
10245                buffer.edit(
10246                    deletion_ranges
10247                        .into_iter()
10248                        .map(|range| (range, empty_str.clone())),
10249                    None,
10250                    cx,
10251                );
10252            });
10253            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10254            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10255        });
10256    }
10257
10258    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10259        if self.read_only(cx) {
10260            return;
10261        }
10262        if self.mode.is_single_line() {
10263            cx.propagate();
10264            return;
10265        }
10266
10267        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10268        let selections = self
10269            .selections
10270            .all::<usize>(&self.display_snapshot(cx))
10271            .into_iter()
10272            .map(|s| s.range());
10273
10274        self.transact(window, cx, |this, window, cx| {
10275            this.buffer.update(cx, |buffer, cx| {
10276                buffer.autoindent_ranges(selections, cx);
10277            });
10278            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10279            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10280        });
10281    }
10282
10283    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10284        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10285        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10286        let selections = self.selections.all::<Point>(&display_map);
10287
10288        let mut new_cursors = Vec::new();
10289        let mut edit_ranges = Vec::new();
10290        let mut selections = selections.iter().peekable();
10291        while let Some(selection) = selections.next() {
10292            let mut rows = selection.spanned_rows(false, &display_map);
10293
10294            // Accumulate contiguous regions of rows that we want to delete.
10295            while let Some(next_selection) = selections.peek() {
10296                let next_rows = next_selection.spanned_rows(false, &display_map);
10297                if next_rows.start <= rows.end {
10298                    rows.end = next_rows.end;
10299                    selections.next().unwrap();
10300                } else {
10301                    break;
10302                }
10303            }
10304
10305            let buffer = display_map.buffer_snapshot();
10306            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10307            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10308                // If there's a line after the range, delete the \n from the end of the row range
10309                (
10310                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10311                    rows.end,
10312                )
10313            } else {
10314                // If there isn't a line after the range, delete the \n from the line before the
10315                // start of the row range
10316                edit_start = edit_start.saturating_sub(1);
10317                (buffer.len(), rows.start.previous_row())
10318            };
10319
10320            let text_layout_details = self.text_layout_details(window);
10321            let x = display_map.x_for_display_point(
10322                selection.head().to_display_point(&display_map),
10323                &text_layout_details,
10324            );
10325            let row = Point::new(target_row.0, 0)
10326                .to_display_point(&display_map)
10327                .row();
10328            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10329
10330            new_cursors.push((
10331                selection.id,
10332                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10333                SelectionGoal::None,
10334            ));
10335            edit_ranges.push(edit_start..edit_end);
10336        }
10337
10338        self.transact(window, cx, |this, window, cx| {
10339            let buffer = this.buffer.update(cx, |buffer, cx| {
10340                let empty_str: Arc<str> = Arc::default();
10341                buffer.edit(
10342                    edit_ranges
10343                        .into_iter()
10344                        .map(|range| (range, empty_str.clone())),
10345                    None,
10346                    cx,
10347                );
10348                buffer.snapshot(cx)
10349            });
10350            let new_selections = new_cursors
10351                .into_iter()
10352                .map(|(id, cursor, goal)| {
10353                    let cursor = cursor.to_point(&buffer);
10354                    Selection {
10355                        id,
10356                        start: cursor,
10357                        end: cursor,
10358                        reversed: false,
10359                        goal,
10360                    }
10361                })
10362                .collect();
10363
10364            this.change_selections(Default::default(), window, cx, |s| {
10365                s.select(new_selections);
10366            });
10367        });
10368    }
10369
10370    pub fn join_lines_impl(
10371        &mut self,
10372        insert_whitespace: bool,
10373        window: &mut Window,
10374        cx: &mut Context<Self>,
10375    ) {
10376        if self.read_only(cx) {
10377            return;
10378        }
10379        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10380        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10381            let start = MultiBufferRow(selection.start.row);
10382            // Treat single line selections as if they include the next line. Otherwise this action
10383            // would do nothing for single line selections individual cursors.
10384            let end = if selection.start.row == selection.end.row {
10385                MultiBufferRow(selection.start.row + 1)
10386            } else {
10387                MultiBufferRow(selection.end.row)
10388            };
10389
10390            if let Some(last_row_range) = row_ranges.last_mut()
10391                && start <= last_row_range.end
10392            {
10393                last_row_range.end = end;
10394                continue;
10395            }
10396            row_ranges.push(start..end);
10397        }
10398
10399        let snapshot = self.buffer.read(cx).snapshot(cx);
10400        let mut cursor_positions = Vec::new();
10401        for row_range in &row_ranges {
10402            let anchor = snapshot.anchor_before(Point::new(
10403                row_range.end.previous_row().0,
10404                snapshot.line_len(row_range.end.previous_row()),
10405            ));
10406            cursor_positions.push(anchor..anchor);
10407        }
10408
10409        self.transact(window, cx, |this, window, cx| {
10410            for row_range in row_ranges.into_iter().rev() {
10411                for row in row_range.iter_rows().rev() {
10412                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10413                    let next_line_row = row.next_row();
10414                    let indent = snapshot.indent_size_for_line(next_line_row);
10415                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10416
10417                    let replace =
10418                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10419                            " "
10420                        } else {
10421                            ""
10422                        };
10423
10424                    this.buffer.update(cx, |buffer, cx| {
10425                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10426                    });
10427                }
10428            }
10429
10430            this.change_selections(Default::default(), window, cx, |s| {
10431                s.select_anchor_ranges(cursor_positions)
10432            });
10433        });
10434    }
10435
10436    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10437        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10438        self.join_lines_impl(true, window, cx);
10439    }
10440
10441    pub fn sort_lines_case_sensitive(
10442        &mut self,
10443        _: &SortLinesCaseSensitive,
10444        window: &mut Window,
10445        cx: &mut Context<Self>,
10446    ) {
10447        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10448    }
10449
10450    pub fn sort_lines_by_length(
10451        &mut self,
10452        _: &SortLinesByLength,
10453        window: &mut Window,
10454        cx: &mut Context<Self>,
10455    ) {
10456        self.manipulate_immutable_lines(window, cx, |lines| {
10457            lines.sort_by_key(|&line| line.chars().count())
10458        })
10459    }
10460
10461    pub fn sort_lines_case_insensitive(
10462        &mut self,
10463        _: &SortLinesCaseInsensitive,
10464        window: &mut Window,
10465        cx: &mut Context<Self>,
10466    ) {
10467        self.manipulate_immutable_lines(window, cx, |lines| {
10468            lines.sort_by_key(|line| line.to_lowercase())
10469        })
10470    }
10471
10472    pub fn unique_lines_case_insensitive(
10473        &mut self,
10474        _: &UniqueLinesCaseInsensitive,
10475        window: &mut Window,
10476        cx: &mut Context<Self>,
10477    ) {
10478        self.manipulate_immutable_lines(window, cx, |lines| {
10479            let mut seen = HashSet::default();
10480            lines.retain(|line| seen.insert(line.to_lowercase()));
10481        })
10482    }
10483
10484    pub fn unique_lines_case_sensitive(
10485        &mut self,
10486        _: &UniqueLinesCaseSensitive,
10487        window: &mut Window,
10488        cx: &mut Context<Self>,
10489    ) {
10490        self.manipulate_immutable_lines(window, cx, |lines| {
10491            let mut seen = HashSet::default();
10492            lines.retain(|line| seen.insert(*line));
10493        })
10494    }
10495
10496    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10497        let snapshot = self.buffer.read(cx).snapshot(cx);
10498        for selection in self.selections.disjoint_anchors_arc().iter() {
10499            if snapshot
10500                .language_at(selection.start)
10501                .and_then(|lang| lang.config().wrap_characters.as_ref())
10502                .is_some()
10503            {
10504                return true;
10505            }
10506        }
10507        false
10508    }
10509
10510    fn wrap_selections_in_tag(
10511        &mut self,
10512        _: &WrapSelectionsInTag,
10513        window: &mut Window,
10514        cx: &mut Context<Self>,
10515    ) {
10516        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10517
10518        let snapshot = self.buffer.read(cx).snapshot(cx);
10519
10520        let mut edits = Vec::new();
10521        let mut boundaries = Vec::new();
10522
10523        for selection in self
10524            .selections
10525            .all_adjusted(&self.display_snapshot(cx))
10526            .iter()
10527        {
10528            let Some(wrap_config) = snapshot
10529                .language_at(selection.start)
10530                .and_then(|lang| lang.config().wrap_characters.clone())
10531            else {
10532                continue;
10533            };
10534
10535            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10536            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10537
10538            let start_before = snapshot.anchor_before(selection.start);
10539            let end_after = snapshot.anchor_after(selection.end);
10540
10541            edits.push((start_before..start_before, open_tag));
10542            edits.push((end_after..end_after, close_tag));
10543
10544            boundaries.push((
10545                start_before,
10546                end_after,
10547                wrap_config.start_prefix.len(),
10548                wrap_config.end_suffix.len(),
10549            ));
10550        }
10551
10552        if edits.is_empty() {
10553            return;
10554        }
10555
10556        self.transact(window, cx, |this, window, cx| {
10557            let buffer = this.buffer.update(cx, |buffer, cx| {
10558                buffer.edit(edits, None, cx);
10559                buffer.snapshot(cx)
10560            });
10561
10562            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10563            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10564                boundaries.into_iter()
10565            {
10566                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10567                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10568                new_selections.push(open_offset..open_offset);
10569                new_selections.push(close_offset..close_offset);
10570            }
10571
10572            this.change_selections(Default::default(), window, cx, |s| {
10573                s.select_ranges(new_selections);
10574            });
10575
10576            this.request_autoscroll(Autoscroll::fit(), cx);
10577        });
10578    }
10579
10580    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10581        let Some(project) = self.project.clone() else {
10582            return;
10583        };
10584        self.reload(project, window, cx)
10585            .detach_and_notify_err(window, cx);
10586    }
10587
10588    pub fn restore_file(
10589        &mut self,
10590        _: &::git::RestoreFile,
10591        window: &mut Window,
10592        cx: &mut Context<Self>,
10593    ) {
10594        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10595        let mut buffer_ids = HashSet::default();
10596        let snapshot = self.buffer().read(cx).snapshot(cx);
10597        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10598            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10599        }
10600
10601        let buffer = self.buffer().read(cx);
10602        let ranges = buffer_ids
10603            .into_iter()
10604            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10605            .collect::<Vec<_>>();
10606
10607        self.restore_hunks_in_ranges(ranges, window, cx);
10608    }
10609
10610    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10611        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10612        let selections = self
10613            .selections
10614            .all(&self.display_snapshot(cx))
10615            .into_iter()
10616            .map(|s| s.range())
10617            .collect();
10618        self.restore_hunks_in_ranges(selections, window, cx);
10619    }
10620
10621    pub fn restore_hunks_in_ranges(
10622        &mut self,
10623        ranges: Vec<Range<Point>>,
10624        window: &mut Window,
10625        cx: &mut Context<Editor>,
10626    ) {
10627        let mut revert_changes = HashMap::default();
10628        let chunk_by = self
10629            .snapshot(window, cx)
10630            .hunks_for_ranges(ranges)
10631            .into_iter()
10632            .chunk_by(|hunk| hunk.buffer_id);
10633        for (buffer_id, hunks) in &chunk_by {
10634            let hunks = hunks.collect::<Vec<_>>();
10635            for hunk in &hunks {
10636                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10637            }
10638            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10639        }
10640        drop(chunk_by);
10641        if !revert_changes.is_empty() {
10642            self.transact(window, cx, |editor, window, cx| {
10643                editor.restore(revert_changes, window, cx);
10644            });
10645        }
10646    }
10647
10648    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10649        if let Some(status) = self
10650            .addons
10651            .iter()
10652            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10653        {
10654            return Some(status);
10655        }
10656        self.project
10657            .as_ref()?
10658            .read(cx)
10659            .status_for_buffer_id(buffer_id, cx)
10660    }
10661
10662    pub fn open_active_item_in_terminal(
10663        &mut self,
10664        _: &OpenInTerminal,
10665        window: &mut Window,
10666        cx: &mut Context<Self>,
10667    ) {
10668        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10669            let project_path = buffer.read(cx).project_path(cx)?;
10670            let project = self.project()?.read(cx);
10671            let entry = project.entry_for_path(&project_path, cx)?;
10672            let parent = match &entry.canonical_path {
10673                Some(canonical_path) => canonical_path.to_path_buf(),
10674                None => project.absolute_path(&project_path, cx)?,
10675            }
10676            .parent()?
10677            .to_path_buf();
10678            Some(parent)
10679        }) {
10680            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10681        }
10682    }
10683
10684    fn set_breakpoint_context_menu(
10685        &mut self,
10686        display_row: DisplayRow,
10687        position: Option<Anchor>,
10688        clicked_point: gpui::Point<Pixels>,
10689        window: &mut Window,
10690        cx: &mut Context<Self>,
10691    ) {
10692        let source = self
10693            .buffer
10694            .read(cx)
10695            .snapshot(cx)
10696            .anchor_before(Point::new(display_row.0, 0u32));
10697
10698        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10699
10700        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10701            self,
10702            source,
10703            clicked_point,
10704            context_menu,
10705            window,
10706            cx,
10707        );
10708    }
10709
10710    fn add_edit_breakpoint_block(
10711        &mut self,
10712        anchor: Anchor,
10713        breakpoint: &Breakpoint,
10714        edit_action: BreakpointPromptEditAction,
10715        window: &mut Window,
10716        cx: &mut Context<Self>,
10717    ) {
10718        let weak_editor = cx.weak_entity();
10719        let bp_prompt = cx.new(|cx| {
10720            BreakpointPromptEditor::new(
10721                weak_editor,
10722                anchor,
10723                breakpoint.clone(),
10724                edit_action,
10725                window,
10726                cx,
10727            )
10728        });
10729
10730        let height = bp_prompt.update(cx, |this, cx| {
10731            this.prompt
10732                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10733        });
10734        let cloned_prompt = bp_prompt.clone();
10735        let blocks = vec![BlockProperties {
10736            style: BlockStyle::Sticky,
10737            placement: BlockPlacement::Above(anchor),
10738            height: Some(height),
10739            render: Arc::new(move |cx| {
10740                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10741                cloned_prompt.clone().into_any_element()
10742            }),
10743            priority: 0,
10744        }];
10745
10746        let focus_handle = bp_prompt.focus_handle(cx);
10747        window.focus(&focus_handle);
10748
10749        let block_ids = self.insert_blocks(blocks, None, cx);
10750        bp_prompt.update(cx, |prompt, _| {
10751            prompt.add_block_ids(block_ids);
10752        });
10753    }
10754
10755    pub(crate) fn breakpoint_at_row(
10756        &self,
10757        row: u32,
10758        window: &mut Window,
10759        cx: &mut Context<Self>,
10760    ) -> Option<(Anchor, Breakpoint)> {
10761        let snapshot = self.snapshot(window, cx);
10762        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10763
10764        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10765    }
10766
10767    pub(crate) fn breakpoint_at_anchor(
10768        &self,
10769        breakpoint_position: Anchor,
10770        snapshot: &EditorSnapshot,
10771        cx: &mut Context<Self>,
10772    ) -> Option<(Anchor, Breakpoint)> {
10773        let buffer = self
10774            .buffer
10775            .read(cx)
10776            .buffer_for_anchor(breakpoint_position, cx)?;
10777
10778        let enclosing_excerpt = breakpoint_position.excerpt_id;
10779        let buffer_snapshot = buffer.read(cx).snapshot();
10780
10781        let row = buffer_snapshot
10782            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10783            .row;
10784
10785        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10786        let anchor_end = snapshot
10787            .buffer_snapshot()
10788            .anchor_after(Point::new(row, line_len));
10789
10790        self.breakpoint_store
10791            .as_ref()?
10792            .read_with(cx, |breakpoint_store, cx| {
10793                breakpoint_store
10794                    .breakpoints(
10795                        &buffer,
10796                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10797                        &buffer_snapshot,
10798                        cx,
10799                    )
10800                    .next()
10801                    .and_then(|(bp, _)| {
10802                        let breakpoint_row = buffer_snapshot
10803                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10804                            .row;
10805
10806                        if breakpoint_row == row {
10807                            snapshot
10808                                .buffer_snapshot()
10809                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10810                                .map(|position| (position, bp.bp.clone()))
10811                        } else {
10812                            None
10813                        }
10814                    })
10815            })
10816    }
10817
10818    pub fn edit_log_breakpoint(
10819        &mut self,
10820        _: &EditLogBreakpoint,
10821        window: &mut Window,
10822        cx: &mut Context<Self>,
10823    ) {
10824        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10825            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10826                message: None,
10827                state: BreakpointState::Enabled,
10828                condition: None,
10829                hit_condition: None,
10830            });
10831
10832            self.add_edit_breakpoint_block(
10833                anchor,
10834                &breakpoint,
10835                BreakpointPromptEditAction::Log,
10836                window,
10837                cx,
10838            );
10839        }
10840    }
10841
10842    fn breakpoints_at_cursors(
10843        &self,
10844        window: &mut Window,
10845        cx: &mut Context<Self>,
10846    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10847        let snapshot = self.snapshot(window, cx);
10848        let cursors = self
10849            .selections
10850            .disjoint_anchors_arc()
10851            .iter()
10852            .map(|selection| {
10853                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
10854
10855                let breakpoint_position = self
10856                    .breakpoint_at_row(cursor_position.row, window, cx)
10857                    .map(|bp| bp.0)
10858                    .unwrap_or_else(|| {
10859                        snapshot
10860                            .display_snapshot
10861                            .buffer_snapshot()
10862                            .anchor_after(Point::new(cursor_position.row, 0))
10863                    });
10864
10865                let breakpoint = self
10866                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10867                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10868
10869                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10870            })
10871            // 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.
10872            .collect::<HashMap<Anchor, _>>();
10873
10874        cursors.into_iter().collect()
10875    }
10876
10877    pub fn enable_breakpoint(
10878        &mut self,
10879        _: &crate::actions::EnableBreakpoint,
10880        window: &mut Window,
10881        cx: &mut Context<Self>,
10882    ) {
10883        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10884            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10885                continue;
10886            };
10887            self.edit_breakpoint_at_anchor(
10888                anchor,
10889                breakpoint,
10890                BreakpointEditAction::InvertState,
10891                cx,
10892            );
10893        }
10894    }
10895
10896    pub fn disable_breakpoint(
10897        &mut self,
10898        _: &crate::actions::DisableBreakpoint,
10899        window: &mut Window,
10900        cx: &mut Context<Self>,
10901    ) {
10902        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10903            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10904                continue;
10905            };
10906            self.edit_breakpoint_at_anchor(
10907                anchor,
10908                breakpoint,
10909                BreakpointEditAction::InvertState,
10910                cx,
10911            );
10912        }
10913    }
10914
10915    pub fn toggle_breakpoint(
10916        &mut self,
10917        _: &crate::actions::ToggleBreakpoint,
10918        window: &mut Window,
10919        cx: &mut Context<Self>,
10920    ) {
10921        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10922            if let Some(breakpoint) = breakpoint {
10923                self.edit_breakpoint_at_anchor(
10924                    anchor,
10925                    breakpoint,
10926                    BreakpointEditAction::Toggle,
10927                    cx,
10928                );
10929            } else {
10930                self.edit_breakpoint_at_anchor(
10931                    anchor,
10932                    Breakpoint::new_standard(),
10933                    BreakpointEditAction::Toggle,
10934                    cx,
10935                );
10936            }
10937        }
10938    }
10939
10940    pub fn edit_breakpoint_at_anchor(
10941        &mut self,
10942        breakpoint_position: Anchor,
10943        breakpoint: Breakpoint,
10944        edit_action: BreakpointEditAction,
10945        cx: &mut Context<Self>,
10946    ) {
10947        let Some(breakpoint_store) = &self.breakpoint_store else {
10948            return;
10949        };
10950
10951        let Some(buffer) = self
10952            .buffer
10953            .read(cx)
10954            .buffer_for_anchor(breakpoint_position, cx)
10955        else {
10956            return;
10957        };
10958
10959        breakpoint_store.update(cx, |breakpoint_store, cx| {
10960            breakpoint_store.toggle_breakpoint(
10961                buffer,
10962                BreakpointWithPosition {
10963                    position: breakpoint_position.text_anchor,
10964                    bp: breakpoint,
10965                },
10966                edit_action,
10967                cx,
10968            );
10969        });
10970
10971        cx.notify();
10972    }
10973
10974    #[cfg(any(test, feature = "test-support"))]
10975    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10976        self.breakpoint_store.clone()
10977    }
10978
10979    pub fn prepare_restore_change(
10980        &self,
10981        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10982        hunk: &MultiBufferDiffHunk,
10983        cx: &mut App,
10984    ) -> Option<()> {
10985        if hunk.is_created_file() {
10986            return None;
10987        }
10988        let buffer = self.buffer.read(cx);
10989        let diff = buffer.diff_for(hunk.buffer_id)?;
10990        let buffer = buffer.buffer(hunk.buffer_id)?;
10991        let buffer = buffer.read(cx);
10992        let original_text = diff
10993            .read(cx)
10994            .base_text()
10995            .as_rope()
10996            .slice(hunk.diff_base_byte_range.clone());
10997        let buffer_snapshot = buffer.snapshot();
10998        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10999        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11000            probe
11001                .0
11002                .start
11003                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11004                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11005        }) {
11006            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11007            Some(())
11008        } else {
11009            None
11010        }
11011    }
11012
11013    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11014        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11015    }
11016
11017    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11018        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11019    }
11020
11021    fn manipulate_lines<M>(
11022        &mut self,
11023        window: &mut Window,
11024        cx: &mut Context<Self>,
11025        mut manipulate: M,
11026    ) where
11027        M: FnMut(&str) -> LineManipulationResult,
11028    {
11029        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11030
11031        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11032        let buffer = self.buffer.read(cx).snapshot(cx);
11033
11034        let mut edits = Vec::new();
11035
11036        let selections = self.selections.all::<Point>(&display_map);
11037        let mut selections = selections.iter().peekable();
11038        let mut contiguous_row_selections = Vec::new();
11039        let mut new_selections = Vec::new();
11040        let mut added_lines = 0;
11041        let mut removed_lines = 0;
11042
11043        while let Some(selection) = selections.next() {
11044            let (start_row, end_row) = consume_contiguous_rows(
11045                &mut contiguous_row_selections,
11046                selection,
11047                &display_map,
11048                &mut selections,
11049            );
11050
11051            let start_point = Point::new(start_row.0, 0);
11052            let end_point = Point::new(
11053                end_row.previous_row().0,
11054                buffer.line_len(end_row.previous_row()),
11055            );
11056            let text = buffer
11057                .text_for_range(start_point..end_point)
11058                .collect::<String>();
11059
11060            let LineManipulationResult {
11061                new_text,
11062                line_count_before,
11063                line_count_after,
11064            } = manipulate(&text);
11065
11066            edits.push((start_point..end_point, new_text));
11067
11068            // Selections must change based on added and removed line count
11069            let start_row =
11070                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11071            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11072            new_selections.push(Selection {
11073                id: selection.id,
11074                start: start_row,
11075                end: end_row,
11076                goal: SelectionGoal::None,
11077                reversed: selection.reversed,
11078            });
11079
11080            if line_count_after > line_count_before {
11081                added_lines += line_count_after - line_count_before;
11082            } else if line_count_before > line_count_after {
11083                removed_lines += line_count_before - line_count_after;
11084            }
11085        }
11086
11087        self.transact(window, cx, |this, window, cx| {
11088            let buffer = this.buffer.update(cx, |buffer, cx| {
11089                buffer.edit(edits, None, cx);
11090                buffer.snapshot(cx)
11091            });
11092
11093            // Recalculate offsets on newly edited buffer
11094            let new_selections = new_selections
11095                .iter()
11096                .map(|s| {
11097                    let start_point = Point::new(s.start.0, 0);
11098                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11099                    Selection {
11100                        id: s.id,
11101                        start: buffer.point_to_offset(start_point),
11102                        end: buffer.point_to_offset(end_point),
11103                        goal: s.goal,
11104                        reversed: s.reversed,
11105                    }
11106                })
11107                .collect();
11108
11109            this.change_selections(Default::default(), window, cx, |s| {
11110                s.select(new_selections);
11111            });
11112
11113            this.request_autoscroll(Autoscroll::fit(), cx);
11114        });
11115    }
11116
11117    fn manipulate_immutable_lines<Fn>(
11118        &mut self,
11119        window: &mut Window,
11120        cx: &mut Context<Self>,
11121        mut callback: Fn,
11122    ) where
11123        Fn: FnMut(&mut Vec<&str>),
11124    {
11125        self.manipulate_lines(window, cx, |text| {
11126            let mut lines: Vec<&str> = text.split('\n').collect();
11127            let line_count_before = lines.len();
11128
11129            callback(&mut lines);
11130
11131            LineManipulationResult {
11132                new_text: lines.join("\n"),
11133                line_count_before,
11134                line_count_after: lines.len(),
11135            }
11136        });
11137    }
11138
11139    fn manipulate_mutable_lines<Fn>(
11140        &mut self,
11141        window: &mut Window,
11142        cx: &mut Context<Self>,
11143        mut callback: Fn,
11144    ) where
11145        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11146    {
11147        self.manipulate_lines(window, cx, |text| {
11148            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11149            let line_count_before = lines.len();
11150
11151            callback(&mut lines);
11152
11153            LineManipulationResult {
11154                new_text: lines.join("\n"),
11155                line_count_before,
11156                line_count_after: lines.len(),
11157            }
11158        });
11159    }
11160
11161    pub fn convert_indentation_to_spaces(
11162        &mut self,
11163        _: &ConvertIndentationToSpaces,
11164        window: &mut Window,
11165        cx: &mut Context<Self>,
11166    ) {
11167        let settings = self.buffer.read(cx).language_settings(cx);
11168        let tab_size = settings.tab_size.get() as usize;
11169
11170        self.manipulate_mutable_lines(window, cx, |lines| {
11171            // Allocates a reasonably sized scratch buffer once for the whole loop
11172            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11173            // Avoids recomputing spaces that could be inserted many times
11174            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11175                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11176                .collect();
11177
11178            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11179                let mut chars = line.as_ref().chars();
11180                let mut col = 0;
11181                let mut changed = false;
11182
11183                for ch in chars.by_ref() {
11184                    match ch {
11185                        ' ' => {
11186                            reindented_line.push(' ');
11187                            col += 1;
11188                        }
11189                        '\t' => {
11190                            // \t are converted to spaces depending on the current column
11191                            let spaces_len = tab_size - (col % tab_size);
11192                            reindented_line.extend(&space_cache[spaces_len - 1]);
11193                            col += spaces_len;
11194                            changed = true;
11195                        }
11196                        _ => {
11197                            // If we dont append before break, the character is consumed
11198                            reindented_line.push(ch);
11199                            break;
11200                        }
11201                    }
11202                }
11203
11204                if !changed {
11205                    reindented_line.clear();
11206                    continue;
11207                }
11208                // Append the rest of the line and replace old reference with new one
11209                reindented_line.extend(chars);
11210                *line = Cow::Owned(reindented_line.clone());
11211                reindented_line.clear();
11212            }
11213        });
11214    }
11215
11216    pub fn convert_indentation_to_tabs(
11217        &mut self,
11218        _: &ConvertIndentationToTabs,
11219        window: &mut Window,
11220        cx: &mut Context<Self>,
11221    ) {
11222        let settings = self.buffer.read(cx).language_settings(cx);
11223        let tab_size = settings.tab_size.get() as usize;
11224
11225        self.manipulate_mutable_lines(window, cx, |lines| {
11226            // Allocates a reasonably sized buffer once for the whole loop
11227            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11228            // Avoids recomputing spaces that could be inserted many times
11229            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11230                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11231                .collect();
11232
11233            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11234                let mut chars = line.chars();
11235                let mut spaces_count = 0;
11236                let mut first_non_indent_char = None;
11237                let mut changed = false;
11238
11239                for ch in chars.by_ref() {
11240                    match ch {
11241                        ' ' => {
11242                            // Keep track of spaces. Append \t when we reach tab_size
11243                            spaces_count += 1;
11244                            changed = true;
11245                            if spaces_count == tab_size {
11246                                reindented_line.push('\t');
11247                                spaces_count = 0;
11248                            }
11249                        }
11250                        '\t' => {
11251                            reindented_line.push('\t');
11252                            spaces_count = 0;
11253                        }
11254                        _ => {
11255                            // Dont append it yet, we might have remaining spaces
11256                            first_non_indent_char = Some(ch);
11257                            break;
11258                        }
11259                    }
11260                }
11261
11262                if !changed {
11263                    reindented_line.clear();
11264                    continue;
11265                }
11266                // Remaining spaces that didn't make a full tab stop
11267                if spaces_count > 0 {
11268                    reindented_line.extend(&space_cache[spaces_count - 1]);
11269                }
11270                // If we consume an extra character that was not indentation, add it back
11271                if let Some(extra_char) = first_non_indent_char {
11272                    reindented_line.push(extra_char);
11273                }
11274                // Append the rest of the line and replace old reference with new one
11275                reindented_line.extend(chars);
11276                *line = Cow::Owned(reindented_line.clone());
11277                reindented_line.clear();
11278            }
11279        });
11280    }
11281
11282    pub fn convert_to_upper_case(
11283        &mut self,
11284        _: &ConvertToUpperCase,
11285        window: &mut Window,
11286        cx: &mut Context<Self>,
11287    ) {
11288        self.manipulate_text(window, cx, |text| text.to_uppercase())
11289    }
11290
11291    pub fn convert_to_lower_case(
11292        &mut self,
11293        _: &ConvertToLowerCase,
11294        window: &mut Window,
11295        cx: &mut Context<Self>,
11296    ) {
11297        self.manipulate_text(window, cx, |text| text.to_lowercase())
11298    }
11299
11300    pub fn convert_to_title_case(
11301        &mut self,
11302        _: &ConvertToTitleCase,
11303        window: &mut Window,
11304        cx: &mut Context<Self>,
11305    ) {
11306        self.manipulate_text(window, cx, |text| {
11307            text.split('\n')
11308                .map(|line| line.to_case(Case::Title))
11309                .join("\n")
11310        })
11311    }
11312
11313    pub fn convert_to_snake_case(
11314        &mut self,
11315        _: &ConvertToSnakeCase,
11316        window: &mut Window,
11317        cx: &mut Context<Self>,
11318    ) {
11319        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11320    }
11321
11322    pub fn convert_to_kebab_case(
11323        &mut self,
11324        _: &ConvertToKebabCase,
11325        window: &mut Window,
11326        cx: &mut Context<Self>,
11327    ) {
11328        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11329    }
11330
11331    pub fn convert_to_upper_camel_case(
11332        &mut self,
11333        _: &ConvertToUpperCamelCase,
11334        window: &mut Window,
11335        cx: &mut Context<Self>,
11336    ) {
11337        self.manipulate_text(window, cx, |text| {
11338            text.split('\n')
11339                .map(|line| line.to_case(Case::UpperCamel))
11340                .join("\n")
11341        })
11342    }
11343
11344    pub fn convert_to_lower_camel_case(
11345        &mut self,
11346        _: &ConvertToLowerCamelCase,
11347        window: &mut Window,
11348        cx: &mut Context<Self>,
11349    ) {
11350        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11351    }
11352
11353    pub fn convert_to_opposite_case(
11354        &mut self,
11355        _: &ConvertToOppositeCase,
11356        window: &mut Window,
11357        cx: &mut Context<Self>,
11358    ) {
11359        self.manipulate_text(window, cx, |text| {
11360            text.chars()
11361                .fold(String::with_capacity(text.len()), |mut t, c| {
11362                    if c.is_uppercase() {
11363                        t.extend(c.to_lowercase());
11364                    } else {
11365                        t.extend(c.to_uppercase());
11366                    }
11367                    t
11368                })
11369        })
11370    }
11371
11372    pub fn convert_to_sentence_case(
11373        &mut self,
11374        _: &ConvertToSentenceCase,
11375        window: &mut Window,
11376        cx: &mut Context<Self>,
11377    ) {
11378        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11379    }
11380
11381    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11382        self.manipulate_text(window, cx, |text| {
11383            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11384            if has_upper_case_characters {
11385                text.to_lowercase()
11386            } else {
11387                text.to_uppercase()
11388            }
11389        })
11390    }
11391
11392    pub fn convert_to_rot13(
11393        &mut self,
11394        _: &ConvertToRot13,
11395        window: &mut Window,
11396        cx: &mut Context<Self>,
11397    ) {
11398        self.manipulate_text(window, cx, |text| {
11399            text.chars()
11400                .map(|c| match c {
11401                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11402                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11403                    _ => c,
11404                })
11405                .collect()
11406        })
11407    }
11408
11409    pub fn convert_to_rot47(
11410        &mut self,
11411        _: &ConvertToRot47,
11412        window: &mut Window,
11413        cx: &mut Context<Self>,
11414    ) {
11415        self.manipulate_text(window, cx, |text| {
11416            text.chars()
11417                .map(|c| {
11418                    let code_point = c as u32;
11419                    if code_point >= 33 && code_point <= 126 {
11420                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11421                    }
11422                    c
11423                })
11424                .collect()
11425        })
11426    }
11427
11428    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11429    where
11430        Fn: FnMut(&str) -> String,
11431    {
11432        let buffer = self.buffer.read(cx).snapshot(cx);
11433
11434        let mut new_selections = Vec::new();
11435        let mut edits = Vec::new();
11436        let mut selection_adjustment = 0i32;
11437
11438        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11439            let selection_is_empty = selection.is_empty();
11440
11441            let (start, end) = if selection_is_empty {
11442                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11443                (word_range.start, word_range.end)
11444            } else {
11445                (
11446                    buffer.point_to_offset(selection.start),
11447                    buffer.point_to_offset(selection.end),
11448                )
11449            };
11450
11451            let text = buffer.text_for_range(start..end).collect::<String>();
11452            let old_length = text.len() as i32;
11453            let text = callback(&text);
11454
11455            new_selections.push(Selection {
11456                start: (start as i32 - selection_adjustment) as usize,
11457                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11458                goal: SelectionGoal::None,
11459                id: selection.id,
11460                reversed: selection.reversed,
11461            });
11462
11463            selection_adjustment += old_length - text.len() as i32;
11464
11465            edits.push((start..end, text));
11466        }
11467
11468        self.transact(window, cx, |this, window, cx| {
11469            this.buffer.update(cx, |buffer, cx| {
11470                buffer.edit(edits, None, cx);
11471            });
11472
11473            this.change_selections(Default::default(), window, cx, |s| {
11474                s.select(new_selections);
11475            });
11476
11477            this.request_autoscroll(Autoscroll::fit(), cx);
11478        });
11479    }
11480
11481    pub fn move_selection_on_drop(
11482        &mut self,
11483        selection: &Selection<Anchor>,
11484        target: DisplayPoint,
11485        is_cut: bool,
11486        window: &mut Window,
11487        cx: &mut Context<Self>,
11488    ) {
11489        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11490        let buffer = display_map.buffer_snapshot();
11491        let mut edits = Vec::new();
11492        let insert_point = display_map
11493            .clip_point(target, Bias::Left)
11494            .to_point(&display_map);
11495        let text = buffer
11496            .text_for_range(selection.start..selection.end)
11497            .collect::<String>();
11498        if is_cut {
11499            edits.push(((selection.start..selection.end), String::new()));
11500        }
11501        let insert_anchor = buffer.anchor_before(insert_point);
11502        edits.push(((insert_anchor..insert_anchor), text));
11503        let last_edit_start = insert_anchor.bias_left(buffer);
11504        let last_edit_end = insert_anchor.bias_right(buffer);
11505        self.transact(window, cx, |this, window, cx| {
11506            this.buffer.update(cx, |buffer, cx| {
11507                buffer.edit(edits, None, cx);
11508            });
11509            this.change_selections(Default::default(), window, cx, |s| {
11510                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11511            });
11512        });
11513    }
11514
11515    pub fn clear_selection_drag_state(&mut self) {
11516        self.selection_drag_state = SelectionDragState::None;
11517    }
11518
11519    pub fn duplicate(
11520        &mut self,
11521        upwards: bool,
11522        whole_lines: bool,
11523        window: &mut Window,
11524        cx: &mut Context<Self>,
11525    ) {
11526        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11527
11528        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11529        let buffer = display_map.buffer_snapshot();
11530        let selections = self.selections.all::<Point>(&display_map);
11531
11532        let mut edits = Vec::new();
11533        let mut selections_iter = selections.iter().peekable();
11534        while let Some(selection) = selections_iter.next() {
11535            let mut rows = selection.spanned_rows(false, &display_map);
11536            // duplicate line-wise
11537            if whole_lines || selection.start == selection.end {
11538                // Avoid duplicating the same lines twice.
11539                while let Some(next_selection) = selections_iter.peek() {
11540                    let next_rows = next_selection.spanned_rows(false, &display_map);
11541                    if next_rows.start < rows.end {
11542                        rows.end = next_rows.end;
11543                        selections_iter.next().unwrap();
11544                    } else {
11545                        break;
11546                    }
11547                }
11548
11549                // Copy the text from the selected row region and splice it either at the start
11550                // or end of the region.
11551                let start = Point::new(rows.start.0, 0);
11552                let end = Point::new(
11553                    rows.end.previous_row().0,
11554                    buffer.line_len(rows.end.previous_row()),
11555                );
11556
11557                let mut text = buffer.text_for_range(start..end).collect::<String>();
11558
11559                let insert_location = if upwards {
11560                    // When duplicating upward, we need to insert before the current line.
11561                    // If we're on the last line and it doesn't end with a newline,
11562                    // we need to add a newline before the duplicated content.
11563                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11564                        && buffer.max_point().column > 0
11565                        && !text.ends_with('\n');
11566
11567                    if needs_leading_newline {
11568                        text.insert(0, '\n');
11569                        end
11570                    } else {
11571                        text.push('\n');
11572                        Point::new(rows.start.0, 0)
11573                    }
11574                } else {
11575                    text.push('\n');
11576                    start
11577                };
11578                edits.push((insert_location..insert_location, text));
11579            } else {
11580                // duplicate character-wise
11581                let start = selection.start;
11582                let end = selection.end;
11583                let text = buffer.text_for_range(start..end).collect::<String>();
11584                edits.push((selection.end..selection.end, text));
11585            }
11586        }
11587
11588        self.transact(window, cx, |this, window, cx| {
11589            this.buffer.update(cx, |buffer, cx| {
11590                buffer.edit(edits, None, cx);
11591            });
11592
11593            // When duplicating upward with whole lines, move the cursor to the duplicated line
11594            if upwards && whole_lines {
11595                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11596
11597                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11598                    let mut new_ranges = Vec::new();
11599                    let selections = s.all::<Point>(&display_map);
11600                    let mut selections_iter = selections.iter().peekable();
11601
11602                    while let Some(first_selection) = selections_iter.next() {
11603                        // Group contiguous selections together to find the total row span
11604                        let mut group_selections = vec![first_selection];
11605                        let mut rows = first_selection.spanned_rows(false, &display_map);
11606
11607                        while let Some(next_selection) = selections_iter.peek() {
11608                            let next_rows = next_selection.spanned_rows(false, &display_map);
11609                            if next_rows.start < rows.end {
11610                                rows.end = next_rows.end;
11611                                group_selections.push(selections_iter.next().unwrap());
11612                            } else {
11613                                break;
11614                            }
11615                        }
11616
11617                        let row_count = rows.end.0 - rows.start.0;
11618
11619                        // Move all selections in this group up by the total number of duplicated rows
11620                        for selection in group_selections {
11621                            let new_start = Point::new(
11622                                selection.start.row.saturating_sub(row_count),
11623                                selection.start.column,
11624                            );
11625
11626                            let new_end = Point::new(
11627                                selection.end.row.saturating_sub(row_count),
11628                                selection.end.column,
11629                            );
11630
11631                            new_ranges.push(new_start..new_end);
11632                        }
11633                    }
11634
11635                    s.select_ranges(new_ranges);
11636                });
11637            }
11638
11639            this.request_autoscroll(Autoscroll::fit(), cx);
11640        });
11641    }
11642
11643    pub fn duplicate_line_up(
11644        &mut self,
11645        _: &DuplicateLineUp,
11646        window: &mut Window,
11647        cx: &mut Context<Self>,
11648    ) {
11649        self.duplicate(true, true, window, cx);
11650    }
11651
11652    pub fn duplicate_line_down(
11653        &mut self,
11654        _: &DuplicateLineDown,
11655        window: &mut Window,
11656        cx: &mut Context<Self>,
11657    ) {
11658        self.duplicate(false, true, window, cx);
11659    }
11660
11661    pub fn duplicate_selection(
11662        &mut self,
11663        _: &DuplicateSelection,
11664        window: &mut Window,
11665        cx: &mut Context<Self>,
11666    ) {
11667        self.duplicate(false, false, window, cx);
11668    }
11669
11670    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11671        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11672        if self.mode.is_single_line() {
11673            cx.propagate();
11674            return;
11675        }
11676
11677        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11678        let buffer = self.buffer.read(cx).snapshot(cx);
11679
11680        let mut edits = Vec::new();
11681        let mut unfold_ranges = Vec::new();
11682        let mut refold_creases = Vec::new();
11683
11684        let selections = self.selections.all::<Point>(&display_map);
11685        let mut selections = selections.iter().peekable();
11686        let mut contiguous_row_selections = Vec::new();
11687        let mut new_selections = Vec::new();
11688
11689        while let Some(selection) = selections.next() {
11690            // Find all the selections that span a contiguous row range
11691            let (start_row, end_row) = consume_contiguous_rows(
11692                &mut contiguous_row_selections,
11693                selection,
11694                &display_map,
11695                &mut selections,
11696            );
11697
11698            // Move the text spanned by the row range to be before the line preceding the row range
11699            if start_row.0 > 0 {
11700                let range_to_move = Point::new(
11701                    start_row.previous_row().0,
11702                    buffer.line_len(start_row.previous_row()),
11703                )
11704                    ..Point::new(
11705                        end_row.previous_row().0,
11706                        buffer.line_len(end_row.previous_row()),
11707                    );
11708                let insertion_point = display_map
11709                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11710                    .0;
11711
11712                // Don't move lines across excerpts
11713                if buffer
11714                    .excerpt_containing(insertion_point..range_to_move.end)
11715                    .is_some()
11716                {
11717                    let text = buffer
11718                        .text_for_range(range_to_move.clone())
11719                        .flat_map(|s| s.chars())
11720                        .skip(1)
11721                        .chain(['\n'])
11722                        .collect::<String>();
11723
11724                    edits.push((
11725                        buffer.anchor_after(range_to_move.start)
11726                            ..buffer.anchor_before(range_to_move.end),
11727                        String::new(),
11728                    ));
11729                    let insertion_anchor = buffer.anchor_after(insertion_point);
11730                    edits.push((insertion_anchor..insertion_anchor, text));
11731
11732                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11733
11734                    // Move selections up
11735                    new_selections.extend(contiguous_row_selections.drain(..).map(
11736                        |mut selection| {
11737                            selection.start.row -= row_delta;
11738                            selection.end.row -= row_delta;
11739                            selection
11740                        },
11741                    ));
11742
11743                    // Move folds up
11744                    unfold_ranges.push(range_to_move.clone());
11745                    for fold in display_map.folds_in_range(
11746                        buffer.anchor_before(range_to_move.start)
11747                            ..buffer.anchor_after(range_to_move.end),
11748                    ) {
11749                        let mut start = fold.range.start.to_point(&buffer);
11750                        let mut end = fold.range.end.to_point(&buffer);
11751                        start.row -= row_delta;
11752                        end.row -= row_delta;
11753                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11754                    }
11755                }
11756            }
11757
11758            // If we didn't move line(s), preserve the existing selections
11759            new_selections.append(&mut contiguous_row_selections);
11760        }
11761
11762        self.transact(window, cx, |this, window, cx| {
11763            this.unfold_ranges(&unfold_ranges, true, true, cx);
11764            this.buffer.update(cx, |buffer, cx| {
11765                for (range, text) in edits {
11766                    buffer.edit([(range, text)], None, cx);
11767                }
11768            });
11769            this.fold_creases(refold_creases, true, window, cx);
11770            this.change_selections(Default::default(), window, cx, |s| {
11771                s.select(new_selections);
11772            })
11773        });
11774    }
11775
11776    pub fn move_line_down(
11777        &mut self,
11778        _: &MoveLineDown,
11779        window: &mut Window,
11780        cx: &mut Context<Self>,
11781    ) {
11782        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11783        if self.mode.is_single_line() {
11784            cx.propagate();
11785            return;
11786        }
11787
11788        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11789        let buffer = self.buffer.read(cx).snapshot(cx);
11790
11791        let mut edits = Vec::new();
11792        let mut unfold_ranges = Vec::new();
11793        let mut refold_creases = Vec::new();
11794
11795        let selections = self.selections.all::<Point>(&display_map);
11796        let mut selections = selections.iter().peekable();
11797        let mut contiguous_row_selections = Vec::new();
11798        let mut new_selections = Vec::new();
11799
11800        while let Some(selection) = selections.next() {
11801            // Find all the selections that span a contiguous row range
11802            let (start_row, end_row) = consume_contiguous_rows(
11803                &mut contiguous_row_selections,
11804                selection,
11805                &display_map,
11806                &mut selections,
11807            );
11808
11809            // Move the text spanned by the row range to be after the last line of the row range
11810            if end_row.0 <= buffer.max_point().row {
11811                let range_to_move =
11812                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11813                let insertion_point = display_map
11814                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11815                    .0;
11816
11817                // Don't move lines across excerpt boundaries
11818                if buffer
11819                    .excerpt_containing(range_to_move.start..insertion_point)
11820                    .is_some()
11821                {
11822                    let mut text = String::from("\n");
11823                    text.extend(buffer.text_for_range(range_to_move.clone()));
11824                    text.pop(); // Drop trailing newline
11825                    edits.push((
11826                        buffer.anchor_after(range_to_move.start)
11827                            ..buffer.anchor_before(range_to_move.end),
11828                        String::new(),
11829                    ));
11830                    let insertion_anchor = buffer.anchor_after(insertion_point);
11831                    edits.push((insertion_anchor..insertion_anchor, text));
11832
11833                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11834
11835                    // Move selections down
11836                    new_selections.extend(contiguous_row_selections.drain(..).map(
11837                        |mut selection| {
11838                            selection.start.row += row_delta;
11839                            selection.end.row += row_delta;
11840                            selection
11841                        },
11842                    ));
11843
11844                    // Move folds down
11845                    unfold_ranges.push(range_to_move.clone());
11846                    for fold in display_map.folds_in_range(
11847                        buffer.anchor_before(range_to_move.start)
11848                            ..buffer.anchor_after(range_to_move.end),
11849                    ) {
11850                        let mut start = fold.range.start.to_point(&buffer);
11851                        let mut end = fold.range.end.to_point(&buffer);
11852                        start.row += row_delta;
11853                        end.row += row_delta;
11854                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11855                    }
11856                }
11857            }
11858
11859            // If we didn't move line(s), preserve the existing selections
11860            new_selections.append(&mut contiguous_row_selections);
11861        }
11862
11863        self.transact(window, cx, |this, window, cx| {
11864            this.unfold_ranges(&unfold_ranges, true, true, cx);
11865            this.buffer.update(cx, |buffer, cx| {
11866                for (range, text) in edits {
11867                    buffer.edit([(range, text)], None, cx);
11868                }
11869            });
11870            this.fold_creases(refold_creases, true, window, cx);
11871            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11872        });
11873    }
11874
11875    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11876        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11877        let text_layout_details = &self.text_layout_details(window);
11878        self.transact(window, cx, |this, window, cx| {
11879            let edits = this.change_selections(Default::default(), window, cx, |s| {
11880                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11881                s.move_with(|display_map, selection| {
11882                    if !selection.is_empty() {
11883                        return;
11884                    }
11885
11886                    let mut head = selection.head();
11887                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11888                    if head.column() == display_map.line_len(head.row()) {
11889                        transpose_offset = display_map
11890                            .buffer_snapshot()
11891                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11892                    }
11893
11894                    if transpose_offset == 0 {
11895                        return;
11896                    }
11897
11898                    *head.column_mut() += 1;
11899                    head = display_map.clip_point(head, Bias::Right);
11900                    let goal = SelectionGoal::HorizontalPosition(
11901                        display_map
11902                            .x_for_display_point(head, text_layout_details)
11903                            .into(),
11904                    );
11905                    selection.collapse_to(head, goal);
11906
11907                    let transpose_start = display_map
11908                        .buffer_snapshot()
11909                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11910                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11911                        let transpose_end = display_map
11912                            .buffer_snapshot()
11913                            .clip_offset(transpose_offset + 1, Bias::Right);
11914                        if let Some(ch) = display_map
11915                            .buffer_snapshot()
11916                            .chars_at(transpose_start)
11917                            .next()
11918                        {
11919                            edits.push((transpose_start..transpose_offset, String::new()));
11920                            edits.push((transpose_end..transpose_end, ch.to_string()));
11921                        }
11922                    }
11923                });
11924                edits
11925            });
11926            this.buffer
11927                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11928            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
11929            this.change_selections(Default::default(), window, cx, |s| {
11930                s.select(selections);
11931            });
11932        });
11933    }
11934
11935    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11936        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11937        if self.mode.is_single_line() {
11938            cx.propagate();
11939            return;
11940        }
11941
11942        self.rewrap_impl(RewrapOptions::default(), cx)
11943    }
11944
11945    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11946        let buffer = self.buffer.read(cx).snapshot(cx);
11947        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
11948
11949        #[derive(Clone, Debug, PartialEq)]
11950        enum CommentFormat {
11951            /// single line comment, with prefix for line
11952            Line(String),
11953            /// single line within a block comment, with prefix for line
11954            BlockLine(String),
11955            /// a single line of a block comment that includes the initial delimiter
11956            BlockCommentWithStart(BlockCommentConfig),
11957            /// a single line of a block comment that includes the ending delimiter
11958            BlockCommentWithEnd(BlockCommentConfig),
11959        }
11960
11961        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11962        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11963            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11964                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11965                .peekable();
11966
11967            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11968                row
11969            } else {
11970                return Vec::new();
11971            };
11972
11973            let language_settings = buffer.language_settings_at(selection.head(), cx);
11974            let language_scope = buffer.language_scope_at(selection.head());
11975
11976            let indent_and_prefix_for_row =
11977                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11978                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11979                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11980                        &language_scope
11981                    {
11982                        let indent_end = Point::new(row, indent.len);
11983                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11984                        let line_text_after_indent = buffer
11985                            .text_for_range(indent_end..line_end)
11986                            .collect::<String>();
11987
11988                        let is_within_comment_override = buffer
11989                            .language_scope_at(indent_end)
11990                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11991                        let comment_delimiters = if is_within_comment_override {
11992                            // we are within a comment syntax node, but we don't
11993                            // yet know what kind of comment: block, doc or line
11994                            match (
11995                                language_scope.documentation_comment(),
11996                                language_scope.block_comment(),
11997                            ) {
11998                                (Some(config), _) | (_, Some(config))
11999                                    if buffer.contains_str_at(indent_end, &config.start) =>
12000                                {
12001                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12002                                }
12003                                (Some(config), _) | (_, Some(config))
12004                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12005                                {
12006                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12007                                }
12008                                (Some(config), _) | (_, Some(config))
12009                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12010                                {
12011                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12012                                }
12013                                (_, _) => language_scope
12014                                    .line_comment_prefixes()
12015                                    .iter()
12016                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12017                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12018                            }
12019                        } else {
12020                            // we not in an overridden comment node, but we may
12021                            // be within a non-overridden line comment node
12022                            language_scope
12023                                .line_comment_prefixes()
12024                                .iter()
12025                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12026                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12027                        };
12028
12029                        let rewrap_prefix = language_scope
12030                            .rewrap_prefixes()
12031                            .iter()
12032                            .find_map(|prefix_regex| {
12033                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12034                                    if mat.start() == 0 {
12035                                        Some(mat.as_str().to_string())
12036                                    } else {
12037                                        None
12038                                    }
12039                                })
12040                            })
12041                            .flatten();
12042                        (comment_delimiters, rewrap_prefix)
12043                    } else {
12044                        (None, None)
12045                    };
12046                    (indent, comment_prefix, rewrap_prefix)
12047                };
12048
12049            let mut ranges = Vec::new();
12050            let from_empty_selection = selection.is_empty();
12051
12052            let mut current_range_start = first_row;
12053            let mut prev_row = first_row;
12054            let (
12055                mut current_range_indent,
12056                mut current_range_comment_delimiters,
12057                mut current_range_rewrap_prefix,
12058            ) = indent_and_prefix_for_row(first_row);
12059
12060            for row in non_blank_rows_iter.skip(1) {
12061                let has_paragraph_break = row > prev_row + 1;
12062
12063                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12064                    indent_and_prefix_for_row(row);
12065
12066                let has_indent_change = row_indent != current_range_indent;
12067                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12068
12069                let has_boundary_change = has_comment_change
12070                    || row_rewrap_prefix.is_some()
12071                    || (has_indent_change && current_range_comment_delimiters.is_some());
12072
12073                if has_paragraph_break || has_boundary_change {
12074                    ranges.push((
12075                        language_settings.clone(),
12076                        Point::new(current_range_start, 0)
12077                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12078                        current_range_indent,
12079                        current_range_comment_delimiters.clone(),
12080                        current_range_rewrap_prefix.clone(),
12081                        from_empty_selection,
12082                    ));
12083                    current_range_start = row;
12084                    current_range_indent = row_indent;
12085                    current_range_comment_delimiters = row_comment_delimiters;
12086                    current_range_rewrap_prefix = row_rewrap_prefix;
12087                }
12088                prev_row = row;
12089            }
12090
12091            ranges.push((
12092                language_settings.clone(),
12093                Point::new(current_range_start, 0)
12094                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12095                current_range_indent,
12096                current_range_comment_delimiters,
12097                current_range_rewrap_prefix,
12098                from_empty_selection,
12099            ));
12100
12101            ranges
12102        });
12103
12104        let mut edits = Vec::new();
12105        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12106
12107        for (
12108            language_settings,
12109            wrap_range,
12110            mut indent_size,
12111            comment_prefix,
12112            rewrap_prefix,
12113            from_empty_selection,
12114        ) in wrap_ranges
12115        {
12116            let mut start_row = wrap_range.start.row;
12117            let mut end_row = wrap_range.end.row;
12118
12119            // Skip selections that overlap with a range that has already been rewrapped.
12120            let selection_range = start_row..end_row;
12121            if rewrapped_row_ranges
12122                .iter()
12123                .any(|range| range.overlaps(&selection_range))
12124            {
12125                continue;
12126            }
12127
12128            let tab_size = language_settings.tab_size;
12129
12130            let (line_prefix, inside_comment) = match &comment_prefix {
12131                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12132                    (Some(prefix.as_str()), true)
12133                }
12134                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12135                    (Some(prefix.as_ref()), true)
12136                }
12137                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12138                    start: _,
12139                    end: _,
12140                    prefix,
12141                    tab_size,
12142                })) => {
12143                    indent_size.len += tab_size;
12144                    (Some(prefix.as_ref()), true)
12145                }
12146                None => (None, false),
12147            };
12148            let indent_prefix = indent_size.chars().collect::<String>();
12149            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12150
12151            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12152                RewrapBehavior::InComments => inside_comment,
12153                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12154                RewrapBehavior::Anywhere => true,
12155            };
12156
12157            let should_rewrap = options.override_language_settings
12158                || allow_rewrap_based_on_language
12159                || self.hard_wrap.is_some();
12160            if !should_rewrap {
12161                continue;
12162            }
12163
12164            if from_empty_selection {
12165                'expand_upwards: while start_row > 0 {
12166                    let prev_row = start_row - 1;
12167                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12168                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12169                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12170                    {
12171                        start_row = prev_row;
12172                    } else {
12173                        break 'expand_upwards;
12174                    }
12175                }
12176
12177                'expand_downwards: while end_row < buffer.max_point().row {
12178                    let next_row = end_row + 1;
12179                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12180                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12181                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12182                    {
12183                        end_row = next_row;
12184                    } else {
12185                        break 'expand_downwards;
12186                    }
12187                }
12188            }
12189
12190            let start = Point::new(start_row, 0);
12191            let start_offset = ToOffset::to_offset(&start, &buffer);
12192            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12193            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12194            let mut first_line_delimiter = None;
12195            let mut last_line_delimiter = None;
12196            let Some(lines_without_prefixes) = selection_text
12197                .lines()
12198                .enumerate()
12199                .map(|(ix, line)| {
12200                    let line_trimmed = line.trim_start();
12201                    if rewrap_prefix.is_some() && ix > 0 {
12202                        Ok(line_trimmed)
12203                    } else if let Some(
12204                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12205                            start,
12206                            prefix,
12207                            end,
12208                            tab_size,
12209                        })
12210                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12211                            start,
12212                            prefix,
12213                            end,
12214                            tab_size,
12215                        }),
12216                    ) = &comment_prefix
12217                    {
12218                        let line_trimmed = line_trimmed
12219                            .strip_prefix(start.as_ref())
12220                            .map(|s| {
12221                                let mut indent_size = indent_size;
12222                                indent_size.len -= tab_size;
12223                                let indent_prefix: String = indent_size.chars().collect();
12224                                first_line_delimiter = Some((indent_prefix, start));
12225                                s.trim_start()
12226                            })
12227                            .unwrap_or(line_trimmed);
12228                        let line_trimmed = line_trimmed
12229                            .strip_suffix(end.as_ref())
12230                            .map(|s| {
12231                                last_line_delimiter = Some(end);
12232                                s.trim_end()
12233                            })
12234                            .unwrap_or(line_trimmed);
12235                        let line_trimmed = line_trimmed
12236                            .strip_prefix(prefix.as_ref())
12237                            .unwrap_or(line_trimmed);
12238                        Ok(line_trimmed)
12239                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12240                        line_trimmed.strip_prefix(prefix).with_context(|| {
12241                            format!("line did not start with prefix {prefix:?}: {line:?}")
12242                        })
12243                    } else {
12244                        line_trimmed
12245                            .strip_prefix(&line_prefix.trim_start())
12246                            .with_context(|| {
12247                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12248                            })
12249                    }
12250                })
12251                .collect::<Result<Vec<_>, _>>()
12252                .log_err()
12253            else {
12254                continue;
12255            };
12256
12257            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12258                buffer
12259                    .language_settings_at(Point::new(start_row, 0), cx)
12260                    .preferred_line_length as usize
12261            });
12262
12263            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12264                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12265            } else {
12266                line_prefix.clone()
12267            };
12268
12269            let wrapped_text = {
12270                let mut wrapped_text = wrap_with_prefix(
12271                    line_prefix,
12272                    subsequent_lines_prefix,
12273                    lines_without_prefixes.join("\n"),
12274                    wrap_column,
12275                    tab_size,
12276                    options.preserve_existing_whitespace,
12277                );
12278
12279                if let Some((indent, delimiter)) = first_line_delimiter {
12280                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12281                }
12282                if let Some(last_line) = last_line_delimiter {
12283                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12284                }
12285
12286                wrapped_text
12287            };
12288
12289            // TODO: should always use char-based diff while still supporting cursor behavior that
12290            // matches vim.
12291            let mut diff_options = DiffOptions::default();
12292            if options.override_language_settings {
12293                diff_options.max_word_diff_len = 0;
12294                diff_options.max_word_diff_line_count = 0;
12295            } else {
12296                diff_options.max_word_diff_len = usize::MAX;
12297                diff_options.max_word_diff_line_count = usize::MAX;
12298            }
12299
12300            for (old_range, new_text) in
12301                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12302            {
12303                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12304                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12305                edits.push((edit_start..edit_end, new_text));
12306            }
12307
12308            rewrapped_row_ranges.push(start_row..=end_row);
12309        }
12310
12311        self.buffer
12312            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12313    }
12314
12315    pub fn cut_common(
12316        &mut self,
12317        cut_no_selection_line: bool,
12318        window: &mut Window,
12319        cx: &mut Context<Self>,
12320    ) -> ClipboardItem {
12321        let mut text = String::new();
12322        let buffer = self.buffer.read(cx).snapshot(cx);
12323        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12324        let mut clipboard_selections = Vec::with_capacity(selections.len());
12325        {
12326            let max_point = buffer.max_point();
12327            let mut is_first = true;
12328            for selection in &mut selections {
12329                let is_entire_line =
12330                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12331                if is_entire_line {
12332                    selection.start = Point::new(selection.start.row, 0);
12333                    if !selection.is_empty() && selection.end.column == 0 {
12334                        selection.end = cmp::min(max_point, selection.end);
12335                    } else {
12336                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12337                    }
12338                    selection.goal = SelectionGoal::None;
12339                }
12340                if is_first {
12341                    is_first = false;
12342                } else {
12343                    text += "\n";
12344                }
12345                let mut len = 0;
12346                for chunk in buffer.text_for_range(selection.start..selection.end) {
12347                    text.push_str(chunk);
12348                    len += chunk.len();
12349                }
12350                clipboard_selections.push(ClipboardSelection {
12351                    len,
12352                    is_entire_line,
12353                    first_line_indent: buffer
12354                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12355                        .len,
12356                });
12357            }
12358        }
12359
12360        self.transact(window, cx, |this, window, cx| {
12361            this.change_selections(Default::default(), window, cx, |s| {
12362                s.select(selections);
12363            });
12364            this.insert("", window, cx);
12365        });
12366        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12367    }
12368
12369    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12370        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12371        let item = self.cut_common(true, window, cx);
12372        cx.write_to_clipboard(item);
12373    }
12374
12375    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12376        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12377        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12378            s.move_with(|snapshot, sel| {
12379                if sel.is_empty() {
12380                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12381                }
12382                if sel.is_empty() {
12383                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12384                }
12385            });
12386        });
12387        let item = self.cut_common(false, window, cx);
12388        cx.set_global(KillRing(item))
12389    }
12390
12391    pub fn kill_ring_yank(
12392        &mut self,
12393        _: &KillRingYank,
12394        window: &mut Window,
12395        cx: &mut Context<Self>,
12396    ) {
12397        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12398        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12399            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12400                (kill_ring.text().to_string(), kill_ring.metadata_json())
12401            } else {
12402                return;
12403            }
12404        } else {
12405            return;
12406        };
12407        self.do_paste(&text, metadata, false, window, cx);
12408    }
12409
12410    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12411        self.do_copy(true, cx);
12412    }
12413
12414    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12415        self.do_copy(false, cx);
12416    }
12417
12418    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12419        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12420        let buffer = self.buffer.read(cx).read(cx);
12421        let mut text = String::new();
12422
12423        let mut clipboard_selections = Vec::with_capacity(selections.len());
12424        {
12425            let max_point = buffer.max_point();
12426            let mut is_first = true;
12427            for selection in &selections {
12428                let mut start = selection.start;
12429                let mut end = selection.end;
12430                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12431                let mut add_trailing_newline = false;
12432                if is_entire_line {
12433                    start = Point::new(start.row, 0);
12434                    let next_line_start = Point::new(end.row + 1, 0);
12435                    if next_line_start <= max_point {
12436                        end = next_line_start;
12437                    } else {
12438                        // We're on the last line without a trailing newline.
12439                        // Copy to the end of the line and add a newline afterwards.
12440                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12441                        add_trailing_newline = true;
12442                    }
12443                }
12444
12445                let mut trimmed_selections = Vec::new();
12446                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12447                    let row = MultiBufferRow(start.row);
12448                    let first_indent = buffer.indent_size_for_line(row);
12449                    if first_indent.len == 0 || start.column > first_indent.len {
12450                        trimmed_selections.push(start..end);
12451                    } else {
12452                        trimmed_selections.push(
12453                            Point::new(row.0, first_indent.len)
12454                                ..Point::new(row.0, buffer.line_len(row)),
12455                        );
12456                        for row in start.row + 1..=end.row {
12457                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12458                            if row == end.row {
12459                                line_len = end.column;
12460                            }
12461                            if line_len == 0 {
12462                                trimmed_selections
12463                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12464                                continue;
12465                            }
12466                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12467                            if row_indent_size.len >= first_indent.len {
12468                                trimmed_selections.push(
12469                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12470                                );
12471                            } else {
12472                                trimmed_selections.clear();
12473                                trimmed_selections.push(start..end);
12474                                break;
12475                            }
12476                        }
12477                    }
12478                } else {
12479                    trimmed_selections.push(start..end);
12480                }
12481
12482                for trimmed_range in trimmed_selections {
12483                    if is_first {
12484                        is_first = false;
12485                    } else {
12486                        text += "\n";
12487                    }
12488                    let mut len = 0;
12489                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12490                        text.push_str(chunk);
12491                        len += chunk.len();
12492                    }
12493                    if add_trailing_newline {
12494                        text.push('\n');
12495                        len += 1;
12496                    }
12497                    clipboard_selections.push(ClipboardSelection {
12498                        len,
12499                        is_entire_line,
12500                        first_line_indent: buffer
12501                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12502                            .len,
12503                    });
12504                }
12505            }
12506        }
12507
12508        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12509            text,
12510            clipboard_selections,
12511        ));
12512    }
12513
12514    pub fn do_paste(
12515        &mut self,
12516        text: &String,
12517        clipboard_selections: Option<Vec<ClipboardSelection>>,
12518        handle_entire_lines: bool,
12519        window: &mut Window,
12520        cx: &mut Context<Self>,
12521    ) {
12522        if self.read_only(cx) {
12523            return;
12524        }
12525
12526        let clipboard_text = Cow::Borrowed(text.as_str());
12527
12528        self.transact(window, cx, |this, window, cx| {
12529            let had_active_edit_prediction = this.has_active_edit_prediction();
12530            let display_map = this.display_snapshot(cx);
12531            let old_selections = this.selections.all::<usize>(&display_map);
12532            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12533
12534            if let Some(mut clipboard_selections) = clipboard_selections {
12535                let all_selections_were_entire_line =
12536                    clipboard_selections.iter().all(|s| s.is_entire_line);
12537                let first_selection_indent_column =
12538                    clipboard_selections.first().map(|s| s.first_line_indent);
12539                if clipboard_selections.len() != old_selections.len() {
12540                    clipboard_selections.drain(..);
12541                }
12542                let mut auto_indent_on_paste = true;
12543
12544                this.buffer.update(cx, |buffer, cx| {
12545                    let snapshot = buffer.read(cx);
12546                    auto_indent_on_paste = snapshot
12547                        .language_settings_at(cursor_offset, cx)
12548                        .auto_indent_on_paste;
12549
12550                    let mut start_offset = 0;
12551                    let mut edits = Vec::new();
12552                    let mut original_indent_columns = Vec::new();
12553                    for (ix, selection) in old_selections.iter().enumerate() {
12554                        let to_insert;
12555                        let entire_line;
12556                        let original_indent_column;
12557                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12558                            let end_offset = start_offset + clipboard_selection.len;
12559                            to_insert = &clipboard_text[start_offset..end_offset];
12560                            entire_line = clipboard_selection.is_entire_line;
12561                            start_offset = end_offset + 1;
12562                            original_indent_column = Some(clipboard_selection.first_line_indent);
12563                        } else {
12564                            to_insert = &*clipboard_text;
12565                            entire_line = all_selections_were_entire_line;
12566                            original_indent_column = first_selection_indent_column
12567                        }
12568
12569                        let (range, to_insert) =
12570                            if selection.is_empty() && handle_entire_lines && entire_line {
12571                                // If the corresponding selection was empty when this slice of the
12572                                // clipboard text was written, then the entire line containing the
12573                                // selection was copied. If this selection is also currently empty,
12574                                // then paste the line before the current line of the buffer.
12575                                let column = selection.start.to_point(&snapshot).column as usize;
12576                                let line_start = selection.start - column;
12577                                (line_start..line_start, Cow::Borrowed(to_insert))
12578                            } else {
12579                                let language = snapshot.language_at(selection.head());
12580                                let range = selection.range();
12581                                if let Some(language) = language
12582                                    && language.name() == "Markdown".into()
12583                                {
12584                                    edit_for_markdown_paste(
12585                                        &snapshot,
12586                                        range,
12587                                        to_insert,
12588                                        url::Url::parse(to_insert).ok(),
12589                                    )
12590                                } else {
12591                                    (range, Cow::Borrowed(to_insert))
12592                                }
12593                            };
12594
12595                        edits.push((range, to_insert));
12596                        original_indent_columns.push(original_indent_column);
12597                    }
12598                    drop(snapshot);
12599
12600                    buffer.edit(
12601                        edits,
12602                        if auto_indent_on_paste {
12603                            Some(AutoindentMode::Block {
12604                                original_indent_columns,
12605                            })
12606                        } else {
12607                            None
12608                        },
12609                        cx,
12610                    );
12611                });
12612
12613                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12614                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12615            } else {
12616                let url = url::Url::parse(&clipboard_text).ok();
12617
12618                let auto_indent_mode = if !clipboard_text.is_empty() {
12619                    Some(AutoindentMode::Block {
12620                        original_indent_columns: Vec::new(),
12621                    })
12622                } else {
12623                    None
12624                };
12625
12626                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12627                    let snapshot = buffer.snapshot(cx);
12628
12629                    let anchors = old_selections
12630                        .iter()
12631                        .map(|s| {
12632                            let anchor = snapshot.anchor_after(s.head());
12633                            s.map(|_| anchor)
12634                        })
12635                        .collect::<Vec<_>>();
12636
12637                    let mut edits = Vec::new();
12638
12639                    for selection in old_selections.iter() {
12640                        let language = snapshot.language_at(selection.head());
12641                        let range = selection.range();
12642
12643                        let (edit_range, edit_text) = if let Some(language) = language
12644                            && language.name() == "Markdown".into()
12645                        {
12646                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12647                        } else {
12648                            (range, clipboard_text.clone())
12649                        };
12650
12651                        edits.push((edit_range, edit_text));
12652                    }
12653
12654                    drop(snapshot);
12655                    buffer.edit(edits, auto_indent_mode, cx);
12656
12657                    anchors
12658                });
12659
12660                this.change_selections(Default::default(), window, cx, |s| {
12661                    s.select_anchors(selection_anchors);
12662                });
12663            }
12664
12665            let trigger_in_words =
12666                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12667
12668            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12669        });
12670    }
12671
12672    pub fn diff_clipboard_with_selection(
12673        &mut self,
12674        _: &DiffClipboardWithSelection,
12675        window: &mut Window,
12676        cx: &mut Context<Self>,
12677    ) {
12678        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12679
12680        if selections.is_empty() {
12681            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12682            return;
12683        };
12684
12685        let clipboard_text = match cx.read_from_clipboard() {
12686            Some(item) => match item.entries().first() {
12687                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12688                _ => None,
12689            },
12690            None => None,
12691        };
12692
12693        let Some(clipboard_text) = clipboard_text else {
12694            log::warn!("Clipboard doesn't contain text.");
12695            return;
12696        };
12697
12698        window.dispatch_action(
12699            Box::new(DiffClipboardWithSelectionData {
12700                clipboard_text,
12701                editor: cx.entity(),
12702            }),
12703            cx,
12704        );
12705    }
12706
12707    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12708        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12709        if let Some(item) = cx.read_from_clipboard() {
12710            let entries = item.entries();
12711
12712            match entries.first() {
12713                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12714                // of all the pasted entries.
12715                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12716                    .do_paste(
12717                        clipboard_string.text(),
12718                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12719                        true,
12720                        window,
12721                        cx,
12722                    ),
12723                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12724            }
12725        }
12726    }
12727
12728    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12729        if self.read_only(cx) {
12730            return;
12731        }
12732
12733        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12734
12735        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12736            if let Some((selections, _)) =
12737                self.selection_history.transaction(transaction_id).cloned()
12738            {
12739                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12740                    s.select_anchors(selections.to_vec());
12741                });
12742            } else {
12743                log::error!(
12744                    "No entry in selection_history found for undo. \
12745                     This may correspond to a bug where undo does not update the selection. \
12746                     If this is occurring, please add details to \
12747                     https://github.com/zed-industries/zed/issues/22692"
12748                );
12749            }
12750            self.request_autoscroll(Autoscroll::fit(), cx);
12751            self.unmark_text(window, cx);
12752            self.refresh_edit_prediction(true, false, window, cx);
12753            cx.emit(EditorEvent::Edited { transaction_id });
12754            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12755        }
12756    }
12757
12758    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12759        if self.read_only(cx) {
12760            return;
12761        }
12762
12763        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12764
12765        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12766            if let Some((_, Some(selections))) =
12767                self.selection_history.transaction(transaction_id).cloned()
12768            {
12769                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12770                    s.select_anchors(selections.to_vec());
12771                });
12772            } else {
12773                log::error!(
12774                    "No entry in selection_history found for redo. \
12775                     This may correspond to a bug where undo does not update the selection. \
12776                     If this is occurring, please add details to \
12777                     https://github.com/zed-industries/zed/issues/22692"
12778                );
12779            }
12780            self.request_autoscroll(Autoscroll::fit(), cx);
12781            self.unmark_text(window, cx);
12782            self.refresh_edit_prediction(true, false, window, cx);
12783            cx.emit(EditorEvent::Edited { transaction_id });
12784        }
12785    }
12786
12787    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12788        self.buffer
12789            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12790    }
12791
12792    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12793        self.buffer
12794            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12795    }
12796
12797    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12798        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12799        self.change_selections(Default::default(), window, cx, |s| {
12800            s.move_with(|map, selection| {
12801                let cursor = if selection.is_empty() {
12802                    movement::left(map, selection.start)
12803                } else {
12804                    selection.start
12805                };
12806                selection.collapse_to(cursor, SelectionGoal::None);
12807            });
12808        })
12809    }
12810
12811    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12812        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12813        self.change_selections(Default::default(), window, cx, |s| {
12814            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12815        })
12816    }
12817
12818    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12819        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12820        self.change_selections(Default::default(), window, cx, |s| {
12821            s.move_with(|map, selection| {
12822                let cursor = if selection.is_empty() {
12823                    movement::right(map, selection.end)
12824                } else {
12825                    selection.end
12826                };
12827                selection.collapse_to(cursor, SelectionGoal::None)
12828            });
12829        })
12830    }
12831
12832    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12833        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12834        self.change_selections(Default::default(), window, cx, |s| {
12835            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12836        });
12837    }
12838
12839    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12840        if self.take_rename(true, window, cx).is_some() {
12841            return;
12842        }
12843
12844        if self.mode.is_single_line() {
12845            cx.propagate();
12846            return;
12847        }
12848
12849        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12850
12851        let text_layout_details = &self.text_layout_details(window);
12852        let selection_count = self.selections.count();
12853        let first_selection = self.selections.first_anchor();
12854
12855        self.change_selections(Default::default(), window, cx, |s| {
12856            s.move_with(|map, selection| {
12857                if !selection.is_empty() {
12858                    selection.goal = SelectionGoal::None;
12859                }
12860                let (cursor, goal) = movement::up(
12861                    map,
12862                    selection.start,
12863                    selection.goal,
12864                    false,
12865                    text_layout_details,
12866                );
12867                selection.collapse_to(cursor, goal);
12868            });
12869        });
12870
12871        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12872        {
12873            cx.propagate();
12874        }
12875    }
12876
12877    pub fn move_up_by_lines(
12878        &mut self,
12879        action: &MoveUpByLines,
12880        window: &mut Window,
12881        cx: &mut Context<Self>,
12882    ) {
12883        if self.take_rename(true, window, cx).is_some() {
12884            return;
12885        }
12886
12887        if self.mode.is_single_line() {
12888            cx.propagate();
12889            return;
12890        }
12891
12892        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12893
12894        let text_layout_details = &self.text_layout_details(window);
12895
12896        self.change_selections(Default::default(), window, cx, |s| {
12897            s.move_with(|map, selection| {
12898                if !selection.is_empty() {
12899                    selection.goal = SelectionGoal::None;
12900                }
12901                let (cursor, goal) = movement::up_by_rows(
12902                    map,
12903                    selection.start,
12904                    action.lines,
12905                    selection.goal,
12906                    false,
12907                    text_layout_details,
12908                );
12909                selection.collapse_to(cursor, goal);
12910            });
12911        })
12912    }
12913
12914    pub fn move_down_by_lines(
12915        &mut self,
12916        action: &MoveDownByLines,
12917        window: &mut Window,
12918        cx: &mut Context<Self>,
12919    ) {
12920        if self.take_rename(true, window, cx).is_some() {
12921            return;
12922        }
12923
12924        if self.mode.is_single_line() {
12925            cx.propagate();
12926            return;
12927        }
12928
12929        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12930
12931        let text_layout_details = &self.text_layout_details(window);
12932
12933        self.change_selections(Default::default(), window, cx, |s| {
12934            s.move_with(|map, selection| {
12935                if !selection.is_empty() {
12936                    selection.goal = SelectionGoal::None;
12937                }
12938                let (cursor, goal) = movement::down_by_rows(
12939                    map,
12940                    selection.start,
12941                    action.lines,
12942                    selection.goal,
12943                    false,
12944                    text_layout_details,
12945                );
12946                selection.collapse_to(cursor, goal);
12947            });
12948        })
12949    }
12950
12951    pub fn select_down_by_lines(
12952        &mut self,
12953        action: &SelectDownByLines,
12954        window: &mut Window,
12955        cx: &mut Context<Self>,
12956    ) {
12957        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12958        let text_layout_details = &self.text_layout_details(window);
12959        self.change_selections(Default::default(), window, cx, |s| {
12960            s.move_heads_with(|map, head, goal| {
12961                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12962            })
12963        })
12964    }
12965
12966    pub fn select_up_by_lines(
12967        &mut self,
12968        action: &SelectUpByLines,
12969        window: &mut Window,
12970        cx: &mut Context<Self>,
12971    ) {
12972        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12973        let text_layout_details = &self.text_layout_details(window);
12974        self.change_selections(Default::default(), window, cx, |s| {
12975            s.move_heads_with(|map, head, goal| {
12976                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12977            })
12978        })
12979    }
12980
12981    pub fn select_page_up(
12982        &mut self,
12983        _: &SelectPageUp,
12984        window: &mut Window,
12985        cx: &mut Context<Self>,
12986    ) {
12987        let Some(row_count) = self.visible_row_count() else {
12988            return;
12989        };
12990
12991        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12992
12993        let text_layout_details = &self.text_layout_details(window);
12994
12995        self.change_selections(Default::default(), window, cx, |s| {
12996            s.move_heads_with(|map, head, goal| {
12997                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12998            })
12999        })
13000    }
13001
13002    pub fn move_page_up(
13003        &mut self,
13004        action: &MovePageUp,
13005        window: &mut Window,
13006        cx: &mut Context<Self>,
13007    ) {
13008        if self.take_rename(true, window, cx).is_some() {
13009            return;
13010        }
13011
13012        if self
13013            .context_menu
13014            .borrow_mut()
13015            .as_mut()
13016            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13017            .unwrap_or(false)
13018        {
13019            return;
13020        }
13021
13022        if matches!(self.mode, EditorMode::SingleLine) {
13023            cx.propagate();
13024            return;
13025        }
13026
13027        let Some(row_count) = self.visible_row_count() else {
13028            return;
13029        };
13030
13031        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13032
13033        let effects = if action.center_cursor {
13034            SelectionEffects::scroll(Autoscroll::center())
13035        } else {
13036            SelectionEffects::default()
13037        };
13038
13039        let text_layout_details = &self.text_layout_details(window);
13040
13041        self.change_selections(effects, window, cx, |s| {
13042            s.move_with(|map, selection| {
13043                if !selection.is_empty() {
13044                    selection.goal = SelectionGoal::None;
13045                }
13046                let (cursor, goal) = movement::up_by_rows(
13047                    map,
13048                    selection.end,
13049                    row_count,
13050                    selection.goal,
13051                    false,
13052                    text_layout_details,
13053                );
13054                selection.collapse_to(cursor, goal);
13055            });
13056        });
13057    }
13058
13059    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13060        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13061        let text_layout_details = &self.text_layout_details(window);
13062        self.change_selections(Default::default(), window, cx, |s| {
13063            s.move_heads_with(|map, head, goal| {
13064                movement::up(map, head, goal, false, text_layout_details)
13065            })
13066        })
13067    }
13068
13069    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13070        self.take_rename(true, window, cx);
13071
13072        if self.mode.is_single_line() {
13073            cx.propagate();
13074            return;
13075        }
13076
13077        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13078
13079        let text_layout_details = &self.text_layout_details(window);
13080        let selection_count = self.selections.count();
13081        let first_selection = self.selections.first_anchor();
13082
13083        self.change_selections(Default::default(), window, cx, |s| {
13084            s.move_with(|map, selection| {
13085                if !selection.is_empty() {
13086                    selection.goal = SelectionGoal::None;
13087                }
13088                let (cursor, goal) = movement::down(
13089                    map,
13090                    selection.end,
13091                    selection.goal,
13092                    false,
13093                    text_layout_details,
13094                );
13095                selection.collapse_to(cursor, goal);
13096            });
13097        });
13098
13099        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13100        {
13101            cx.propagate();
13102        }
13103    }
13104
13105    pub fn select_page_down(
13106        &mut self,
13107        _: &SelectPageDown,
13108        window: &mut Window,
13109        cx: &mut Context<Self>,
13110    ) {
13111        let Some(row_count) = self.visible_row_count() else {
13112            return;
13113        };
13114
13115        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13116
13117        let text_layout_details = &self.text_layout_details(window);
13118
13119        self.change_selections(Default::default(), window, cx, |s| {
13120            s.move_heads_with(|map, head, goal| {
13121                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13122            })
13123        })
13124    }
13125
13126    pub fn move_page_down(
13127        &mut self,
13128        action: &MovePageDown,
13129        window: &mut Window,
13130        cx: &mut Context<Self>,
13131    ) {
13132        if self.take_rename(true, window, cx).is_some() {
13133            return;
13134        }
13135
13136        if self
13137            .context_menu
13138            .borrow_mut()
13139            .as_mut()
13140            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13141            .unwrap_or(false)
13142        {
13143            return;
13144        }
13145
13146        if matches!(self.mode, EditorMode::SingleLine) {
13147            cx.propagate();
13148            return;
13149        }
13150
13151        let Some(row_count) = self.visible_row_count() else {
13152            return;
13153        };
13154
13155        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13156
13157        let effects = if action.center_cursor {
13158            SelectionEffects::scroll(Autoscroll::center())
13159        } else {
13160            SelectionEffects::default()
13161        };
13162
13163        let text_layout_details = &self.text_layout_details(window);
13164        self.change_selections(effects, window, cx, |s| {
13165            s.move_with(|map, selection| {
13166                if !selection.is_empty() {
13167                    selection.goal = SelectionGoal::None;
13168                }
13169                let (cursor, goal) = movement::down_by_rows(
13170                    map,
13171                    selection.end,
13172                    row_count,
13173                    selection.goal,
13174                    false,
13175                    text_layout_details,
13176                );
13177                selection.collapse_to(cursor, goal);
13178            });
13179        });
13180    }
13181
13182    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13183        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13184        let text_layout_details = &self.text_layout_details(window);
13185        self.change_selections(Default::default(), window, cx, |s| {
13186            s.move_heads_with(|map, head, goal| {
13187                movement::down(map, head, goal, false, text_layout_details)
13188            })
13189        });
13190    }
13191
13192    pub fn context_menu_first(
13193        &mut self,
13194        _: &ContextMenuFirst,
13195        window: &mut Window,
13196        cx: &mut Context<Self>,
13197    ) {
13198        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13199            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13200        }
13201    }
13202
13203    pub fn context_menu_prev(
13204        &mut self,
13205        _: &ContextMenuPrevious,
13206        window: &mut Window,
13207        cx: &mut Context<Self>,
13208    ) {
13209        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13210            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13211        }
13212    }
13213
13214    pub fn context_menu_next(
13215        &mut self,
13216        _: &ContextMenuNext,
13217        window: &mut Window,
13218        cx: &mut Context<Self>,
13219    ) {
13220        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13221            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13222        }
13223    }
13224
13225    pub fn context_menu_last(
13226        &mut self,
13227        _: &ContextMenuLast,
13228        window: &mut Window,
13229        cx: &mut Context<Self>,
13230    ) {
13231        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13232            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13233        }
13234    }
13235
13236    pub fn signature_help_prev(
13237        &mut self,
13238        _: &SignatureHelpPrevious,
13239        _: &mut Window,
13240        cx: &mut Context<Self>,
13241    ) {
13242        if let Some(popover) = self.signature_help_state.popover_mut() {
13243            if popover.current_signature == 0 {
13244                popover.current_signature = popover.signatures.len() - 1;
13245            } else {
13246                popover.current_signature -= 1;
13247            }
13248            cx.notify();
13249        }
13250    }
13251
13252    pub fn signature_help_next(
13253        &mut self,
13254        _: &SignatureHelpNext,
13255        _: &mut Window,
13256        cx: &mut Context<Self>,
13257    ) {
13258        if let Some(popover) = self.signature_help_state.popover_mut() {
13259            if popover.current_signature + 1 == popover.signatures.len() {
13260                popover.current_signature = 0;
13261            } else {
13262                popover.current_signature += 1;
13263            }
13264            cx.notify();
13265        }
13266    }
13267
13268    pub fn move_to_previous_word_start(
13269        &mut self,
13270        _: &MoveToPreviousWordStart,
13271        window: &mut Window,
13272        cx: &mut Context<Self>,
13273    ) {
13274        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13275        self.change_selections(Default::default(), window, cx, |s| {
13276            s.move_cursors_with(|map, head, _| {
13277                (
13278                    movement::previous_word_start(map, head),
13279                    SelectionGoal::None,
13280                )
13281            });
13282        })
13283    }
13284
13285    pub fn move_to_previous_subword_start(
13286        &mut self,
13287        _: &MoveToPreviousSubwordStart,
13288        window: &mut Window,
13289        cx: &mut Context<Self>,
13290    ) {
13291        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13292        self.change_selections(Default::default(), window, cx, |s| {
13293            s.move_cursors_with(|map, head, _| {
13294                (
13295                    movement::previous_subword_start(map, head),
13296                    SelectionGoal::None,
13297                )
13298            });
13299        })
13300    }
13301
13302    pub fn select_to_previous_word_start(
13303        &mut self,
13304        _: &SelectToPreviousWordStart,
13305        window: &mut Window,
13306        cx: &mut Context<Self>,
13307    ) {
13308        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13309        self.change_selections(Default::default(), window, cx, |s| {
13310            s.move_heads_with(|map, head, _| {
13311                (
13312                    movement::previous_word_start(map, head),
13313                    SelectionGoal::None,
13314                )
13315            });
13316        })
13317    }
13318
13319    pub fn select_to_previous_subword_start(
13320        &mut self,
13321        _: &SelectToPreviousSubwordStart,
13322        window: &mut Window,
13323        cx: &mut Context<Self>,
13324    ) {
13325        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13326        self.change_selections(Default::default(), window, cx, |s| {
13327            s.move_heads_with(|map, head, _| {
13328                (
13329                    movement::previous_subword_start(map, head),
13330                    SelectionGoal::None,
13331                )
13332            });
13333        })
13334    }
13335
13336    pub fn delete_to_previous_word_start(
13337        &mut self,
13338        action: &DeleteToPreviousWordStart,
13339        window: &mut Window,
13340        cx: &mut Context<Self>,
13341    ) {
13342        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13343        self.transact(window, cx, |this, window, cx| {
13344            this.select_autoclose_pair(window, cx);
13345            this.change_selections(Default::default(), window, cx, |s| {
13346                s.move_with(|map, selection| {
13347                    if selection.is_empty() {
13348                        let mut cursor = if action.ignore_newlines {
13349                            movement::previous_word_start(map, selection.head())
13350                        } else {
13351                            movement::previous_word_start_or_newline(map, selection.head())
13352                        };
13353                        cursor = movement::adjust_greedy_deletion(
13354                            map,
13355                            selection.head(),
13356                            cursor,
13357                            action.ignore_brackets,
13358                        );
13359                        selection.set_head(cursor, SelectionGoal::None);
13360                    }
13361                });
13362            });
13363            this.insert("", window, cx);
13364        });
13365    }
13366
13367    pub fn delete_to_previous_subword_start(
13368        &mut self,
13369        _: &DeleteToPreviousSubwordStart,
13370        window: &mut Window,
13371        cx: &mut Context<Self>,
13372    ) {
13373        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13374        self.transact(window, cx, |this, window, cx| {
13375            this.select_autoclose_pair(window, cx);
13376            this.change_selections(Default::default(), window, cx, |s| {
13377                s.move_with(|map, selection| {
13378                    if selection.is_empty() {
13379                        let mut cursor = movement::previous_subword_start(map, selection.head());
13380                        cursor =
13381                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13382                        selection.set_head(cursor, SelectionGoal::None);
13383                    }
13384                });
13385            });
13386            this.insert("", window, cx);
13387        });
13388    }
13389
13390    pub fn move_to_next_word_end(
13391        &mut self,
13392        _: &MoveToNextWordEnd,
13393        window: &mut Window,
13394        cx: &mut Context<Self>,
13395    ) {
13396        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13397        self.change_selections(Default::default(), window, cx, |s| {
13398            s.move_cursors_with(|map, head, _| {
13399                (movement::next_word_end(map, head), SelectionGoal::None)
13400            });
13401        })
13402    }
13403
13404    pub fn move_to_next_subword_end(
13405        &mut self,
13406        _: &MoveToNextSubwordEnd,
13407        window: &mut Window,
13408        cx: &mut Context<Self>,
13409    ) {
13410        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13411        self.change_selections(Default::default(), window, cx, |s| {
13412            s.move_cursors_with(|map, head, _| {
13413                (movement::next_subword_end(map, head), SelectionGoal::None)
13414            });
13415        })
13416    }
13417
13418    pub fn select_to_next_word_end(
13419        &mut self,
13420        _: &SelectToNextWordEnd,
13421        window: &mut Window,
13422        cx: &mut Context<Self>,
13423    ) {
13424        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13425        self.change_selections(Default::default(), window, cx, |s| {
13426            s.move_heads_with(|map, head, _| {
13427                (movement::next_word_end(map, head), SelectionGoal::None)
13428            });
13429        })
13430    }
13431
13432    pub fn select_to_next_subword_end(
13433        &mut self,
13434        _: &SelectToNextSubwordEnd,
13435        window: &mut Window,
13436        cx: &mut Context<Self>,
13437    ) {
13438        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13439        self.change_selections(Default::default(), window, cx, |s| {
13440            s.move_heads_with(|map, head, _| {
13441                (movement::next_subword_end(map, head), SelectionGoal::None)
13442            });
13443        })
13444    }
13445
13446    pub fn delete_to_next_word_end(
13447        &mut self,
13448        action: &DeleteToNextWordEnd,
13449        window: &mut Window,
13450        cx: &mut Context<Self>,
13451    ) {
13452        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13453        self.transact(window, cx, |this, window, cx| {
13454            this.change_selections(Default::default(), window, cx, |s| {
13455                s.move_with(|map, selection| {
13456                    if selection.is_empty() {
13457                        let mut cursor = if action.ignore_newlines {
13458                            movement::next_word_end(map, selection.head())
13459                        } else {
13460                            movement::next_word_end_or_newline(map, selection.head())
13461                        };
13462                        cursor = movement::adjust_greedy_deletion(
13463                            map,
13464                            selection.head(),
13465                            cursor,
13466                            action.ignore_brackets,
13467                        );
13468                        selection.set_head(cursor, SelectionGoal::None);
13469                    }
13470                });
13471            });
13472            this.insert("", window, cx);
13473        });
13474    }
13475
13476    pub fn delete_to_next_subword_end(
13477        &mut self,
13478        _: &DeleteToNextSubwordEnd,
13479        window: &mut Window,
13480        cx: &mut Context<Self>,
13481    ) {
13482        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13483        self.transact(window, cx, |this, window, cx| {
13484            this.change_selections(Default::default(), window, cx, |s| {
13485                s.move_with(|map, selection| {
13486                    if selection.is_empty() {
13487                        let mut cursor = movement::next_subword_end(map, selection.head());
13488                        cursor =
13489                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13490                        selection.set_head(cursor, SelectionGoal::None);
13491                    }
13492                });
13493            });
13494            this.insert("", window, cx);
13495        });
13496    }
13497
13498    pub fn move_to_beginning_of_line(
13499        &mut self,
13500        action: &MoveToBeginningOfLine,
13501        window: &mut Window,
13502        cx: &mut Context<Self>,
13503    ) {
13504        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13505        self.change_selections(Default::default(), window, cx, |s| {
13506            s.move_cursors_with(|map, head, _| {
13507                (
13508                    movement::indented_line_beginning(
13509                        map,
13510                        head,
13511                        action.stop_at_soft_wraps,
13512                        action.stop_at_indent,
13513                    ),
13514                    SelectionGoal::None,
13515                )
13516            });
13517        })
13518    }
13519
13520    pub fn select_to_beginning_of_line(
13521        &mut self,
13522        action: &SelectToBeginningOfLine,
13523        window: &mut Window,
13524        cx: &mut Context<Self>,
13525    ) {
13526        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13527        self.change_selections(Default::default(), window, cx, |s| {
13528            s.move_heads_with(|map, head, _| {
13529                (
13530                    movement::indented_line_beginning(
13531                        map,
13532                        head,
13533                        action.stop_at_soft_wraps,
13534                        action.stop_at_indent,
13535                    ),
13536                    SelectionGoal::None,
13537                )
13538            });
13539        });
13540    }
13541
13542    pub fn delete_to_beginning_of_line(
13543        &mut self,
13544        action: &DeleteToBeginningOfLine,
13545        window: &mut Window,
13546        cx: &mut Context<Self>,
13547    ) {
13548        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13549        self.transact(window, cx, |this, window, cx| {
13550            this.change_selections(Default::default(), window, cx, |s| {
13551                s.move_with(|_, selection| {
13552                    selection.reversed = true;
13553                });
13554            });
13555
13556            this.select_to_beginning_of_line(
13557                &SelectToBeginningOfLine {
13558                    stop_at_soft_wraps: false,
13559                    stop_at_indent: action.stop_at_indent,
13560                },
13561                window,
13562                cx,
13563            );
13564            this.backspace(&Backspace, window, cx);
13565        });
13566    }
13567
13568    pub fn move_to_end_of_line(
13569        &mut self,
13570        action: &MoveToEndOfLine,
13571        window: &mut Window,
13572        cx: &mut Context<Self>,
13573    ) {
13574        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13575        self.change_selections(Default::default(), window, cx, |s| {
13576            s.move_cursors_with(|map, head, _| {
13577                (
13578                    movement::line_end(map, head, action.stop_at_soft_wraps),
13579                    SelectionGoal::None,
13580                )
13581            });
13582        })
13583    }
13584
13585    pub fn select_to_end_of_line(
13586        &mut self,
13587        action: &SelectToEndOfLine,
13588        window: &mut Window,
13589        cx: &mut Context<Self>,
13590    ) {
13591        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13592        self.change_selections(Default::default(), window, cx, |s| {
13593            s.move_heads_with(|map, head, _| {
13594                (
13595                    movement::line_end(map, head, action.stop_at_soft_wraps),
13596                    SelectionGoal::None,
13597                )
13598            });
13599        })
13600    }
13601
13602    pub fn delete_to_end_of_line(
13603        &mut self,
13604        _: &DeleteToEndOfLine,
13605        window: &mut Window,
13606        cx: &mut Context<Self>,
13607    ) {
13608        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13609        self.transact(window, cx, |this, window, cx| {
13610            this.select_to_end_of_line(
13611                &SelectToEndOfLine {
13612                    stop_at_soft_wraps: false,
13613                },
13614                window,
13615                cx,
13616            );
13617            this.delete(&Delete, window, cx);
13618        });
13619    }
13620
13621    pub fn cut_to_end_of_line(
13622        &mut self,
13623        action: &CutToEndOfLine,
13624        window: &mut Window,
13625        cx: &mut Context<Self>,
13626    ) {
13627        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13628        self.transact(window, cx, |this, window, cx| {
13629            this.select_to_end_of_line(
13630                &SelectToEndOfLine {
13631                    stop_at_soft_wraps: false,
13632                },
13633                window,
13634                cx,
13635            );
13636            if !action.stop_at_newlines {
13637                this.change_selections(Default::default(), window, cx, |s| {
13638                    s.move_with(|_, sel| {
13639                        if sel.is_empty() {
13640                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13641                        }
13642                    });
13643                });
13644            }
13645            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13646            let item = this.cut_common(false, window, cx);
13647            cx.write_to_clipboard(item);
13648        });
13649    }
13650
13651    pub fn move_to_start_of_paragraph(
13652        &mut self,
13653        _: &MoveToStartOfParagraph,
13654        window: &mut Window,
13655        cx: &mut Context<Self>,
13656    ) {
13657        if matches!(self.mode, EditorMode::SingleLine) {
13658            cx.propagate();
13659            return;
13660        }
13661        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13662        self.change_selections(Default::default(), window, cx, |s| {
13663            s.move_with(|map, selection| {
13664                selection.collapse_to(
13665                    movement::start_of_paragraph(map, selection.head(), 1),
13666                    SelectionGoal::None,
13667                )
13668            });
13669        })
13670    }
13671
13672    pub fn move_to_end_of_paragraph(
13673        &mut self,
13674        _: &MoveToEndOfParagraph,
13675        window: &mut Window,
13676        cx: &mut Context<Self>,
13677    ) {
13678        if matches!(self.mode, EditorMode::SingleLine) {
13679            cx.propagate();
13680            return;
13681        }
13682        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13683        self.change_selections(Default::default(), window, cx, |s| {
13684            s.move_with(|map, selection| {
13685                selection.collapse_to(
13686                    movement::end_of_paragraph(map, selection.head(), 1),
13687                    SelectionGoal::None,
13688                )
13689            });
13690        })
13691    }
13692
13693    pub fn select_to_start_of_paragraph(
13694        &mut self,
13695        _: &SelectToStartOfParagraph,
13696        window: &mut Window,
13697        cx: &mut Context<Self>,
13698    ) {
13699        if matches!(self.mode, EditorMode::SingleLine) {
13700            cx.propagate();
13701            return;
13702        }
13703        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13704        self.change_selections(Default::default(), window, cx, |s| {
13705            s.move_heads_with(|map, head, _| {
13706                (
13707                    movement::start_of_paragraph(map, head, 1),
13708                    SelectionGoal::None,
13709                )
13710            });
13711        })
13712    }
13713
13714    pub fn select_to_end_of_paragraph(
13715        &mut self,
13716        _: &SelectToEndOfParagraph,
13717        window: &mut Window,
13718        cx: &mut Context<Self>,
13719    ) {
13720        if matches!(self.mode, EditorMode::SingleLine) {
13721            cx.propagate();
13722            return;
13723        }
13724        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13725        self.change_selections(Default::default(), window, cx, |s| {
13726            s.move_heads_with(|map, head, _| {
13727                (
13728                    movement::end_of_paragraph(map, head, 1),
13729                    SelectionGoal::None,
13730                )
13731            });
13732        })
13733    }
13734
13735    pub fn move_to_start_of_excerpt(
13736        &mut self,
13737        _: &MoveToStartOfExcerpt,
13738        window: &mut Window,
13739        cx: &mut Context<Self>,
13740    ) {
13741        if matches!(self.mode, EditorMode::SingleLine) {
13742            cx.propagate();
13743            return;
13744        }
13745        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13746        self.change_selections(Default::default(), window, cx, |s| {
13747            s.move_with(|map, selection| {
13748                selection.collapse_to(
13749                    movement::start_of_excerpt(
13750                        map,
13751                        selection.head(),
13752                        workspace::searchable::Direction::Prev,
13753                    ),
13754                    SelectionGoal::None,
13755                )
13756            });
13757        })
13758    }
13759
13760    pub fn move_to_start_of_next_excerpt(
13761        &mut self,
13762        _: &MoveToStartOfNextExcerpt,
13763        window: &mut Window,
13764        cx: &mut Context<Self>,
13765    ) {
13766        if matches!(self.mode, EditorMode::SingleLine) {
13767            cx.propagate();
13768            return;
13769        }
13770
13771        self.change_selections(Default::default(), window, cx, |s| {
13772            s.move_with(|map, selection| {
13773                selection.collapse_to(
13774                    movement::start_of_excerpt(
13775                        map,
13776                        selection.head(),
13777                        workspace::searchable::Direction::Next,
13778                    ),
13779                    SelectionGoal::None,
13780                )
13781            });
13782        })
13783    }
13784
13785    pub fn move_to_end_of_excerpt(
13786        &mut self,
13787        _: &MoveToEndOfExcerpt,
13788        window: &mut Window,
13789        cx: &mut Context<Self>,
13790    ) {
13791        if matches!(self.mode, EditorMode::SingleLine) {
13792            cx.propagate();
13793            return;
13794        }
13795        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13796        self.change_selections(Default::default(), window, cx, |s| {
13797            s.move_with(|map, selection| {
13798                selection.collapse_to(
13799                    movement::end_of_excerpt(
13800                        map,
13801                        selection.head(),
13802                        workspace::searchable::Direction::Next,
13803                    ),
13804                    SelectionGoal::None,
13805                )
13806            });
13807        })
13808    }
13809
13810    pub fn move_to_end_of_previous_excerpt(
13811        &mut self,
13812        _: &MoveToEndOfPreviousExcerpt,
13813        window: &mut Window,
13814        cx: &mut Context<Self>,
13815    ) {
13816        if matches!(self.mode, EditorMode::SingleLine) {
13817            cx.propagate();
13818            return;
13819        }
13820        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13821        self.change_selections(Default::default(), window, cx, |s| {
13822            s.move_with(|map, selection| {
13823                selection.collapse_to(
13824                    movement::end_of_excerpt(
13825                        map,
13826                        selection.head(),
13827                        workspace::searchable::Direction::Prev,
13828                    ),
13829                    SelectionGoal::None,
13830                )
13831            });
13832        })
13833    }
13834
13835    pub fn select_to_start_of_excerpt(
13836        &mut self,
13837        _: &SelectToStartOfExcerpt,
13838        window: &mut Window,
13839        cx: &mut Context<Self>,
13840    ) {
13841        if matches!(self.mode, EditorMode::SingleLine) {
13842            cx.propagate();
13843            return;
13844        }
13845        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13846        self.change_selections(Default::default(), window, cx, |s| {
13847            s.move_heads_with(|map, head, _| {
13848                (
13849                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13850                    SelectionGoal::None,
13851                )
13852            });
13853        })
13854    }
13855
13856    pub fn select_to_start_of_next_excerpt(
13857        &mut self,
13858        _: &SelectToStartOfNextExcerpt,
13859        window: &mut Window,
13860        cx: &mut Context<Self>,
13861    ) {
13862        if matches!(self.mode, EditorMode::SingleLine) {
13863            cx.propagate();
13864            return;
13865        }
13866        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13867        self.change_selections(Default::default(), window, cx, |s| {
13868            s.move_heads_with(|map, head, _| {
13869                (
13870                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13871                    SelectionGoal::None,
13872                )
13873            });
13874        })
13875    }
13876
13877    pub fn select_to_end_of_excerpt(
13878        &mut self,
13879        _: &SelectToEndOfExcerpt,
13880        window: &mut Window,
13881        cx: &mut Context<Self>,
13882    ) {
13883        if matches!(self.mode, EditorMode::SingleLine) {
13884            cx.propagate();
13885            return;
13886        }
13887        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13888        self.change_selections(Default::default(), window, cx, |s| {
13889            s.move_heads_with(|map, head, _| {
13890                (
13891                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13892                    SelectionGoal::None,
13893                )
13894            });
13895        })
13896    }
13897
13898    pub fn select_to_end_of_previous_excerpt(
13899        &mut self,
13900        _: &SelectToEndOfPreviousExcerpt,
13901        window: &mut Window,
13902        cx: &mut Context<Self>,
13903    ) {
13904        if matches!(self.mode, EditorMode::SingleLine) {
13905            cx.propagate();
13906            return;
13907        }
13908        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13909        self.change_selections(Default::default(), window, cx, |s| {
13910            s.move_heads_with(|map, head, _| {
13911                (
13912                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13913                    SelectionGoal::None,
13914                )
13915            });
13916        })
13917    }
13918
13919    pub fn move_to_beginning(
13920        &mut self,
13921        _: &MoveToBeginning,
13922        window: &mut Window,
13923        cx: &mut Context<Self>,
13924    ) {
13925        if matches!(self.mode, EditorMode::SingleLine) {
13926            cx.propagate();
13927            return;
13928        }
13929        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13930        self.change_selections(Default::default(), window, cx, |s| {
13931            s.select_ranges(vec![0..0]);
13932        });
13933    }
13934
13935    pub fn select_to_beginning(
13936        &mut self,
13937        _: &SelectToBeginning,
13938        window: &mut Window,
13939        cx: &mut Context<Self>,
13940    ) {
13941        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
13942        selection.set_head(Point::zero(), SelectionGoal::None);
13943        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13944        self.change_selections(Default::default(), window, cx, |s| {
13945            s.select(vec![selection]);
13946        });
13947    }
13948
13949    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13950        if matches!(self.mode, EditorMode::SingleLine) {
13951            cx.propagate();
13952            return;
13953        }
13954        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13955        let cursor = self.buffer.read(cx).read(cx).len();
13956        self.change_selections(Default::default(), window, cx, |s| {
13957            s.select_ranges(vec![cursor..cursor])
13958        });
13959    }
13960
13961    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13962        self.nav_history = nav_history;
13963    }
13964
13965    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13966        self.nav_history.as_ref()
13967    }
13968
13969    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13970        self.push_to_nav_history(
13971            self.selections.newest_anchor().head(),
13972            None,
13973            false,
13974            true,
13975            cx,
13976        );
13977    }
13978
13979    fn push_to_nav_history(
13980        &mut self,
13981        cursor_anchor: Anchor,
13982        new_position: Option<Point>,
13983        is_deactivate: bool,
13984        always: bool,
13985        cx: &mut Context<Self>,
13986    ) {
13987        if let Some(nav_history) = self.nav_history.as_mut() {
13988            let buffer = self.buffer.read(cx).read(cx);
13989            let cursor_position = cursor_anchor.to_point(&buffer);
13990            let scroll_state = self.scroll_manager.anchor();
13991            let scroll_top_row = scroll_state.top_row(&buffer);
13992            drop(buffer);
13993
13994            if let Some(new_position) = new_position {
13995                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13996                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13997                    return;
13998                }
13999            }
14000
14001            nav_history.push(
14002                Some(NavigationData {
14003                    cursor_anchor,
14004                    cursor_position,
14005                    scroll_anchor: scroll_state,
14006                    scroll_top_row,
14007                }),
14008                cx,
14009            );
14010            cx.emit(EditorEvent::PushedToNavHistory {
14011                anchor: cursor_anchor,
14012                is_deactivate,
14013            })
14014        }
14015    }
14016
14017    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14018        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14019        let buffer = self.buffer.read(cx).snapshot(cx);
14020        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14021        selection.set_head(buffer.len(), SelectionGoal::None);
14022        self.change_selections(Default::default(), window, cx, |s| {
14023            s.select(vec![selection]);
14024        });
14025    }
14026
14027    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14028        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14029        let end = self.buffer.read(cx).read(cx).len();
14030        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14031            s.select_ranges(vec![0..end]);
14032        });
14033    }
14034
14035    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14036        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14037        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14038        let mut selections = self.selections.all::<Point>(&display_map);
14039        let max_point = display_map.buffer_snapshot().max_point();
14040        for selection in &mut selections {
14041            let rows = selection.spanned_rows(true, &display_map);
14042            selection.start = Point::new(rows.start.0, 0);
14043            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14044            selection.reversed = false;
14045        }
14046        self.change_selections(Default::default(), window, cx, |s| {
14047            s.select(selections);
14048        });
14049    }
14050
14051    pub fn split_selection_into_lines(
14052        &mut self,
14053        action: &SplitSelectionIntoLines,
14054        window: &mut Window,
14055        cx: &mut Context<Self>,
14056    ) {
14057        let selections = self
14058            .selections
14059            .all::<Point>(&self.display_snapshot(cx))
14060            .into_iter()
14061            .map(|selection| selection.start..selection.end)
14062            .collect::<Vec<_>>();
14063        self.unfold_ranges(&selections, true, true, cx);
14064
14065        let mut new_selection_ranges = Vec::new();
14066        {
14067            let buffer = self.buffer.read(cx).read(cx);
14068            for selection in selections {
14069                for row in selection.start.row..selection.end.row {
14070                    let line_start = Point::new(row, 0);
14071                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14072
14073                    if action.keep_selections {
14074                        // Keep the selection range for each line
14075                        let selection_start = if row == selection.start.row {
14076                            selection.start
14077                        } else {
14078                            line_start
14079                        };
14080                        new_selection_ranges.push(selection_start..line_end);
14081                    } else {
14082                        // Collapse to cursor at end of line
14083                        new_selection_ranges.push(line_end..line_end);
14084                    }
14085                }
14086
14087                let is_multiline_selection = selection.start.row != selection.end.row;
14088                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14089                // so this action feels more ergonomic when paired with other selection operations
14090                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14091                if !should_skip_last {
14092                    if action.keep_selections {
14093                        if is_multiline_selection {
14094                            let line_start = Point::new(selection.end.row, 0);
14095                            new_selection_ranges.push(line_start..selection.end);
14096                        } else {
14097                            new_selection_ranges.push(selection.start..selection.end);
14098                        }
14099                    } else {
14100                        new_selection_ranges.push(selection.end..selection.end);
14101                    }
14102                }
14103            }
14104        }
14105        self.change_selections(Default::default(), window, cx, |s| {
14106            s.select_ranges(new_selection_ranges);
14107        });
14108    }
14109
14110    pub fn add_selection_above(
14111        &mut self,
14112        action: &AddSelectionAbove,
14113        window: &mut Window,
14114        cx: &mut Context<Self>,
14115    ) {
14116        self.add_selection(true, action.skip_soft_wrap, window, cx);
14117    }
14118
14119    pub fn add_selection_below(
14120        &mut self,
14121        action: &AddSelectionBelow,
14122        window: &mut Window,
14123        cx: &mut Context<Self>,
14124    ) {
14125        self.add_selection(false, action.skip_soft_wrap, window, cx);
14126    }
14127
14128    fn add_selection(
14129        &mut self,
14130        above: bool,
14131        skip_soft_wrap: bool,
14132        window: &mut Window,
14133        cx: &mut Context<Self>,
14134    ) {
14135        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14136
14137        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14138        let all_selections = self.selections.all::<Point>(&display_map);
14139        let text_layout_details = self.text_layout_details(window);
14140
14141        let (mut columnar_selections, new_selections_to_columnarize) = {
14142            if let Some(state) = self.add_selections_state.as_ref() {
14143                let columnar_selection_ids: HashSet<_> = state
14144                    .groups
14145                    .iter()
14146                    .flat_map(|group| group.stack.iter())
14147                    .copied()
14148                    .collect();
14149
14150                all_selections
14151                    .into_iter()
14152                    .partition(|s| columnar_selection_ids.contains(&s.id))
14153            } else {
14154                (Vec::new(), all_selections)
14155            }
14156        };
14157
14158        let mut state = self
14159            .add_selections_state
14160            .take()
14161            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14162
14163        for selection in new_selections_to_columnarize {
14164            let range = selection.display_range(&display_map).sorted();
14165            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14166            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14167            let positions = start_x.min(end_x)..start_x.max(end_x);
14168            let mut stack = Vec::new();
14169            for row in range.start.row().0..=range.end.row().0 {
14170                if let Some(selection) = self.selections.build_columnar_selection(
14171                    &display_map,
14172                    DisplayRow(row),
14173                    &positions,
14174                    selection.reversed,
14175                    &text_layout_details,
14176                ) {
14177                    stack.push(selection.id);
14178                    columnar_selections.push(selection);
14179                }
14180            }
14181            if !stack.is_empty() {
14182                if above {
14183                    stack.reverse();
14184                }
14185                state.groups.push(AddSelectionsGroup { above, stack });
14186            }
14187        }
14188
14189        let mut final_selections = Vec::new();
14190        let end_row = if above {
14191            DisplayRow(0)
14192        } else {
14193            display_map.max_point().row()
14194        };
14195
14196        let mut last_added_item_per_group = HashMap::default();
14197        for group in state.groups.iter_mut() {
14198            if let Some(last_id) = group.stack.last() {
14199                last_added_item_per_group.insert(*last_id, group);
14200            }
14201        }
14202
14203        for selection in columnar_selections {
14204            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14205                if above == group.above {
14206                    let range = selection.display_range(&display_map).sorted();
14207                    debug_assert_eq!(range.start.row(), range.end.row());
14208                    let mut row = range.start.row();
14209                    let positions =
14210                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14211                            Pixels::from(start)..Pixels::from(end)
14212                        } else {
14213                            let start_x =
14214                                display_map.x_for_display_point(range.start, &text_layout_details);
14215                            let end_x =
14216                                display_map.x_for_display_point(range.end, &text_layout_details);
14217                            start_x.min(end_x)..start_x.max(end_x)
14218                        };
14219
14220                    let mut maybe_new_selection = None;
14221                    let direction = if above { -1 } else { 1 };
14222
14223                    while row != end_row {
14224                        if skip_soft_wrap {
14225                            row = display_map
14226                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14227                                .row();
14228                        } else if above {
14229                            row.0 -= 1;
14230                        } else {
14231                            row.0 += 1;
14232                        }
14233
14234                        if let Some(new_selection) = self.selections.build_columnar_selection(
14235                            &display_map,
14236                            row,
14237                            &positions,
14238                            selection.reversed,
14239                            &text_layout_details,
14240                        ) {
14241                            maybe_new_selection = Some(new_selection);
14242                            break;
14243                        }
14244                    }
14245
14246                    if let Some(new_selection) = maybe_new_selection {
14247                        group.stack.push(new_selection.id);
14248                        if above {
14249                            final_selections.push(new_selection);
14250                            final_selections.push(selection);
14251                        } else {
14252                            final_selections.push(selection);
14253                            final_selections.push(new_selection);
14254                        }
14255                    } else {
14256                        final_selections.push(selection);
14257                    }
14258                } else {
14259                    group.stack.pop();
14260                }
14261            } else {
14262                final_selections.push(selection);
14263            }
14264        }
14265
14266        self.change_selections(Default::default(), window, cx, |s| {
14267            s.select(final_selections);
14268        });
14269
14270        let final_selection_ids: HashSet<_> = self
14271            .selections
14272            .all::<Point>(&display_map)
14273            .iter()
14274            .map(|s| s.id)
14275            .collect();
14276        state.groups.retain_mut(|group| {
14277            // selections might get merged above so we remove invalid items from stacks
14278            group.stack.retain(|id| final_selection_ids.contains(id));
14279
14280            // single selection in stack can be treated as initial state
14281            group.stack.len() > 1
14282        });
14283
14284        if !state.groups.is_empty() {
14285            self.add_selections_state = Some(state);
14286        }
14287    }
14288
14289    fn select_match_ranges(
14290        &mut self,
14291        range: Range<usize>,
14292        reversed: bool,
14293        replace_newest: bool,
14294        auto_scroll: Option<Autoscroll>,
14295        window: &mut Window,
14296        cx: &mut Context<Editor>,
14297    ) {
14298        self.unfold_ranges(
14299            std::slice::from_ref(&range),
14300            false,
14301            auto_scroll.is_some(),
14302            cx,
14303        );
14304        let effects = if let Some(scroll) = auto_scroll {
14305            SelectionEffects::scroll(scroll)
14306        } else {
14307            SelectionEffects::no_scroll()
14308        };
14309        self.change_selections(effects, window, cx, |s| {
14310            if replace_newest {
14311                s.delete(s.newest_anchor().id);
14312            }
14313            if reversed {
14314                s.insert_range(range.end..range.start);
14315            } else {
14316                s.insert_range(range);
14317            }
14318        });
14319    }
14320
14321    pub fn select_next_match_internal(
14322        &mut self,
14323        display_map: &DisplaySnapshot,
14324        replace_newest: bool,
14325        autoscroll: Option<Autoscroll>,
14326        window: &mut Window,
14327        cx: &mut Context<Self>,
14328    ) -> Result<()> {
14329        let buffer = display_map.buffer_snapshot();
14330        let mut selections = self.selections.all::<usize>(&display_map);
14331        if let Some(mut select_next_state) = self.select_next_state.take() {
14332            let query = &select_next_state.query;
14333            if !select_next_state.done {
14334                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14335                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14336                let mut next_selected_range = None;
14337
14338                let bytes_after_last_selection =
14339                    buffer.bytes_in_range(last_selection.end..buffer.len());
14340                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14341                let query_matches = query
14342                    .stream_find_iter(bytes_after_last_selection)
14343                    .map(|result| (last_selection.end, result))
14344                    .chain(
14345                        query
14346                            .stream_find_iter(bytes_before_first_selection)
14347                            .map(|result| (0, result)),
14348                    );
14349
14350                for (start_offset, query_match) in query_matches {
14351                    let query_match = query_match.unwrap(); // can only fail due to I/O
14352                    let offset_range =
14353                        start_offset + query_match.start()..start_offset + query_match.end();
14354
14355                    if !select_next_state.wordwise
14356                        || (!buffer.is_inside_word(offset_range.start, None)
14357                            && !buffer.is_inside_word(offset_range.end, None))
14358                    {
14359                        let idx = selections
14360                            .partition_point(|selection| selection.end <= offset_range.start);
14361                        let overlaps = selections
14362                            .get(idx)
14363                            .map_or(false, |selection| selection.start < offset_range.end);
14364
14365                        if !overlaps {
14366                            next_selected_range = Some(offset_range);
14367                            break;
14368                        }
14369                    }
14370                }
14371
14372                if let Some(next_selected_range) = next_selected_range {
14373                    self.select_match_ranges(
14374                        next_selected_range,
14375                        last_selection.reversed,
14376                        replace_newest,
14377                        autoscroll,
14378                        window,
14379                        cx,
14380                    );
14381                } else {
14382                    select_next_state.done = true;
14383                }
14384            }
14385
14386            self.select_next_state = Some(select_next_state);
14387        } else {
14388            let mut only_carets = true;
14389            let mut same_text_selected = true;
14390            let mut selected_text = None;
14391
14392            let mut selections_iter = selections.iter().peekable();
14393            while let Some(selection) = selections_iter.next() {
14394                if selection.start != selection.end {
14395                    only_carets = false;
14396                }
14397
14398                if same_text_selected {
14399                    if selected_text.is_none() {
14400                        selected_text =
14401                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14402                    }
14403
14404                    if let Some(next_selection) = selections_iter.peek() {
14405                        if next_selection.range().len() == selection.range().len() {
14406                            let next_selected_text = buffer
14407                                .text_for_range(next_selection.range())
14408                                .collect::<String>();
14409                            if Some(next_selected_text) != selected_text {
14410                                same_text_selected = false;
14411                                selected_text = None;
14412                            }
14413                        } else {
14414                            same_text_selected = false;
14415                            selected_text = None;
14416                        }
14417                    }
14418                }
14419            }
14420
14421            if only_carets {
14422                for selection in &mut selections {
14423                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14424                    selection.start = word_range.start;
14425                    selection.end = word_range.end;
14426                    selection.goal = SelectionGoal::None;
14427                    selection.reversed = false;
14428                    self.select_match_ranges(
14429                        selection.start..selection.end,
14430                        selection.reversed,
14431                        replace_newest,
14432                        autoscroll,
14433                        window,
14434                        cx,
14435                    );
14436                }
14437
14438                if selections.len() == 1 {
14439                    let selection = selections
14440                        .last()
14441                        .expect("ensured that there's only one selection");
14442                    let query = buffer
14443                        .text_for_range(selection.start..selection.end)
14444                        .collect::<String>();
14445                    let is_empty = query.is_empty();
14446                    let select_state = SelectNextState {
14447                        query: AhoCorasick::new(&[query])?,
14448                        wordwise: true,
14449                        done: is_empty,
14450                    };
14451                    self.select_next_state = Some(select_state);
14452                } else {
14453                    self.select_next_state = None;
14454                }
14455            } else if let Some(selected_text) = selected_text {
14456                self.select_next_state = Some(SelectNextState {
14457                    query: AhoCorasick::new(&[selected_text])?,
14458                    wordwise: false,
14459                    done: false,
14460                });
14461                self.select_next_match_internal(
14462                    display_map,
14463                    replace_newest,
14464                    autoscroll,
14465                    window,
14466                    cx,
14467                )?;
14468            }
14469        }
14470        Ok(())
14471    }
14472
14473    pub fn select_all_matches(
14474        &mut self,
14475        _action: &SelectAllMatches,
14476        window: &mut Window,
14477        cx: &mut Context<Self>,
14478    ) -> Result<()> {
14479        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14480
14481        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14482
14483        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14484        let Some(select_next_state) = self.select_next_state.as_mut() else {
14485            return Ok(());
14486        };
14487        if select_next_state.done {
14488            return Ok(());
14489        }
14490
14491        let mut new_selections = Vec::new();
14492
14493        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14494        let buffer = display_map.buffer_snapshot();
14495        let query_matches = select_next_state
14496            .query
14497            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14498
14499        for query_match in query_matches.into_iter() {
14500            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14501            let offset_range = if reversed {
14502                query_match.end()..query_match.start()
14503            } else {
14504                query_match.start()..query_match.end()
14505            };
14506
14507            if !select_next_state.wordwise
14508                || (!buffer.is_inside_word(offset_range.start, None)
14509                    && !buffer.is_inside_word(offset_range.end, None))
14510            {
14511                new_selections.push(offset_range.start..offset_range.end);
14512            }
14513        }
14514
14515        select_next_state.done = true;
14516
14517        if new_selections.is_empty() {
14518            log::error!("bug: new_selections is empty in select_all_matches");
14519            return Ok(());
14520        }
14521
14522        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14523        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14524            selections.select_ranges(new_selections)
14525        });
14526
14527        Ok(())
14528    }
14529
14530    pub fn select_next(
14531        &mut self,
14532        action: &SelectNext,
14533        window: &mut Window,
14534        cx: &mut Context<Self>,
14535    ) -> Result<()> {
14536        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14537        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14538        self.select_next_match_internal(
14539            &display_map,
14540            action.replace_newest,
14541            Some(Autoscroll::newest()),
14542            window,
14543            cx,
14544        )?;
14545        Ok(())
14546    }
14547
14548    pub fn select_previous(
14549        &mut self,
14550        action: &SelectPrevious,
14551        window: &mut Window,
14552        cx: &mut Context<Self>,
14553    ) -> Result<()> {
14554        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14555        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14556        let buffer = display_map.buffer_snapshot();
14557        let mut selections = self.selections.all::<usize>(&display_map);
14558        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14559            let query = &select_prev_state.query;
14560            if !select_prev_state.done {
14561                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14562                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14563                let mut next_selected_range = None;
14564                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14565                let bytes_before_last_selection =
14566                    buffer.reversed_bytes_in_range(0..last_selection.start);
14567                let bytes_after_first_selection =
14568                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14569                let query_matches = query
14570                    .stream_find_iter(bytes_before_last_selection)
14571                    .map(|result| (last_selection.start, result))
14572                    .chain(
14573                        query
14574                            .stream_find_iter(bytes_after_first_selection)
14575                            .map(|result| (buffer.len(), result)),
14576                    );
14577                for (end_offset, query_match) in query_matches {
14578                    let query_match = query_match.unwrap(); // can only fail due to I/O
14579                    let offset_range =
14580                        end_offset - query_match.end()..end_offset - query_match.start();
14581
14582                    if !select_prev_state.wordwise
14583                        || (!buffer.is_inside_word(offset_range.start, None)
14584                            && !buffer.is_inside_word(offset_range.end, None))
14585                    {
14586                        next_selected_range = Some(offset_range);
14587                        break;
14588                    }
14589                }
14590
14591                if let Some(next_selected_range) = next_selected_range {
14592                    self.select_match_ranges(
14593                        next_selected_range,
14594                        last_selection.reversed,
14595                        action.replace_newest,
14596                        Some(Autoscroll::newest()),
14597                        window,
14598                        cx,
14599                    );
14600                } else {
14601                    select_prev_state.done = true;
14602                }
14603            }
14604
14605            self.select_prev_state = Some(select_prev_state);
14606        } else {
14607            let mut only_carets = true;
14608            let mut same_text_selected = true;
14609            let mut selected_text = None;
14610
14611            let mut selections_iter = selections.iter().peekable();
14612            while let Some(selection) = selections_iter.next() {
14613                if selection.start != selection.end {
14614                    only_carets = false;
14615                }
14616
14617                if same_text_selected {
14618                    if selected_text.is_none() {
14619                        selected_text =
14620                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14621                    }
14622
14623                    if let Some(next_selection) = selections_iter.peek() {
14624                        if next_selection.range().len() == selection.range().len() {
14625                            let next_selected_text = buffer
14626                                .text_for_range(next_selection.range())
14627                                .collect::<String>();
14628                            if Some(next_selected_text) != selected_text {
14629                                same_text_selected = false;
14630                                selected_text = None;
14631                            }
14632                        } else {
14633                            same_text_selected = false;
14634                            selected_text = None;
14635                        }
14636                    }
14637                }
14638            }
14639
14640            if only_carets {
14641                for selection in &mut selections {
14642                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14643                    selection.start = word_range.start;
14644                    selection.end = word_range.end;
14645                    selection.goal = SelectionGoal::None;
14646                    selection.reversed = false;
14647                    self.select_match_ranges(
14648                        selection.start..selection.end,
14649                        selection.reversed,
14650                        action.replace_newest,
14651                        Some(Autoscroll::newest()),
14652                        window,
14653                        cx,
14654                    );
14655                }
14656                if selections.len() == 1 {
14657                    let selection = selections
14658                        .last()
14659                        .expect("ensured that there's only one selection");
14660                    let query = buffer
14661                        .text_for_range(selection.start..selection.end)
14662                        .collect::<String>();
14663                    let is_empty = query.is_empty();
14664                    let select_state = SelectNextState {
14665                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14666                        wordwise: true,
14667                        done: is_empty,
14668                    };
14669                    self.select_prev_state = Some(select_state);
14670                } else {
14671                    self.select_prev_state = None;
14672                }
14673            } else if let Some(selected_text) = selected_text {
14674                self.select_prev_state = Some(SelectNextState {
14675                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14676                    wordwise: false,
14677                    done: false,
14678                });
14679                self.select_previous(action, window, cx)?;
14680            }
14681        }
14682        Ok(())
14683    }
14684
14685    pub fn find_next_match(
14686        &mut self,
14687        _: &FindNextMatch,
14688        window: &mut Window,
14689        cx: &mut Context<Self>,
14690    ) -> Result<()> {
14691        let selections = self.selections.disjoint_anchors_arc();
14692        match selections.first() {
14693            Some(first) if selections.len() >= 2 => {
14694                self.change_selections(Default::default(), window, cx, |s| {
14695                    s.select_ranges([first.range()]);
14696                });
14697            }
14698            _ => self.select_next(
14699                &SelectNext {
14700                    replace_newest: true,
14701                },
14702                window,
14703                cx,
14704            )?,
14705        }
14706        Ok(())
14707    }
14708
14709    pub fn find_previous_match(
14710        &mut self,
14711        _: &FindPreviousMatch,
14712        window: &mut Window,
14713        cx: &mut Context<Self>,
14714    ) -> Result<()> {
14715        let selections = self.selections.disjoint_anchors_arc();
14716        match selections.last() {
14717            Some(last) if selections.len() >= 2 => {
14718                self.change_selections(Default::default(), window, cx, |s| {
14719                    s.select_ranges([last.range()]);
14720                });
14721            }
14722            _ => self.select_previous(
14723                &SelectPrevious {
14724                    replace_newest: true,
14725                },
14726                window,
14727                cx,
14728            )?,
14729        }
14730        Ok(())
14731    }
14732
14733    pub fn toggle_comments(
14734        &mut self,
14735        action: &ToggleComments,
14736        window: &mut Window,
14737        cx: &mut Context<Self>,
14738    ) {
14739        if self.read_only(cx) {
14740            return;
14741        }
14742        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14743        let text_layout_details = &self.text_layout_details(window);
14744        self.transact(window, cx, |this, window, cx| {
14745            let mut selections = this
14746                .selections
14747                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14748            let mut edits = Vec::new();
14749            let mut selection_edit_ranges = Vec::new();
14750            let mut last_toggled_row = None;
14751            let snapshot = this.buffer.read(cx).read(cx);
14752            let empty_str: Arc<str> = Arc::default();
14753            let mut suffixes_inserted = Vec::new();
14754            let ignore_indent = action.ignore_indent;
14755
14756            fn comment_prefix_range(
14757                snapshot: &MultiBufferSnapshot,
14758                row: MultiBufferRow,
14759                comment_prefix: &str,
14760                comment_prefix_whitespace: &str,
14761                ignore_indent: bool,
14762            ) -> Range<Point> {
14763                let indent_size = if ignore_indent {
14764                    0
14765                } else {
14766                    snapshot.indent_size_for_line(row).len
14767                };
14768
14769                let start = Point::new(row.0, indent_size);
14770
14771                let mut line_bytes = snapshot
14772                    .bytes_in_range(start..snapshot.max_point())
14773                    .flatten()
14774                    .copied();
14775
14776                // If this line currently begins with the line comment prefix, then record
14777                // the range containing the prefix.
14778                if line_bytes
14779                    .by_ref()
14780                    .take(comment_prefix.len())
14781                    .eq(comment_prefix.bytes())
14782                {
14783                    // Include any whitespace that matches the comment prefix.
14784                    let matching_whitespace_len = line_bytes
14785                        .zip(comment_prefix_whitespace.bytes())
14786                        .take_while(|(a, b)| a == b)
14787                        .count() as u32;
14788                    let end = Point::new(
14789                        start.row,
14790                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14791                    );
14792                    start..end
14793                } else {
14794                    start..start
14795                }
14796            }
14797
14798            fn comment_suffix_range(
14799                snapshot: &MultiBufferSnapshot,
14800                row: MultiBufferRow,
14801                comment_suffix: &str,
14802                comment_suffix_has_leading_space: bool,
14803            ) -> Range<Point> {
14804                let end = Point::new(row.0, snapshot.line_len(row));
14805                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14806
14807                let mut line_end_bytes = snapshot
14808                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14809                    .flatten()
14810                    .copied();
14811
14812                let leading_space_len = if suffix_start_column > 0
14813                    && line_end_bytes.next() == Some(b' ')
14814                    && comment_suffix_has_leading_space
14815                {
14816                    1
14817                } else {
14818                    0
14819                };
14820
14821                // If this line currently begins with the line comment prefix, then record
14822                // the range containing the prefix.
14823                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14824                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14825                    start..end
14826                } else {
14827                    end..end
14828                }
14829            }
14830
14831            // TODO: Handle selections that cross excerpts
14832            for selection in &mut selections {
14833                let start_column = snapshot
14834                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14835                    .len;
14836                let language = if let Some(language) =
14837                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14838                {
14839                    language
14840                } else {
14841                    continue;
14842                };
14843
14844                selection_edit_ranges.clear();
14845
14846                // If multiple selections contain a given row, avoid processing that
14847                // row more than once.
14848                let mut start_row = MultiBufferRow(selection.start.row);
14849                if last_toggled_row == Some(start_row) {
14850                    start_row = start_row.next_row();
14851                }
14852                let end_row =
14853                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14854                        MultiBufferRow(selection.end.row - 1)
14855                    } else {
14856                        MultiBufferRow(selection.end.row)
14857                    };
14858                last_toggled_row = Some(end_row);
14859
14860                if start_row > end_row {
14861                    continue;
14862                }
14863
14864                // If the language has line comments, toggle those.
14865                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14866
14867                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14868                if ignore_indent {
14869                    full_comment_prefixes = full_comment_prefixes
14870                        .into_iter()
14871                        .map(|s| Arc::from(s.trim_end()))
14872                        .collect();
14873                }
14874
14875                if !full_comment_prefixes.is_empty() {
14876                    let first_prefix = full_comment_prefixes
14877                        .first()
14878                        .expect("prefixes is non-empty");
14879                    let prefix_trimmed_lengths = full_comment_prefixes
14880                        .iter()
14881                        .map(|p| p.trim_end_matches(' ').len())
14882                        .collect::<SmallVec<[usize; 4]>>();
14883
14884                    let mut all_selection_lines_are_comments = true;
14885
14886                    for row in start_row.0..=end_row.0 {
14887                        let row = MultiBufferRow(row);
14888                        if start_row < end_row && snapshot.is_line_blank(row) {
14889                            continue;
14890                        }
14891
14892                        let prefix_range = full_comment_prefixes
14893                            .iter()
14894                            .zip(prefix_trimmed_lengths.iter().copied())
14895                            .map(|(prefix, trimmed_prefix_len)| {
14896                                comment_prefix_range(
14897                                    snapshot.deref(),
14898                                    row,
14899                                    &prefix[..trimmed_prefix_len],
14900                                    &prefix[trimmed_prefix_len..],
14901                                    ignore_indent,
14902                                )
14903                            })
14904                            .max_by_key(|range| range.end.column - range.start.column)
14905                            .expect("prefixes is non-empty");
14906
14907                        if prefix_range.is_empty() {
14908                            all_selection_lines_are_comments = false;
14909                        }
14910
14911                        selection_edit_ranges.push(prefix_range);
14912                    }
14913
14914                    if all_selection_lines_are_comments {
14915                        edits.extend(
14916                            selection_edit_ranges
14917                                .iter()
14918                                .cloned()
14919                                .map(|range| (range, empty_str.clone())),
14920                        );
14921                    } else {
14922                        let min_column = selection_edit_ranges
14923                            .iter()
14924                            .map(|range| range.start.column)
14925                            .min()
14926                            .unwrap_or(0);
14927                        edits.extend(selection_edit_ranges.iter().map(|range| {
14928                            let position = Point::new(range.start.row, min_column);
14929                            (position..position, first_prefix.clone())
14930                        }));
14931                    }
14932                } else if let Some(BlockCommentConfig {
14933                    start: full_comment_prefix,
14934                    end: comment_suffix,
14935                    ..
14936                }) = language.block_comment()
14937                {
14938                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14939                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14940                    let prefix_range = comment_prefix_range(
14941                        snapshot.deref(),
14942                        start_row,
14943                        comment_prefix,
14944                        comment_prefix_whitespace,
14945                        ignore_indent,
14946                    );
14947                    let suffix_range = comment_suffix_range(
14948                        snapshot.deref(),
14949                        end_row,
14950                        comment_suffix.trim_start_matches(' '),
14951                        comment_suffix.starts_with(' '),
14952                    );
14953
14954                    if prefix_range.is_empty() || suffix_range.is_empty() {
14955                        edits.push((
14956                            prefix_range.start..prefix_range.start,
14957                            full_comment_prefix.clone(),
14958                        ));
14959                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14960                        suffixes_inserted.push((end_row, comment_suffix.len()));
14961                    } else {
14962                        edits.push((prefix_range, empty_str.clone()));
14963                        edits.push((suffix_range, empty_str.clone()));
14964                    }
14965                } else {
14966                    continue;
14967                }
14968            }
14969
14970            drop(snapshot);
14971            this.buffer.update(cx, |buffer, cx| {
14972                buffer.edit(edits, None, cx);
14973            });
14974
14975            // Adjust selections so that they end before any comment suffixes that
14976            // were inserted.
14977            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14978            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
14979            let snapshot = this.buffer.read(cx).read(cx);
14980            for selection in &mut selections {
14981                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14982                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14983                        Ordering::Less => {
14984                            suffixes_inserted.next();
14985                            continue;
14986                        }
14987                        Ordering::Greater => break,
14988                        Ordering::Equal => {
14989                            if selection.end.column == snapshot.line_len(row) {
14990                                if selection.is_empty() {
14991                                    selection.start.column -= suffix_len as u32;
14992                                }
14993                                selection.end.column -= suffix_len as u32;
14994                            }
14995                            break;
14996                        }
14997                    }
14998                }
14999            }
15000
15001            drop(snapshot);
15002            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15003
15004            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15005            let selections_on_single_row = selections.windows(2).all(|selections| {
15006                selections[0].start.row == selections[1].start.row
15007                    && selections[0].end.row == selections[1].end.row
15008                    && selections[0].start.row == selections[0].end.row
15009            });
15010            let selections_selecting = selections
15011                .iter()
15012                .any(|selection| selection.start != selection.end);
15013            let advance_downwards = action.advance_downwards
15014                && selections_on_single_row
15015                && !selections_selecting
15016                && !matches!(this.mode, EditorMode::SingleLine);
15017
15018            if advance_downwards {
15019                let snapshot = this.buffer.read(cx).snapshot(cx);
15020
15021                this.change_selections(Default::default(), window, cx, |s| {
15022                    s.move_cursors_with(|display_snapshot, display_point, _| {
15023                        let mut point = display_point.to_point(display_snapshot);
15024                        point.row += 1;
15025                        point = snapshot.clip_point(point, Bias::Left);
15026                        let display_point = point.to_display_point(display_snapshot);
15027                        let goal = SelectionGoal::HorizontalPosition(
15028                            display_snapshot
15029                                .x_for_display_point(display_point, text_layout_details)
15030                                .into(),
15031                        );
15032                        (display_point, goal)
15033                    })
15034                });
15035            }
15036        });
15037    }
15038
15039    pub fn select_enclosing_symbol(
15040        &mut self,
15041        _: &SelectEnclosingSymbol,
15042        window: &mut Window,
15043        cx: &mut Context<Self>,
15044    ) {
15045        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15046
15047        let buffer = self.buffer.read(cx).snapshot(cx);
15048        let old_selections = self
15049            .selections
15050            .all::<usize>(&self.display_snapshot(cx))
15051            .into_boxed_slice();
15052
15053        fn update_selection(
15054            selection: &Selection<usize>,
15055            buffer_snap: &MultiBufferSnapshot,
15056        ) -> Option<Selection<usize>> {
15057            let cursor = selection.head();
15058            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15059            for symbol in symbols.iter().rev() {
15060                let start = symbol.range.start.to_offset(buffer_snap);
15061                let end = symbol.range.end.to_offset(buffer_snap);
15062                let new_range = start..end;
15063                if start < selection.start || end > selection.end {
15064                    return Some(Selection {
15065                        id: selection.id,
15066                        start: new_range.start,
15067                        end: new_range.end,
15068                        goal: SelectionGoal::None,
15069                        reversed: selection.reversed,
15070                    });
15071                }
15072            }
15073            None
15074        }
15075
15076        let mut selected_larger_symbol = false;
15077        let new_selections = old_selections
15078            .iter()
15079            .map(|selection| match update_selection(selection, &buffer) {
15080                Some(new_selection) => {
15081                    if new_selection.range() != selection.range() {
15082                        selected_larger_symbol = true;
15083                    }
15084                    new_selection
15085                }
15086                None => selection.clone(),
15087            })
15088            .collect::<Vec<_>>();
15089
15090        if selected_larger_symbol {
15091            self.change_selections(Default::default(), window, cx, |s| {
15092                s.select(new_selections);
15093            });
15094        }
15095    }
15096
15097    pub fn select_larger_syntax_node(
15098        &mut self,
15099        _: &SelectLargerSyntaxNode,
15100        window: &mut Window,
15101        cx: &mut Context<Self>,
15102    ) {
15103        let Some(visible_row_count) = self.visible_row_count() else {
15104            return;
15105        };
15106        let old_selections: Box<[_]> = self
15107            .selections
15108            .all::<usize>(&self.display_snapshot(cx))
15109            .into();
15110        if old_selections.is_empty() {
15111            return;
15112        }
15113
15114        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15115
15116        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15117        let buffer = self.buffer.read(cx).snapshot(cx);
15118
15119        let mut selected_larger_node = false;
15120        let mut new_selections = old_selections
15121            .iter()
15122            .map(|selection| {
15123                let old_range = selection.start..selection.end;
15124
15125                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15126                    // manually select word at selection
15127                    if ["string_content", "inline"].contains(&node.kind()) {
15128                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15129                        // ignore if word is already selected
15130                        if !word_range.is_empty() && old_range != word_range {
15131                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15132                            // only select word if start and end point belongs to same word
15133                            if word_range == last_word_range {
15134                                selected_larger_node = true;
15135                                return Selection {
15136                                    id: selection.id,
15137                                    start: word_range.start,
15138                                    end: word_range.end,
15139                                    goal: SelectionGoal::None,
15140                                    reversed: selection.reversed,
15141                                };
15142                            }
15143                        }
15144                    }
15145                }
15146
15147                let mut new_range = old_range.clone();
15148                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15149                    new_range = range;
15150                    if !node.is_named() {
15151                        continue;
15152                    }
15153                    if !display_map.intersects_fold(new_range.start)
15154                        && !display_map.intersects_fold(new_range.end)
15155                    {
15156                        break;
15157                    }
15158                }
15159
15160                selected_larger_node |= new_range != old_range;
15161                Selection {
15162                    id: selection.id,
15163                    start: new_range.start,
15164                    end: new_range.end,
15165                    goal: SelectionGoal::None,
15166                    reversed: selection.reversed,
15167                }
15168            })
15169            .collect::<Vec<_>>();
15170
15171        if !selected_larger_node {
15172            return; // don't put this call in the history
15173        }
15174
15175        // scroll based on transformation done to the last selection created by the user
15176        let (last_old, last_new) = old_selections
15177            .last()
15178            .zip(new_selections.last().cloned())
15179            .expect("old_selections isn't empty");
15180
15181        // revert selection
15182        let is_selection_reversed = {
15183            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15184            new_selections.last_mut().expect("checked above").reversed =
15185                should_newest_selection_be_reversed;
15186            should_newest_selection_be_reversed
15187        };
15188
15189        if selected_larger_node {
15190            self.select_syntax_node_history.disable_clearing = true;
15191            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15192                s.select(new_selections.clone());
15193            });
15194            self.select_syntax_node_history.disable_clearing = false;
15195        }
15196
15197        let start_row = last_new.start.to_display_point(&display_map).row().0;
15198        let end_row = last_new.end.to_display_point(&display_map).row().0;
15199        let selection_height = end_row - start_row + 1;
15200        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15201
15202        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15203        let scroll_behavior = if fits_on_the_screen {
15204            self.request_autoscroll(Autoscroll::fit(), cx);
15205            SelectSyntaxNodeScrollBehavior::FitSelection
15206        } else if is_selection_reversed {
15207            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15208            SelectSyntaxNodeScrollBehavior::CursorTop
15209        } else {
15210            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15211            SelectSyntaxNodeScrollBehavior::CursorBottom
15212        };
15213
15214        self.select_syntax_node_history.push((
15215            old_selections,
15216            scroll_behavior,
15217            is_selection_reversed,
15218        ));
15219    }
15220
15221    pub fn select_smaller_syntax_node(
15222        &mut self,
15223        _: &SelectSmallerSyntaxNode,
15224        window: &mut Window,
15225        cx: &mut Context<Self>,
15226    ) {
15227        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15228
15229        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15230            self.select_syntax_node_history.pop()
15231        {
15232            if let Some(selection) = selections.last_mut() {
15233                selection.reversed = is_selection_reversed;
15234            }
15235
15236            self.select_syntax_node_history.disable_clearing = true;
15237            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15238                s.select(selections.to_vec());
15239            });
15240            self.select_syntax_node_history.disable_clearing = false;
15241
15242            match scroll_behavior {
15243                SelectSyntaxNodeScrollBehavior::CursorTop => {
15244                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15245                }
15246                SelectSyntaxNodeScrollBehavior::FitSelection => {
15247                    self.request_autoscroll(Autoscroll::fit(), cx);
15248                }
15249                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15250                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15251                }
15252            }
15253        }
15254    }
15255
15256    pub fn unwrap_syntax_node(
15257        &mut self,
15258        _: &UnwrapSyntaxNode,
15259        window: &mut Window,
15260        cx: &mut Context<Self>,
15261    ) {
15262        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15263
15264        let buffer = self.buffer.read(cx).snapshot(cx);
15265        let selections = self
15266            .selections
15267            .all::<usize>(&self.display_snapshot(cx))
15268            .into_iter()
15269            // subtracting the offset requires sorting
15270            .sorted_by_key(|i| i.start);
15271
15272        let full_edits = selections
15273            .into_iter()
15274            .filter_map(|selection| {
15275                let child = if selection.is_empty()
15276                    && let Some((_, ancestor_range)) =
15277                        buffer.syntax_ancestor(selection.start..selection.end)
15278                {
15279                    ancestor_range
15280                } else {
15281                    selection.range()
15282                };
15283
15284                let mut parent = child.clone();
15285                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15286                    parent = ancestor_range;
15287                    if parent.start < child.start || parent.end > child.end {
15288                        break;
15289                    }
15290                }
15291
15292                if parent == child {
15293                    return None;
15294                }
15295                let text = buffer.text_for_range(child).collect::<String>();
15296                Some((selection.id, parent, text))
15297            })
15298            .collect::<Vec<_>>();
15299        if full_edits.is_empty() {
15300            return;
15301        }
15302
15303        self.transact(window, cx, |this, window, cx| {
15304            this.buffer.update(cx, |buffer, cx| {
15305                buffer.edit(
15306                    full_edits
15307                        .iter()
15308                        .map(|(_, p, t)| (p.clone(), t.clone()))
15309                        .collect::<Vec<_>>(),
15310                    None,
15311                    cx,
15312                );
15313            });
15314            this.change_selections(Default::default(), window, cx, |s| {
15315                let mut offset = 0;
15316                let mut selections = vec![];
15317                for (id, parent, text) in full_edits {
15318                    let start = parent.start - offset;
15319                    offset += parent.len() - text.len();
15320                    selections.push(Selection {
15321                        id,
15322                        start,
15323                        end: start + text.len(),
15324                        reversed: false,
15325                        goal: Default::default(),
15326                    });
15327                }
15328                s.select(selections);
15329            });
15330        });
15331    }
15332
15333    pub fn select_next_syntax_node(
15334        &mut self,
15335        _: &SelectNextSyntaxNode,
15336        window: &mut Window,
15337        cx: &mut Context<Self>,
15338    ) {
15339        let old_selections: Box<[_]> = self
15340            .selections
15341            .all::<usize>(&self.display_snapshot(cx))
15342            .into();
15343        if old_selections.is_empty() {
15344            return;
15345        }
15346
15347        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15348
15349        let buffer = self.buffer.read(cx).snapshot(cx);
15350        let mut selected_sibling = false;
15351
15352        let new_selections = old_selections
15353            .iter()
15354            .map(|selection| {
15355                let old_range = selection.start..selection.end;
15356
15357                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15358                    let new_range = node.byte_range();
15359                    selected_sibling = true;
15360                    Selection {
15361                        id: selection.id,
15362                        start: new_range.start,
15363                        end: new_range.end,
15364                        goal: SelectionGoal::None,
15365                        reversed: selection.reversed,
15366                    }
15367                } else {
15368                    selection.clone()
15369                }
15370            })
15371            .collect::<Vec<_>>();
15372
15373        if selected_sibling {
15374            self.change_selections(
15375                SelectionEffects::scroll(Autoscroll::fit()),
15376                window,
15377                cx,
15378                |s| {
15379                    s.select(new_selections);
15380                },
15381            );
15382        }
15383    }
15384
15385    pub fn select_prev_syntax_node(
15386        &mut self,
15387        _: &SelectPreviousSyntaxNode,
15388        window: &mut Window,
15389        cx: &mut Context<Self>,
15390    ) {
15391        let old_selections: Box<[_]> = self
15392            .selections
15393            .all::<usize>(&self.display_snapshot(cx))
15394            .into();
15395        if old_selections.is_empty() {
15396            return;
15397        }
15398
15399        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15400
15401        let buffer = self.buffer.read(cx).snapshot(cx);
15402        let mut selected_sibling = false;
15403
15404        let new_selections = old_selections
15405            .iter()
15406            .map(|selection| {
15407                let old_range = selection.start..selection.end;
15408
15409                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15410                    let new_range = node.byte_range();
15411                    selected_sibling = true;
15412                    Selection {
15413                        id: selection.id,
15414                        start: new_range.start,
15415                        end: new_range.end,
15416                        goal: SelectionGoal::None,
15417                        reversed: selection.reversed,
15418                    }
15419                } else {
15420                    selection.clone()
15421                }
15422            })
15423            .collect::<Vec<_>>();
15424
15425        if selected_sibling {
15426            self.change_selections(
15427                SelectionEffects::scroll(Autoscroll::fit()),
15428                window,
15429                cx,
15430                |s| {
15431                    s.select(new_selections);
15432                },
15433            );
15434        }
15435    }
15436
15437    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15438        if !EditorSettings::get_global(cx).gutter.runnables {
15439            self.clear_tasks();
15440            return Task::ready(());
15441        }
15442        let project = self.project().map(Entity::downgrade);
15443        let task_sources = self.lsp_task_sources(cx);
15444        let multi_buffer = self.buffer.downgrade();
15445        cx.spawn_in(window, async move |editor, cx| {
15446            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15447            let Some(project) = project.and_then(|p| p.upgrade()) else {
15448                return;
15449            };
15450            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15451                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15452            }) else {
15453                return;
15454            };
15455
15456            let hide_runnables = project
15457                .update(cx, |project, _| project.is_via_collab())
15458                .unwrap_or(true);
15459            if hide_runnables {
15460                return;
15461            }
15462            let new_rows =
15463                cx.background_spawn({
15464                    let snapshot = display_snapshot.clone();
15465                    async move {
15466                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15467                    }
15468                })
15469                    .await;
15470            let Ok(lsp_tasks) =
15471                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15472            else {
15473                return;
15474            };
15475            let lsp_tasks = lsp_tasks.await;
15476
15477            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15478                lsp_tasks
15479                    .into_iter()
15480                    .flat_map(|(kind, tasks)| {
15481                        tasks.into_iter().filter_map(move |(location, task)| {
15482                            Some((kind.clone(), location?, task))
15483                        })
15484                    })
15485                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15486                        let buffer = location.target.buffer;
15487                        let buffer_snapshot = buffer.read(cx).snapshot();
15488                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15489                            |(excerpt_id, snapshot, _)| {
15490                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15491                                    display_snapshot
15492                                        .buffer_snapshot()
15493                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15494                                } else {
15495                                    None
15496                                }
15497                            },
15498                        );
15499                        if let Some(offset) = offset {
15500                            let task_buffer_range =
15501                                location.target.range.to_point(&buffer_snapshot);
15502                            let context_buffer_range =
15503                                task_buffer_range.to_offset(&buffer_snapshot);
15504                            let context_range = BufferOffset(context_buffer_range.start)
15505                                ..BufferOffset(context_buffer_range.end);
15506
15507                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15508                                .or_insert_with(|| RunnableTasks {
15509                                    templates: Vec::new(),
15510                                    offset,
15511                                    column: task_buffer_range.start.column,
15512                                    extra_variables: HashMap::default(),
15513                                    context_range,
15514                                })
15515                                .templates
15516                                .push((kind, task.original_task().clone()));
15517                        }
15518
15519                        acc
15520                    })
15521            }) else {
15522                return;
15523            };
15524
15525            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15526                buffer.language_settings(cx).tasks.prefer_lsp
15527            }) else {
15528                return;
15529            };
15530
15531            let rows = Self::runnable_rows(
15532                project,
15533                display_snapshot,
15534                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15535                new_rows,
15536                cx.clone(),
15537            )
15538            .await;
15539            editor
15540                .update(cx, |editor, _| {
15541                    editor.clear_tasks();
15542                    for (key, mut value) in rows {
15543                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15544                            value.templates.extend(lsp_tasks.templates);
15545                        }
15546
15547                        editor.insert_tasks(key, value);
15548                    }
15549                    for (key, value) in lsp_tasks_by_rows {
15550                        editor.insert_tasks(key, value);
15551                    }
15552                })
15553                .ok();
15554        })
15555    }
15556    fn fetch_runnable_ranges(
15557        snapshot: &DisplaySnapshot,
15558        range: Range<Anchor>,
15559    ) -> Vec<language::RunnableRange> {
15560        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15561    }
15562
15563    fn runnable_rows(
15564        project: Entity<Project>,
15565        snapshot: DisplaySnapshot,
15566        prefer_lsp: bool,
15567        runnable_ranges: Vec<RunnableRange>,
15568        cx: AsyncWindowContext,
15569    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15570        cx.spawn(async move |cx| {
15571            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15572            for mut runnable in runnable_ranges {
15573                let Some(tasks) = cx
15574                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15575                    .ok()
15576                else {
15577                    continue;
15578                };
15579                let mut tasks = tasks.await;
15580
15581                if prefer_lsp {
15582                    tasks.retain(|(task_kind, _)| {
15583                        !matches!(task_kind, TaskSourceKind::Language { .. })
15584                    });
15585                }
15586                if tasks.is_empty() {
15587                    continue;
15588                }
15589
15590                let point = runnable
15591                    .run_range
15592                    .start
15593                    .to_point(&snapshot.buffer_snapshot());
15594                let Some(row) = snapshot
15595                    .buffer_snapshot()
15596                    .buffer_line_for_row(MultiBufferRow(point.row))
15597                    .map(|(_, range)| range.start.row)
15598                else {
15599                    continue;
15600                };
15601
15602                let context_range =
15603                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15604                runnable_rows.push((
15605                    (runnable.buffer_id, row),
15606                    RunnableTasks {
15607                        templates: tasks,
15608                        offset: snapshot
15609                            .buffer_snapshot()
15610                            .anchor_before(runnable.run_range.start),
15611                        context_range,
15612                        column: point.column,
15613                        extra_variables: runnable.extra_captures,
15614                    },
15615                ));
15616            }
15617            runnable_rows
15618        })
15619    }
15620
15621    fn templates_with_tags(
15622        project: &Entity<Project>,
15623        runnable: &mut Runnable,
15624        cx: &mut App,
15625    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15626        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15627            let (worktree_id, file) = project
15628                .buffer_for_id(runnable.buffer, cx)
15629                .and_then(|buffer| buffer.read(cx).file())
15630                .map(|file| (file.worktree_id(cx), file.clone()))
15631                .unzip();
15632
15633            (
15634                project.task_store().read(cx).task_inventory().cloned(),
15635                worktree_id,
15636                file,
15637            )
15638        });
15639
15640        let tags = mem::take(&mut runnable.tags);
15641        let language = runnable.language.clone();
15642        cx.spawn(async move |cx| {
15643            let mut templates_with_tags = Vec::new();
15644            if let Some(inventory) = inventory {
15645                for RunnableTag(tag) in tags {
15646                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15647                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15648                    }) else {
15649                        return templates_with_tags;
15650                    };
15651                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15652                        move |(_, template)| {
15653                            template.tags.iter().any(|source_tag| source_tag == &tag)
15654                        },
15655                    ));
15656                }
15657            }
15658            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15659
15660            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15661                // Strongest source wins; if we have worktree tag binding, prefer that to
15662                // global and language bindings;
15663                // if we have a global binding, prefer that to language binding.
15664                let first_mismatch = templates_with_tags
15665                    .iter()
15666                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15667                if let Some(index) = first_mismatch {
15668                    templates_with_tags.truncate(index);
15669                }
15670            }
15671
15672            templates_with_tags
15673        })
15674    }
15675
15676    pub fn move_to_enclosing_bracket(
15677        &mut self,
15678        _: &MoveToEnclosingBracket,
15679        window: &mut Window,
15680        cx: &mut Context<Self>,
15681    ) {
15682        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15683        self.change_selections(Default::default(), window, cx, |s| {
15684            s.move_offsets_with(|snapshot, selection| {
15685                let Some(enclosing_bracket_ranges) =
15686                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15687                else {
15688                    return;
15689                };
15690
15691                let mut best_length = usize::MAX;
15692                let mut best_inside = false;
15693                let mut best_in_bracket_range = false;
15694                let mut best_destination = None;
15695                for (open, close) in enclosing_bracket_ranges {
15696                    let close = close.to_inclusive();
15697                    let length = close.end() - open.start;
15698                    let inside = selection.start >= open.end && selection.end <= *close.start();
15699                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15700                        || close.contains(&selection.head());
15701
15702                    // If best is next to a bracket and current isn't, skip
15703                    if !in_bracket_range && best_in_bracket_range {
15704                        continue;
15705                    }
15706
15707                    // Prefer smaller lengths unless best is inside and current isn't
15708                    if length > best_length && (best_inside || !inside) {
15709                        continue;
15710                    }
15711
15712                    best_length = length;
15713                    best_inside = inside;
15714                    best_in_bracket_range = in_bracket_range;
15715                    best_destination = Some(
15716                        if close.contains(&selection.start) && close.contains(&selection.end) {
15717                            if inside { open.end } else { open.start }
15718                        } else if inside {
15719                            *close.start()
15720                        } else {
15721                            *close.end()
15722                        },
15723                    );
15724                }
15725
15726                if let Some(destination) = best_destination {
15727                    selection.collapse_to(destination, SelectionGoal::None);
15728                }
15729            })
15730        });
15731    }
15732
15733    pub fn undo_selection(
15734        &mut self,
15735        _: &UndoSelection,
15736        window: &mut Window,
15737        cx: &mut Context<Self>,
15738    ) {
15739        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15740        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15741            self.selection_history.mode = SelectionHistoryMode::Undoing;
15742            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15743                this.end_selection(window, cx);
15744                this.change_selections(
15745                    SelectionEffects::scroll(Autoscroll::newest()),
15746                    window,
15747                    cx,
15748                    |s| s.select_anchors(entry.selections.to_vec()),
15749                );
15750            });
15751            self.selection_history.mode = SelectionHistoryMode::Normal;
15752
15753            self.select_next_state = entry.select_next_state;
15754            self.select_prev_state = entry.select_prev_state;
15755            self.add_selections_state = entry.add_selections_state;
15756        }
15757    }
15758
15759    pub fn redo_selection(
15760        &mut self,
15761        _: &RedoSelection,
15762        window: &mut Window,
15763        cx: &mut Context<Self>,
15764    ) {
15765        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15766        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15767            self.selection_history.mode = SelectionHistoryMode::Redoing;
15768            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15769                this.end_selection(window, cx);
15770                this.change_selections(
15771                    SelectionEffects::scroll(Autoscroll::newest()),
15772                    window,
15773                    cx,
15774                    |s| s.select_anchors(entry.selections.to_vec()),
15775                );
15776            });
15777            self.selection_history.mode = SelectionHistoryMode::Normal;
15778
15779            self.select_next_state = entry.select_next_state;
15780            self.select_prev_state = entry.select_prev_state;
15781            self.add_selections_state = entry.add_selections_state;
15782        }
15783    }
15784
15785    pub fn expand_excerpts(
15786        &mut self,
15787        action: &ExpandExcerpts,
15788        _: &mut Window,
15789        cx: &mut Context<Self>,
15790    ) {
15791        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15792    }
15793
15794    pub fn expand_excerpts_down(
15795        &mut self,
15796        action: &ExpandExcerptsDown,
15797        _: &mut Window,
15798        cx: &mut Context<Self>,
15799    ) {
15800        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15801    }
15802
15803    pub fn expand_excerpts_up(
15804        &mut self,
15805        action: &ExpandExcerptsUp,
15806        _: &mut Window,
15807        cx: &mut Context<Self>,
15808    ) {
15809        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15810    }
15811
15812    pub fn expand_excerpts_for_direction(
15813        &mut self,
15814        lines: u32,
15815        direction: ExpandExcerptDirection,
15816
15817        cx: &mut Context<Self>,
15818    ) {
15819        let selections = self.selections.disjoint_anchors_arc();
15820
15821        let lines = if lines == 0 {
15822            EditorSettings::get_global(cx).expand_excerpt_lines
15823        } else {
15824            lines
15825        };
15826
15827        self.buffer.update(cx, |buffer, cx| {
15828            let snapshot = buffer.snapshot(cx);
15829            let mut excerpt_ids = selections
15830                .iter()
15831                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15832                .collect::<Vec<_>>();
15833            excerpt_ids.sort();
15834            excerpt_ids.dedup();
15835            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15836        })
15837    }
15838
15839    pub fn expand_excerpt(
15840        &mut self,
15841        excerpt: ExcerptId,
15842        direction: ExpandExcerptDirection,
15843        window: &mut Window,
15844        cx: &mut Context<Self>,
15845    ) {
15846        let current_scroll_position = self.scroll_position(cx);
15847        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15848        let mut scroll = None;
15849
15850        if direction == ExpandExcerptDirection::Down {
15851            let multi_buffer = self.buffer.read(cx);
15852            let snapshot = multi_buffer.snapshot(cx);
15853            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15854                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15855                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15856            {
15857                let buffer_snapshot = buffer.read(cx).snapshot();
15858                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15859                let last_row = buffer_snapshot.max_point().row;
15860                let lines_below = last_row.saturating_sub(excerpt_end_row);
15861                if lines_below >= lines_to_expand {
15862                    scroll = Some(
15863                        current_scroll_position
15864                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
15865                    );
15866                }
15867            }
15868        }
15869        if direction == ExpandExcerptDirection::Up
15870            && self
15871                .buffer
15872                .read(cx)
15873                .snapshot(cx)
15874                .excerpt_before(excerpt)
15875                .is_none()
15876        {
15877            scroll = Some(current_scroll_position);
15878        }
15879
15880        self.buffer.update(cx, |buffer, cx| {
15881            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15882        });
15883
15884        if let Some(new_scroll_position) = scroll {
15885            self.set_scroll_position(new_scroll_position, window, cx);
15886        }
15887    }
15888
15889    pub fn go_to_singleton_buffer_point(
15890        &mut self,
15891        point: Point,
15892        window: &mut Window,
15893        cx: &mut Context<Self>,
15894    ) {
15895        self.go_to_singleton_buffer_range(point..point, window, cx);
15896    }
15897
15898    pub fn go_to_singleton_buffer_range(
15899        &mut self,
15900        range: Range<Point>,
15901        window: &mut Window,
15902        cx: &mut Context<Self>,
15903    ) {
15904        let multibuffer = self.buffer().read(cx);
15905        let Some(buffer) = multibuffer.as_singleton() else {
15906            return;
15907        };
15908        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15909            return;
15910        };
15911        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15912            return;
15913        };
15914        self.change_selections(
15915            SelectionEffects::default().nav_history(true),
15916            window,
15917            cx,
15918            |s| s.select_anchor_ranges([start..end]),
15919        );
15920    }
15921
15922    pub fn go_to_diagnostic(
15923        &mut self,
15924        action: &GoToDiagnostic,
15925        window: &mut Window,
15926        cx: &mut Context<Self>,
15927    ) {
15928        if !self.diagnostics_enabled() {
15929            return;
15930        }
15931        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15932        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15933    }
15934
15935    pub fn go_to_prev_diagnostic(
15936        &mut self,
15937        action: &GoToPreviousDiagnostic,
15938        window: &mut Window,
15939        cx: &mut Context<Self>,
15940    ) {
15941        if !self.diagnostics_enabled() {
15942            return;
15943        }
15944        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15945        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15946    }
15947
15948    pub fn go_to_diagnostic_impl(
15949        &mut self,
15950        direction: Direction,
15951        severity: GoToDiagnosticSeverityFilter,
15952        window: &mut Window,
15953        cx: &mut Context<Self>,
15954    ) {
15955        let buffer = self.buffer.read(cx).snapshot(cx);
15956        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
15957
15958        let mut active_group_id = None;
15959        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15960            && active_group.active_range.start.to_offset(&buffer) == selection.start
15961        {
15962            active_group_id = Some(active_group.group_id);
15963        }
15964
15965        fn filtered<'a>(
15966            snapshot: EditorSnapshot,
15967            severity: GoToDiagnosticSeverityFilter,
15968            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
15969        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
15970            diagnostics
15971                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15972                .filter(|entry| entry.range.start != entry.range.end)
15973                .filter(|entry| !entry.diagnostic.is_unnecessary)
15974                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15975        }
15976
15977        let snapshot = self.snapshot(window, cx);
15978        let before = filtered(
15979            snapshot.clone(),
15980            severity,
15981            buffer
15982                .diagnostics_in_range(0..selection.start)
15983                .filter(|entry| entry.range.start <= selection.start),
15984        );
15985        let after = filtered(
15986            snapshot,
15987            severity,
15988            buffer
15989                .diagnostics_in_range(selection.start..buffer.len())
15990                .filter(|entry| entry.range.start >= selection.start),
15991        );
15992
15993        let mut found: Option<DiagnosticEntryRef<usize>> = None;
15994        if direction == Direction::Prev {
15995            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15996            {
15997                for diagnostic in prev_diagnostics.into_iter().rev() {
15998                    if diagnostic.range.start != selection.start
15999                        || active_group_id
16000                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16001                    {
16002                        found = Some(diagnostic);
16003                        break 'outer;
16004                    }
16005                }
16006            }
16007        } else {
16008            for diagnostic in after.chain(before) {
16009                if diagnostic.range.start != selection.start
16010                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16011                {
16012                    found = Some(diagnostic);
16013                    break;
16014                }
16015            }
16016        }
16017        let Some(next_diagnostic) = found else {
16018            return;
16019        };
16020
16021        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16022        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16023            return;
16024        };
16025        self.change_selections(Default::default(), window, cx, |s| {
16026            s.select_ranges(vec![
16027                next_diagnostic.range.start..next_diagnostic.range.start,
16028            ])
16029        });
16030        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16031        self.refresh_edit_prediction(false, true, window, cx);
16032    }
16033
16034    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16035        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16036        let snapshot = self.snapshot(window, cx);
16037        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16038        self.go_to_hunk_before_or_after_position(
16039            &snapshot,
16040            selection.head(),
16041            Direction::Next,
16042            window,
16043            cx,
16044        );
16045    }
16046
16047    pub fn go_to_hunk_before_or_after_position(
16048        &mut self,
16049        snapshot: &EditorSnapshot,
16050        position: Point,
16051        direction: Direction,
16052        window: &mut Window,
16053        cx: &mut Context<Editor>,
16054    ) {
16055        let row = if direction == Direction::Next {
16056            self.hunk_after_position(snapshot, position)
16057                .map(|hunk| hunk.row_range.start)
16058        } else {
16059            self.hunk_before_position(snapshot, position)
16060        };
16061
16062        if let Some(row) = row {
16063            let destination = Point::new(row.0, 0);
16064            let autoscroll = Autoscroll::center();
16065
16066            self.unfold_ranges(&[destination..destination], false, false, cx);
16067            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16068                s.select_ranges([destination..destination]);
16069            });
16070        }
16071    }
16072
16073    fn hunk_after_position(
16074        &mut self,
16075        snapshot: &EditorSnapshot,
16076        position: Point,
16077    ) -> Option<MultiBufferDiffHunk> {
16078        snapshot
16079            .buffer_snapshot()
16080            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16081            .find(|hunk| hunk.row_range.start.0 > position.row)
16082            .or_else(|| {
16083                snapshot
16084                    .buffer_snapshot()
16085                    .diff_hunks_in_range(Point::zero()..position)
16086                    .find(|hunk| hunk.row_range.end.0 < position.row)
16087            })
16088    }
16089
16090    fn go_to_prev_hunk(
16091        &mut self,
16092        _: &GoToPreviousHunk,
16093        window: &mut Window,
16094        cx: &mut Context<Self>,
16095    ) {
16096        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16097        let snapshot = self.snapshot(window, cx);
16098        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16099        self.go_to_hunk_before_or_after_position(
16100            &snapshot,
16101            selection.head(),
16102            Direction::Prev,
16103            window,
16104            cx,
16105        );
16106    }
16107
16108    fn hunk_before_position(
16109        &mut self,
16110        snapshot: &EditorSnapshot,
16111        position: Point,
16112    ) -> Option<MultiBufferRow> {
16113        snapshot
16114            .buffer_snapshot()
16115            .diff_hunk_before(position)
16116            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16117    }
16118
16119    fn go_to_next_change(
16120        &mut self,
16121        _: &GoToNextChange,
16122        window: &mut Window,
16123        cx: &mut Context<Self>,
16124    ) {
16125        if let Some(selections) = self
16126            .change_list
16127            .next_change(1, Direction::Next)
16128            .map(|s| s.to_vec())
16129        {
16130            self.change_selections(Default::default(), window, cx, |s| {
16131                let map = s.display_map();
16132                s.select_display_ranges(selections.iter().map(|a| {
16133                    let point = a.to_display_point(&map);
16134                    point..point
16135                }))
16136            })
16137        }
16138    }
16139
16140    fn go_to_previous_change(
16141        &mut self,
16142        _: &GoToPreviousChange,
16143        window: &mut Window,
16144        cx: &mut Context<Self>,
16145    ) {
16146        if let Some(selections) = self
16147            .change_list
16148            .next_change(1, Direction::Prev)
16149            .map(|s| s.to_vec())
16150        {
16151            self.change_selections(Default::default(), window, cx, |s| {
16152                let map = s.display_map();
16153                s.select_display_ranges(selections.iter().map(|a| {
16154                    let point = a.to_display_point(&map);
16155                    point..point
16156                }))
16157            })
16158        }
16159    }
16160
16161    pub fn go_to_next_document_highlight(
16162        &mut self,
16163        _: &GoToNextDocumentHighlight,
16164        window: &mut Window,
16165        cx: &mut Context<Self>,
16166    ) {
16167        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16168    }
16169
16170    pub fn go_to_prev_document_highlight(
16171        &mut self,
16172        _: &GoToPreviousDocumentHighlight,
16173        window: &mut Window,
16174        cx: &mut Context<Self>,
16175    ) {
16176        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16177    }
16178
16179    pub fn go_to_document_highlight_before_or_after_position(
16180        &mut self,
16181        direction: Direction,
16182        window: &mut Window,
16183        cx: &mut Context<Editor>,
16184    ) {
16185        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16186        let snapshot = self.snapshot(window, cx);
16187        let buffer = &snapshot.buffer_snapshot();
16188        let position = self
16189            .selections
16190            .newest::<Point>(&snapshot.display_snapshot)
16191            .head();
16192        let anchor_position = buffer.anchor_after(position);
16193
16194        // Get all document highlights (both read and write)
16195        let mut all_highlights = Vec::new();
16196
16197        if let Some((_, read_highlights)) = self
16198            .background_highlights
16199            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16200        {
16201            all_highlights.extend(read_highlights.iter());
16202        }
16203
16204        if let Some((_, write_highlights)) = self
16205            .background_highlights
16206            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16207        {
16208            all_highlights.extend(write_highlights.iter());
16209        }
16210
16211        if all_highlights.is_empty() {
16212            return;
16213        }
16214
16215        // Sort highlights by position
16216        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16217
16218        let target_highlight = match direction {
16219            Direction::Next => {
16220                // Find the first highlight after the current position
16221                all_highlights
16222                    .iter()
16223                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16224            }
16225            Direction::Prev => {
16226                // Find the last highlight before the current position
16227                all_highlights
16228                    .iter()
16229                    .rev()
16230                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16231            }
16232        };
16233
16234        if let Some(highlight) = target_highlight {
16235            let destination = highlight.start.to_point(buffer);
16236            let autoscroll = Autoscroll::center();
16237
16238            self.unfold_ranges(&[destination..destination], false, false, cx);
16239            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16240                s.select_ranges([destination..destination]);
16241            });
16242        }
16243    }
16244
16245    fn go_to_line<T: 'static>(
16246        &mut self,
16247        position: Anchor,
16248        highlight_color: Option<Hsla>,
16249        window: &mut Window,
16250        cx: &mut Context<Self>,
16251    ) {
16252        let snapshot = self.snapshot(window, cx).display_snapshot;
16253        let position = position.to_point(&snapshot.buffer_snapshot());
16254        let start = snapshot
16255            .buffer_snapshot()
16256            .clip_point(Point::new(position.row, 0), Bias::Left);
16257        let end = start + Point::new(1, 0);
16258        let start = snapshot.buffer_snapshot().anchor_before(start);
16259        let end = snapshot.buffer_snapshot().anchor_before(end);
16260
16261        self.highlight_rows::<T>(
16262            start..end,
16263            highlight_color
16264                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16265            Default::default(),
16266            cx,
16267        );
16268
16269        if self.buffer.read(cx).is_singleton() {
16270            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16271        }
16272    }
16273
16274    pub fn go_to_definition(
16275        &mut self,
16276        _: &GoToDefinition,
16277        window: &mut Window,
16278        cx: &mut Context<Self>,
16279    ) -> Task<Result<Navigated>> {
16280        let definition =
16281            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16282        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16283        cx.spawn_in(window, async move |editor, cx| {
16284            if definition.await? == Navigated::Yes {
16285                return Ok(Navigated::Yes);
16286            }
16287            match fallback_strategy {
16288                GoToDefinitionFallback::None => Ok(Navigated::No),
16289                GoToDefinitionFallback::FindAllReferences => {
16290                    match editor.update_in(cx, |editor, window, cx| {
16291                        editor.find_all_references(&FindAllReferences, window, cx)
16292                    })? {
16293                        Some(references) => references.await,
16294                        None => Ok(Navigated::No),
16295                    }
16296                }
16297            }
16298        })
16299    }
16300
16301    pub fn go_to_declaration(
16302        &mut self,
16303        _: &GoToDeclaration,
16304        window: &mut Window,
16305        cx: &mut Context<Self>,
16306    ) -> Task<Result<Navigated>> {
16307        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16308    }
16309
16310    pub fn go_to_declaration_split(
16311        &mut self,
16312        _: &GoToDeclaration,
16313        window: &mut Window,
16314        cx: &mut Context<Self>,
16315    ) -> Task<Result<Navigated>> {
16316        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16317    }
16318
16319    pub fn go_to_implementation(
16320        &mut self,
16321        _: &GoToImplementation,
16322        window: &mut Window,
16323        cx: &mut Context<Self>,
16324    ) -> Task<Result<Navigated>> {
16325        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16326    }
16327
16328    pub fn go_to_implementation_split(
16329        &mut self,
16330        _: &GoToImplementationSplit,
16331        window: &mut Window,
16332        cx: &mut Context<Self>,
16333    ) -> Task<Result<Navigated>> {
16334        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16335    }
16336
16337    pub fn go_to_type_definition(
16338        &mut self,
16339        _: &GoToTypeDefinition,
16340        window: &mut Window,
16341        cx: &mut Context<Self>,
16342    ) -> Task<Result<Navigated>> {
16343        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16344    }
16345
16346    pub fn go_to_definition_split(
16347        &mut self,
16348        _: &GoToDefinitionSplit,
16349        window: &mut Window,
16350        cx: &mut Context<Self>,
16351    ) -> Task<Result<Navigated>> {
16352        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16353    }
16354
16355    pub fn go_to_type_definition_split(
16356        &mut self,
16357        _: &GoToTypeDefinitionSplit,
16358        window: &mut Window,
16359        cx: &mut Context<Self>,
16360    ) -> Task<Result<Navigated>> {
16361        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16362    }
16363
16364    fn go_to_definition_of_kind(
16365        &mut self,
16366        kind: GotoDefinitionKind,
16367        split: bool,
16368        window: &mut Window,
16369        cx: &mut Context<Self>,
16370    ) -> Task<Result<Navigated>> {
16371        let Some(provider) = self.semantics_provider.clone() else {
16372            return Task::ready(Ok(Navigated::No));
16373        };
16374        let head = self
16375            .selections
16376            .newest::<usize>(&self.display_snapshot(cx))
16377            .head();
16378        let buffer = self.buffer.read(cx);
16379        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16380            return Task::ready(Ok(Navigated::No));
16381        };
16382        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16383            return Task::ready(Ok(Navigated::No));
16384        };
16385
16386        cx.spawn_in(window, async move |editor, cx| {
16387            let Some(definitions) = definitions.await? else {
16388                return Ok(Navigated::No);
16389            };
16390            let navigated = editor
16391                .update_in(cx, |editor, window, cx| {
16392                    editor.navigate_to_hover_links(
16393                        Some(kind),
16394                        definitions
16395                            .into_iter()
16396                            .filter(|location| {
16397                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16398                            })
16399                            .map(HoverLink::Text)
16400                            .collect::<Vec<_>>(),
16401                        split,
16402                        window,
16403                        cx,
16404                    )
16405                })?
16406                .await?;
16407            anyhow::Ok(navigated)
16408        })
16409    }
16410
16411    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16412        let selection = self.selections.newest_anchor();
16413        let head = selection.head();
16414        let tail = selection.tail();
16415
16416        let Some((buffer, start_position)) =
16417            self.buffer.read(cx).text_anchor_for_position(head, cx)
16418        else {
16419            return;
16420        };
16421
16422        let end_position = if head != tail {
16423            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16424                return;
16425            };
16426            Some(pos)
16427        } else {
16428            None
16429        };
16430
16431        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16432            let url = if let Some(end_pos) = end_position {
16433                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16434            } else {
16435                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16436            };
16437
16438            if let Some(url) = url {
16439                cx.update(|window, cx| {
16440                    if parse_zed_link(&url, cx).is_some() {
16441                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16442                    } else {
16443                        cx.open_url(&url);
16444                    }
16445                })?;
16446            }
16447
16448            anyhow::Ok(())
16449        });
16450
16451        url_finder.detach();
16452    }
16453
16454    pub fn open_selected_filename(
16455        &mut self,
16456        _: &OpenSelectedFilename,
16457        window: &mut Window,
16458        cx: &mut Context<Self>,
16459    ) {
16460        let Some(workspace) = self.workspace() else {
16461            return;
16462        };
16463
16464        let position = self.selections.newest_anchor().head();
16465
16466        let Some((buffer, buffer_position)) =
16467            self.buffer.read(cx).text_anchor_for_position(position, cx)
16468        else {
16469            return;
16470        };
16471
16472        let project = self.project.clone();
16473
16474        cx.spawn_in(window, async move |_, cx| {
16475            let result = find_file(&buffer, project, buffer_position, cx).await;
16476
16477            if let Some((_, path)) = result {
16478                workspace
16479                    .update_in(cx, |workspace, window, cx| {
16480                        workspace.open_resolved_path(path, window, cx)
16481                    })?
16482                    .await?;
16483            }
16484            anyhow::Ok(())
16485        })
16486        .detach();
16487    }
16488
16489    pub(crate) fn navigate_to_hover_links(
16490        &mut self,
16491        kind: Option<GotoDefinitionKind>,
16492        definitions: Vec<HoverLink>,
16493        split: bool,
16494        window: &mut Window,
16495        cx: &mut Context<Editor>,
16496    ) -> Task<Result<Navigated>> {
16497        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16498        let mut first_url_or_file = None;
16499        let definitions: Vec<_> = definitions
16500            .into_iter()
16501            .filter_map(|def| match def {
16502                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16503                HoverLink::InlayHint(lsp_location, server_id) => {
16504                    let computation =
16505                        self.compute_target_location(lsp_location, server_id, window, cx);
16506                    Some(cx.background_spawn(computation))
16507                }
16508                HoverLink::Url(url) => {
16509                    first_url_or_file = Some(Either::Left(url));
16510                    None
16511                }
16512                HoverLink::File(path) => {
16513                    first_url_or_file = Some(Either::Right(path));
16514                    None
16515                }
16516            })
16517            .collect();
16518
16519        let workspace = self.workspace();
16520
16521        cx.spawn_in(window, async move |editor, cx| {
16522            let locations: Vec<Location> = future::join_all(definitions)
16523                .await
16524                .into_iter()
16525                .filter_map(|location| location.transpose())
16526                .collect::<Result<_>>()
16527                .context("location tasks")?;
16528            let mut locations = cx.update(|_, cx| {
16529                locations
16530                    .into_iter()
16531                    .map(|location| {
16532                        let buffer = location.buffer.read(cx);
16533                        (location.buffer, location.range.to_point(buffer))
16534                    })
16535                    .into_group_map()
16536            })?;
16537            let mut num_locations = 0;
16538            for ranges in locations.values_mut() {
16539                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16540                ranges.dedup();
16541                num_locations += ranges.len();
16542            }
16543
16544            if num_locations > 1 {
16545                let Some(workspace) = workspace else {
16546                    return Ok(Navigated::No);
16547                };
16548
16549                let tab_kind = match kind {
16550                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16551                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16552                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16553                    Some(GotoDefinitionKind::Type) => "Types",
16554                };
16555                let title = editor
16556                    .update_in(cx, |_, _, cx| {
16557                        let target = locations
16558                            .iter()
16559                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16560                            .map(|(buffer, location)| {
16561                                buffer
16562                                    .read(cx)
16563                                    .text_for_range(location.clone())
16564                                    .collect::<String>()
16565                            })
16566                            .filter(|text| !text.contains('\n'))
16567                            .unique()
16568                            .take(3)
16569                            .join(", ");
16570                        if target.is_empty() {
16571                            tab_kind.to_owned()
16572                        } else {
16573                            format!("{tab_kind} for {target}")
16574                        }
16575                    })
16576                    .context("buffer title")?;
16577
16578                let opened = workspace
16579                    .update_in(cx, |workspace, window, cx| {
16580                        Self::open_locations_in_multibuffer(
16581                            workspace,
16582                            locations,
16583                            title,
16584                            split,
16585                            MultibufferSelectionMode::First,
16586                            window,
16587                            cx,
16588                        )
16589                    })
16590                    .is_ok();
16591
16592                anyhow::Ok(Navigated::from_bool(opened))
16593            } else if num_locations == 0 {
16594                // If there is one url or file, open it directly
16595                match first_url_or_file {
16596                    Some(Either::Left(url)) => {
16597                        cx.update(|_, cx| cx.open_url(&url))?;
16598                        Ok(Navigated::Yes)
16599                    }
16600                    Some(Either::Right(path)) => {
16601                        let Some(workspace) = workspace else {
16602                            return Ok(Navigated::No);
16603                        };
16604
16605                        workspace
16606                            .update_in(cx, |workspace, window, cx| {
16607                                workspace.open_resolved_path(path, window, cx)
16608                            })?
16609                            .await?;
16610                        Ok(Navigated::Yes)
16611                    }
16612                    None => Ok(Navigated::No),
16613                }
16614            } else {
16615                let Some(workspace) = workspace else {
16616                    return Ok(Navigated::No);
16617                };
16618
16619                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16620                let target_range = target_ranges.first().unwrap().clone();
16621
16622                editor.update_in(cx, |editor, window, cx| {
16623                    let range = target_range.to_point(target_buffer.read(cx));
16624                    let range = editor.range_for_match(&range);
16625                    let range = collapse_multiline_range(range);
16626
16627                    if !split
16628                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16629                    {
16630                        editor.go_to_singleton_buffer_range(range, window, cx);
16631                    } else {
16632                        let pane = workspace.read(cx).active_pane().clone();
16633                        window.defer(cx, move |window, cx| {
16634                            let target_editor: Entity<Self> =
16635                                workspace.update(cx, |workspace, cx| {
16636                                    let pane = if split {
16637                                        workspace.adjacent_pane(window, cx)
16638                                    } else {
16639                                        workspace.active_pane().clone()
16640                                    };
16641
16642                                    workspace.open_project_item(
16643                                        pane,
16644                                        target_buffer.clone(),
16645                                        true,
16646                                        true,
16647                                        window,
16648                                        cx,
16649                                    )
16650                                });
16651                            target_editor.update(cx, |target_editor, cx| {
16652                                // When selecting a definition in a different buffer, disable the nav history
16653                                // to avoid creating a history entry at the previous cursor location.
16654                                pane.update(cx, |pane, _| pane.disable_history());
16655                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16656                                pane.update(cx, |pane, _| pane.enable_history());
16657                            });
16658                        });
16659                    }
16660                    Navigated::Yes
16661                })
16662            }
16663        })
16664    }
16665
16666    fn compute_target_location(
16667        &self,
16668        lsp_location: lsp::Location,
16669        server_id: LanguageServerId,
16670        window: &mut Window,
16671        cx: &mut Context<Self>,
16672    ) -> Task<anyhow::Result<Option<Location>>> {
16673        let Some(project) = self.project.clone() else {
16674            return Task::ready(Ok(None));
16675        };
16676
16677        cx.spawn_in(window, async move |editor, cx| {
16678            let location_task = editor.update(cx, |_, cx| {
16679                project.update(cx, |project, cx| {
16680                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16681                })
16682            })?;
16683            let location = Some({
16684                let target_buffer_handle = location_task.await.context("open local buffer")?;
16685                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16686                    let target_start = target_buffer
16687                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16688                    let target_end = target_buffer
16689                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16690                    target_buffer.anchor_after(target_start)
16691                        ..target_buffer.anchor_before(target_end)
16692                })?;
16693                Location {
16694                    buffer: target_buffer_handle,
16695                    range,
16696                }
16697            });
16698            Ok(location)
16699        })
16700    }
16701
16702    fn go_to_next_reference(
16703        &mut self,
16704        _: &GoToNextReference,
16705        window: &mut Window,
16706        cx: &mut Context<Self>,
16707    ) {
16708        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16709        if let Some(task) = task {
16710            task.detach();
16711        };
16712    }
16713
16714    fn go_to_prev_reference(
16715        &mut self,
16716        _: &GoToPreviousReference,
16717        window: &mut Window,
16718        cx: &mut Context<Self>,
16719    ) {
16720        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16721        if let Some(task) = task {
16722            task.detach();
16723        };
16724    }
16725
16726    pub fn go_to_reference_before_or_after_position(
16727        &mut self,
16728        direction: Direction,
16729        count: usize,
16730        window: &mut Window,
16731        cx: &mut Context<Self>,
16732    ) -> Option<Task<Result<()>>> {
16733        let selection = self.selections.newest_anchor();
16734        let head = selection.head();
16735
16736        let multi_buffer = self.buffer.read(cx);
16737
16738        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
16739        let workspace = self.workspace()?;
16740        let project = workspace.read(cx).project().clone();
16741        let references =
16742            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
16743        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
16744            let Some(locations) = references.await? else {
16745                return Ok(());
16746            };
16747
16748            if locations.is_empty() {
16749                // totally normal - the cursor may be on something which is not
16750                // a symbol (e.g. a keyword)
16751                log::info!("no references found under cursor");
16752                return Ok(());
16753            }
16754
16755            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
16756
16757            let multi_buffer_snapshot =
16758                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
16759
16760            let (locations, current_location_index) =
16761                multi_buffer.update(cx, |multi_buffer, cx| {
16762                    let mut locations = locations
16763                        .into_iter()
16764                        .filter_map(|loc| {
16765                            let start = multi_buffer.buffer_anchor_to_anchor(
16766                                &loc.buffer,
16767                                loc.range.start,
16768                                cx,
16769                            )?;
16770                            let end = multi_buffer.buffer_anchor_to_anchor(
16771                                &loc.buffer,
16772                                loc.range.end,
16773                                cx,
16774                            )?;
16775                            Some(start..end)
16776                        })
16777                        .collect::<Vec<_>>();
16778
16779                    // There is an O(n) implementation, but given this list will be
16780                    // small (usually <100 items), the extra O(log(n)) factor isn't
16781                    // worth the (surprisingly large amount of) extra complexity.
16782                    locations
16783                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
16784
16785                    let head_offset = head.to_offset(&multi_buffer_snapshot);
16786
16787                    let current_location_index = locations.iter().position(|loc| {
16788                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
16789                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
16790                    });
16791
16792                    (locations, current_location_index)
16793                })?;
16794
16795            let Some(current_location_index) = current_location_index else {
16796                // This indicates something has gone wrong, because we already
16797                // handle the "no references" case above
16798                log::error!(
16799                    "failed to find current reference under cursor. Total references: {}",
16800                    locations.len()
16801                );
16802                return Ok(());
16803            };
16804
16805            let destination_location_index = match direction {
16806                Direction::Next => (current_location_index + count) % locations.len(),
16807                Direction::Prev => {
16808                    (current_location_index + locations.len() - count % locations.len())
16809                        % locations.len()
16810                }
16811            };
16812
16813            // TODO(cameron): is this needed?
16814            // the thinking is to avoid "jumping to the current location" (avoid
16815            // polluting "jumplist" in vim terms)
16816            if current_location_index == destination_location_index {
16817                return Ok(());
16818            }
16819
16820            let Range { start, end } = locations[destination_location_index];
16821
16822            editor.update_in(cx, |editor, window, cx| {
16823                let effects = SelectionEffects::default();
16824
16825                editor.unfold_ranges(&[start..end], false, false, cx);
16826                editor.change_selections(effects, window, cx, |s| {
16827                    s.select_ranges([start..start]);
16828                });
16829            })?;
16830
16831            Ok(())
16832        }))
16833    }
16834
16835    pub fn find_all_references(
16836        &mut self,
16837        _: &FindAllReferences,
16838        window: &mut Window,
16839        cx: &mut Context<Self>,
16840    ) -> Option<Task<Result<Navigated>>> {
16841        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16842        let multi_buffer = self.buffer.read(cx);
16843        let head = selection.head();
16844
16845        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16846        let head_anchor = multi_buffer_snapshot.anchor_at(
16847            head,
16848            if head < selection.tail() {
16849                Bias::Right
16850            } else {
16851                Bias::Left
16852            },
16853        );
16854
16855        match self
16856            .find_all_references_task_sources
16857            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16858        {
16859            Ok(_) => {
16860                log::info!(
16861                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16862                );
16863                return None;
16864            }
16865            Err(i) => {
16866                self.find_all_references_task_sources.insert(i, head_anchor);
16867            }
16868        }
16869
16870        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16871        let workspace = self.workspace()?;
16872        let project = workspace.read(cx).project().clone();
16873        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16874        Some(cx.spawn_in(window, async move |editor, cx| {
16875            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16876                if let Ok(i) = editor
16877                    .find_all_references_task_sources
16878                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16879                {
16880                    editor.find_all_references_task_sources.remove(i);
16881                }
16882            });
16883
16884            let Some(locations) = references.await? else {
16885                return anyhow::Ok(Navigated::No);
16886            };
16887            let mut locations = cx.update(|_, cx| {
16888                locations
16889                    .into_iter()
16890                    .map(|location| {
16891                        let buffer = location.buffer.read(cx);
16892                        (location.buffer, location.range.to_point(buffer))
16893                    })
16894                    .into_group_map()
16895            })?;
16896            if locations.is_empty() {
16897                return anyhow::Ok(Navigated::No);
16898            }
16899            for ranges in locations.values_mut() {
16900                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16901                ranges.dedup();
16902            }
16903
16904            workspace.update_in(cx, |workspace, window, cx| {
16905                let target = locations
16906                    .iter()
16907                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16908                    .map(|(buffer, location)| {
16909                        buffer
16910                            .read(cx)
16911                            .text_for_range(location.clone())
16912                            .collect::<String>()
16913                    })
16914                    .filter(|text| !text.contains('\n'))
16915                    .unique()
16916                    .take(3)
16917                    .join(", ");
16918                let title = if target.is_empty() {
16919                    "References".to_owned()
16920                } else {
16921                    format!("References to {target}")
16922                };
16923                Self::open_locations_in_multibuffer(
16924                    workspace,
16925                    locations,
16926                    title,
16927                    false,
16928                    MultibufferSelectionMode::First,
16929                    window,
16930                    cx,
16931                );
16932                Navigated::Yes
16933            })
16934        }))
16935    }
16936
16937    /// Opens a multibuffer with the given project locations in it
16938    pub fn open_locations_in_multibuffer(
16939        workspace: &mut Workspace,
16940        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16941        title: String,
16942        split: bool,
16943        multibuffer_selection_mode: MultibufferSelectionMode,
16944        window: &mut Window,
16945        cx: &mut Context<Workspace>,
16946    ) {
16947        if locations.is_empty() {
16948            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16949            return;
16950        }
16951
16952        let capability = workspace.project().read(cx).capability();
16953        let mut ranges = <Vec<Range<Anchor>>>::new();
16954
16955        // a key to find existing multibuffer editors with the same set of locations
16956        // to prevent us from opening more and more multibuffer tabs for searches and the like
16957        let mut key = (title.clone(), vec![]);
16958        let excerpt_buffer = cx.new(|cx| {
16959            let key = &mut key.1;
16960            let mut multibuffer = MultiBuffer::new(capability);
16961            for (buffer, mut ranges_for_buffer) in locations {
16962                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16963                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16964                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16965                    PathKey::for_buffer(&buffer, cx),
16966                    buffer.clone(),
16967                    ranges_for_buffer,
16968                    multibuffer_context_lines(cx),
16969                    cx,
16970                );
16971                ranges.extend(new_ranges)
16972            }
16973
16974            multibuffer.with_title(title)
16975        });
16976        let existing = workspace.active_pane().update(cx, |pane, cx| {
16977            pane.items()
16978                .filter_map(|item| item.downcast::<Editor>())
16979                .find(|editor| {
16980                    editor
16981                        .read(cx)
16982                        .lookup_key
16983                        .as_ref()
16984                        .and_then(|it| {
16985                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16986                        })
16987                        .is_some_and(|it| *it == key)
16988                })
16989        });
16990        let editor = existing.unwrap_or_else(|| {
16991            cx.new(|cx| {
16992                let mut editor = Editor::for_multibuffer(
16993                    excerpt_buffer,
16994                    Some(workspace.project().clone()),
16995                    window,
16996                    cx,
16997                );
16998                editor.lookup_key = Some(Box::new(key));
16999                editor
17000            })
17001        });
17002        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17003            MultibufferSelectionMode::First => {
17004                if let Some(first_range) = ranges.first() {
17005                    editor.change_selections(
17006                        SelectionEffects::no_scroll(),
17007                        window,
17008                        cx,
17009                        |selections| {
17010                            selections.clear_disjoint();
17011                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17012                        },
17013                    );
17014                }
17015                editor.highlight_background::<Self>(
17016                    &ranges,
17017                    |theme| theme.colors().editor_highlighted_line_background,
17018                    cx,
17019                );
17020            }
17021            MultibufferSelectionMode::All => {
17022                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17023                    selections.clear_disjoint();
17024                    selections.select_anchor_ranges(ranges);
17025                });
17026            }
17027        });
17028
17029        let item = Box::new(editor);
17030        let item_id = item.item_id();
17031
17032        if split {
17033            let pane = workspace.adjacent_pane(window, cx);
17034            workspace.add_item(pane, item, None, true, true, window, cx);
17035        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17036            let (preview_item_id, preview_item_idx) =
17037                workspace.active_pane().read_with(cx, |pane, _| {
17038                    (pane.preview_item_id(), pane.preview_item_idx())
17039                });
17040
17041            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17042
17043            if let Some(preview_item_id) = preview_item_id {
17044                workspace.active_pane().update(cx, |pane, cx| {
17045                    pane.remove_item(preview_item_id, false, false, window, cx);
17046                });
17047            }
17048        } else {
17049            workspace.add_item_to_active_pane(item, None, true, window, cx);
17050        }
17051        workspace.active_pane().update(cx, |pane, cx| {
17052            pane.set_preview_item_id(Some(item_id), cx);
17053        });
17054    }
17055
17056    pub fn rename(
17057        &mut self,
17058        _: &Rename,
17059        window: &mut Window,
17060        cx: &mut Context<Self>,
17061    ) -> Option<Task<Result<()>>> {
17062        use language::ToOffset as _;
17063
17064        let provider = self.semantics_provider.clone()?;
17065        let selection = self.selections.newest_anchor().clone();
17066        let (cursor_buffer, cursor_buffer_position) = self
17067            .buffer
17068            .read(cx)
17069            .text_anchor_for_position(selection.head(), cx)?;
17070        let (tail_buffer, cursor_buffer_position_end) = self
17071            .buffer
17072            .read(cx)
17073            .text_anchor_for_position(selection.tail(), cx)?;
17074        if tail_buffer != cursor_buffer {
17075            return None;
17076        }
17077
17078        let snapshot = cursor_buffer.read(cx).snapshot();
17079        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17080        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17081        let prepare_rename = provider
17082            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17083            .unwrap_or_else(|| Task::ready(Ok(None)));
17084        drop(snapshot);
17085
17086        Some(cx.spawn_in(window, async move |this, cx| {
17087            let rename_range = if let Some(range) = prepare_rename.await? {
17088                Some(range)
17089            } else {
17090                this.update(cx, |this, cx| {
17091                    let buffer = this.buffer.read(cx).snapshot(cx);
17092                    let mut buffer_highlights = this
17093                        .document_highlights_for_position(selection.head(), &buffer)
17094                        .filter(|highlight| {
17095                            highlight.start.excerpt_id == selection.head().excerpt_id
17096                                && highlight.end.excerpt_id == selection.head().excerpt_id
17097                        });
17098                    buffer_highlights
17099                        .next()
17100                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17101                })?
17102            };
17103            if let Some(rename_range) = rename_range {
17104                this.update_in(cx, |this, window, cx| {
17105                    let snapshot = cursor_buffer.read(cx).snapshot();
17106                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17107                    let cursor_offset_in_rename_range =
17108                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17109                    let cursor_offset_in_rename_range_end =
17110                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17111
17112                    this.take_rename(false, window, cx);
17113                    let buffer = this.buffer.read(cx).read(cx);
17114                    let cursor_offset = selection.head().to_offset(&buffer);
17115                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17116                    let rename_end = rename_start + rename_buffer_range.len();
17117                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17118                    let mut old_highlight_id = None;
17119                    let old_name: Arc<str> = buffer
17120                        .chunks(rename_start..rename_end, true)
17121                        .map(|chunk| {
17122                            if old_highlight_id.is_none() {
17123                                old_highlight_id = chunk.syntax_highlight_id;
17124                            }
17125                            chunk.text
17126                        })
17127                        .collect::<String>()
17128                        .into();
17129
17130                    drop(buffer);
17131
17132                    // Position the selection in the rename editor so that it matches the current selection.
17133                    this.show_local_selections = false;
17134                    let rename_editor = cx.new(|cx| {
17135                        let mut editor = Editor::single_line(window, cx);
17136                        editor.buffer.update(cx, |buffer, cx| {
17137                            buffer.edit([(0..0, old_name.clone())], None, cx)
17138                        });
17139                        let rename_selection_range = match cursor_offset_in_rename_range
17140                            .cmp(&cursor_offset_in_rename_range_end)
17141                        {
17142                            Ordering::Equal => {
17143                                editor.select_all(&SelectAll, window, cx);
17144                                return editor;
17145                            }
17146                            Ordering::Less => {
17147                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17148                            }
17149                            Ordering::Greater => {
17150                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17151                            }
17152                        };
17153                        if rename_selection_range.end > old_name.len() {
17154                            editor.select_all(&SelectAll, window, cx);
17155                        } else {
17156                            editor.change_selections(Default::default(), window, cx, |s| {
17157                                s.select_ranges([rename_selection_range]);
17158                            });
17159                        }
17160                        editor
17161                    });
17162                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17163                        if e == &EditorEvent::Focused {
17164                            cx.emit(EditorEvent::FocusedIn)
17165                        }
17166                    })
17167                    .detach();
17168
17169                    let write_highlights =
17170                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17171                    let read_highlights =
17172                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17173                    let ranges = write_highlights
17174                        .iter()
17175                        .flat_map(|(_, ranges)| ranges.iter())
17176                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17177                        .cloned()
17178                        .collect();
17179
17180                    this.highlight_text::<Rename>(
17181                        ranges,
17182                        HighlightStyle {
17183                            fade_out: Some(0.6),
17184                            ..Default::default()
17185                        },
17186                        cx,
17187                    );
17188                    let rename_focus_handle = rename_editor.focus_handle(cx);
17189                    window.focus(&rename_focus_handle);
17190                    let block_id = this.insert_blocks(
17191                        [BlockProperties {
17192                            style: BlockStyle::Flex,
17193                            placement: BlockPlacement::Below(range.start),
17194                            height: Some(1),
17195                            render: Arc::new({
17196                                let rename_editor = rename_editor.clone();
17197                                move |cx: &mut BlockContext| {
17198                                    let mut text_style = cx.editor_style.text.clone();
17199                                    if let Some(highlight_style) = old_highlight_id
17200                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17201                                    {
17202                                        text_style = text_style.highlight(highlight_style);
17203                                    }
17204                                    div()
17205                                        .block_mouse_except_scroll()
17206                                        .pl(cx.anchor_x)
17207                                        .child(EditorElement::new(
17208                                            &rename_editor,
17209                                            EditorStyle {
17210                                                background: cx.theme().system().transparent,
17211                                                local_player: cx.editor_style.local_player,
17212                                                text: text_style,
17213                                                scrollbar_width: cx.editor_style.scrollbar_width,
17214                                                syntax: cx.editor_style.syntax.clone(),
17215                                                status: cx.editor_style.status.clone(),
17216                                                inlay_hints_style: HighlightStyle {
17217                                                    font_weight: Some(FontWeight::BOLD),
17218                                                    ..make_inlay_hints_style(cx.app)
17219                                                },
17220                                                edit_prediction_styles: make_suggestion_styles(
17221                                                    cx.app,
17222                                                ),
17223                                                ..EditorStyle::default()
17224                                            },
17225                                        ))
17226                                        .into_any_element()
17227                                }
17228                            }),
17229                            priority: 0,
17230                        }],
17231                        Some(Autoscroll::fit()),
17232                        cx,
17233                    )[0];
17234                    this.pending_rename = Some(RenameState {
17235                        range,
17236                        old_name,
17237                        editor: rename_editor,
17238                        block_id,
17239                    });
17240                })?;
17241            }
17242
17243            Ok(())
17244        }))
17245    }
17246
17247    pub fn confirm_rename(
17248        &mut self,
17249        _: &ConfirmRename,
17250        window: &mut Window,
17251        cx: &mut Context<Self>,
17252    ) -> Option<Task<Result<()>>> {
17253        let rename = self.take_rename(false, window, cx)?;
17254        let workspace = self.workspace()?.downgrade();
17255        let (buffer, start) = self
17256            .buffer
17257            .read(cx)
17258            .text_anchor_for_position(rename.range.start, cx)?;
17259        let (end_buffer, _) = self
17260            .buffer
17261            .read(cx)
17262            .text_anchor_for_position(rename.range.end, cx)?;
17263        if buffer != end_buffer {
17264            return None;
17265        }
17266
17267        let old_name = rename.old_name;
17268        let new_name = rename.editor.read(cx).text(cx);
17269
17270        let rename = self.semantics_provider.as_ref()?.perform_rename(
17271            &buffer,
17272            start,
17273            new_name.clone(),
17274            cx,
17275        )?;
17276
17277        Some(cx.spawn_in(window, async move |editor, cx| {
17278            let project_transaction = rename.await?;
17279            Self::open_project_transaction(
17280                &editor,
17281                workspace,
17282                project_transaction,
17283                format!("Rename: {} → {}", old_name, new_name),
17284                cx,
17285            )
17286            .await?;
17287
17288            editor.update(cx, |editor, cx| {
17289                editor.refresh_document_highlights(cx);
17290            })?;
17291            Ok(())
17292        }))
17293    }
17294
17295    fn take_rename(
17296        &mut self,
17297        moving_cursor: bool,
17298        window: &mut Window,
17299        cx: &mut Context<Self>,
17300    ) -> Option<RenameState> {
17301        let rename = self.pending_rename.take()?;
17302        if rename.editor.focus_handle(cx).is_focused(window) {
17303            window.focus(&self.focus_handle);
17304        }
17305
17306        self.remove_blocks(
17307            [rename.block_id].into_iter().collect(),
17308            Some(Autoscroll::fit()),
17309            cx,
17310        );
17311        self.clear_highlights::<Rename>(cx);
17312        self.show_local_selections = true;
17313
17314        if moving_cursor {
17315            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17316                editor
17317                    .selections
17318                    .newest::<usize>(&editor.display_snapshot(cx))
17319                    .head()
17320            });
17321
17322            // Update the selection to match the position of the selection inside
17323            // the rename editor.
17324            let snapshot = self.buffer.read(cx).read(cx);
17325            let rename_range = rename.range.to_offset(&snapshot);
17326            let cursor_in_editor = snapshot
17327                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17328                .min(rename_range.end);
17329            drop(snapshot);
17330
17331            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17332                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17333            });
17334        } else {
17335            self.refresh_document_highlights(cx);
17336        }
17337
17338        Some(rename)
17339    }
17340
17341    pub fn pending_rename(&self) -> Option<&RenameState> {
17342        self.pending_rename.as_ref()
17343    }
17344
17345    fn format(
17346        &mut self,
17347        _: &Format,
17348        window: &mut Window,
17349        cx: &mut Context<Self>,
17350    ) -> Option<Task<Result<()>>> {
17351        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17352
17353        let project = match &self.project {
17354            Some(project) => project.clone(),
17355            None => return None,
17356        };
17357
17358        Some(self.perform_format(
17359            project,
17360            FormatTrigger::Manual,
17361            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17362            window,
17363            cx,
17364        ))
17365    }
17366
17367    fn format_selections(
17368        &mut self,
17369        _: &FormatSelections,
17370        window: &mut Window,
17371        cx: &mut Context<Self>,
17372    ) -> Option<Task<Result<()>>> {
17373        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17374
17375        let project = match &self.project {
17376            Some(project) => project.clone(),
17377            None => return None,
17378        };
17379
17380        let ranges = self
17381            .selections
17382            .all_adjusted(&self.display_snapshot(cx))
17383            .into_iter()
17384            .map(|selection| selection.range())
17385            .collect_vec();
17386
17387        Some(self.perform_format(
17388            project,
17389            FormatTrigger::Manual,
17390            FormatTarget::Ranges(ranges),
17391            window,
17392            cx,
17393        ))
17394    }
17395
17396    fn perform_format(
17397        &mut self,
17398        project: Entity<Project>,
17399        trigger: FormatTrigger,
17400        target: FormatTarget,
17401        window: &mut Window,
17402        cx: &mut Context<Self>,
17403    ) -> Task<Result<()>> {
17404        let buffer = self.buffer.clone();
17405        let (buffers, target) = match target {
17406            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17407            FormatTarget::Ranges(selection_ranges) => {
17408                let multi_buffer = buffer.read(cx);
17409                let snapshot = multi_buffer.read(cx);
17410                let mut buffers = HashSet::default();
17411                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17412                    BTreeMap::new();
17413                for selection_range in selection_ranges {
17414                    for (buffer, buffer_range, _) in
17415                        snapshot.range_to_buffer_ranges(selection_range)
17416                    {
17417                        let buffer_id = buffer.remote_id();
17418                        let start = buffer.anchor_before(buffer_range.start);
17419                        let end = buffer.anchor_after(buffer_range.end);
17420                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17421                        buffer_id_to_ranges
17422                            .entry(buffer_id)
17423                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17424                            .or_insert_with(|| vec![start..end]);
17425                    }
17426                }
17427                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17428            }
17429        };
17430
17431        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17432        let selections_prev = transaction_id_prev
17433            .and_then(|transaction_id_prev| {
17434                // default to selections as they were after the last edit, if we have them,
17435                // instead of how they are now.
17436                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17437                // will take you back to where you made the last edit, instead of staying where you scrolled
17438                self.selection_history
17439                    .transaction(transaction_id_prev)
17440                    .map(|t| t.0.clone())
17441            })
17442            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17443
17444        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17445        let format = project.update(cx, |project, cx| {
17446            project.format(buffers, target, true, trigger, cx)
17447        });
17448
17449        cx.spawn_in(window, async move |editor, cx| {
17450            let transaction = futures::select_biased! {
17451                transaction = format.log_err().fuse() => transaction,
17452                () = timeout => {
17453                    log::warn!("timed out waiting for formatting");
17454                    None
17455                }
17456            };
17457
17458            buffer
17459                .update(cx, |buffer, cx| {
17460                    if let Some(transaction) = transaction
17461                        && !buffer.is_singleton()
17462                    {
17463                        buffer.push_transaction(&transaction.0, cx);
17464                    }
17465                    cx.notify();
17466                })
17467                .ok();
17468
17469            if let Some(transaction_id_now) =
17470                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17471            {
17472                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17473                if has_new_transaction {
17474                    _ = editor.update(cx, |editor, _| {
17475                        editor
17476                            .selection_history
17477                            .insert_transaction(transaction_id_now, selections_prev);
17478                    });
17479                }
17480            }
17481
17482            Ok(())
17483        })
17484    }
17485
17486    fn organize_imports(
17487        &mut self,
17488        _: &OrganizeImports,
17489        window: &mut Window,
17490        cx: &mut Context<Self>,
17491    ) -> Option<Task<Result<()>>> {
17492        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17493        let project = match &self.project {
17494            Some(project) => project.clone(),
17495            None => return None,
17496        };
17497        Some(self.perform_code_action_kind(
17498            project,
17499            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17500            window,
17501            cx,
17502        ))
17503    }
17504
17505    fn perform_code_action_kind(
17506        &mut self,
17507        project: Entity<Project>,
17508        kind: CodeActionKind,
17509        window: &mut Window,
17510        cx: &mut Context<Self>,
17511    ) -> Task<Result<()>> {
17512        let buffer = self.buffer.clone();
17513        let buffers = buffer.read(cx).all_buffers();
17514        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17515        let apply_action = project.update(cx, |project, cx| {
17516            project.apply_code_action_kind(buffers, kind, true, cx)
17517        });
17518        cx.spawn_in(window, async move |_, cx| {
17519            let transaction = futures::select_biased! {
17520                () = timeout => {
17521                    log::warn!("timed out waiting for executing code action");
17522                    None
17523                }
17524                transaction = apply_action.log_err().fuse() => transaction,
17525            };
17526            buffer
17527                .update(cx, |buffer, cx| {
17528                    // check if we need this
17529                    if let Some(transaction) = transaction
17530                        && !buffer.is_singleton()
17531                    {
17532                        buffer.push_transaction(&transaction.0, cx);
17533                    }
17534                    cx.notify();
17535                })
17536                .ok();
17537            Ok(())
17538        })
17539    }
17540
17541    pub fn restart_language_server(
17542        &mut self,
17543        _: &RestartLanguageServer,
17544        _: &mut Window,
17545        cx: &mut Context<Self>,
17546    ) {
17547        if let Some(project) = self.project.clone() {
17548            self.buffer.update(cx, |multi_buffer, cx| {
17549                project.update(cx, |project, cx| {
17550                    project.restart_language_servers_for_buffers(
17551                        multi_buffer.all_buffers().into_iter().collect(),
17552                        HashSet::default(),
17553                        cx,
17554                    );
17555                });
17556            })
17557        }
17558    }
17559
17560    pub fn stop_language_server(
17561        &mut self,
17562        _: &StopLanguageServer,
17563        _: &mut Window,
17564        cx: &mut Context<Self>,
17565    ) {
17566        if let Some(project) = self.project.clone() {
17567            self.buffer.update(cx, |multi_buffer, cx| {
17568                project.update(cx, |project, cx| {
17569                    project.stop_language_servers_for_buffers(
17570                        multi_buffer.all_buffers().into_iter().collect(),
17571                        HashSet::default(),
17572                        cx,
17573                    );
17574                });
17575            });
17576            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17577        }
17578    }
17579
17580    fn cancel_language_server_work(
17581        workspace: &mut Workspace,
17582        _: &actions::CancelLanguageServerWork,
17583        _: &mut Window,
17584        cx: &mut Context<Workspace>,
17585    ) {
17586        let project = workspace.project();
17587        let buffers = workspace
17588            .active_item(cx)
17589            .and_then(|item| item.act_as::<Editor>(cx))
17590            .map_or(HashSet::default(), |editor| {
17591                editor.read(cx).buffer.read(cx).all_buffers()
17592            });
17593        project.update(cx, |project, cx| {
17594            project.cancel_language_server_work_for_buffers(buffers, cx);
17595        });
17596    }
17597
17598    fn show_character_palette(
17599        &mut self,
17600        _: &ShowCharacterPalette,
17601        window: &mut Window,
17602        _: &mut Context<Self>,
17603    ) {
17604        window.show_character_palette();
17605    }
17606
17607    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17608        if !self.diagnostics_enabled() {
17609            return;
17610        }
17611
17612        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17613            let buffer = self.buffer.read(cx).snapshot(cx);
17614            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17615            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17616            let is_valid = buffer
17617                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17618                .any(|entry| {
17619                    entry.diagnostic.is_primary
17620                        && !entry.range.is_empty()
17621                        && entry.range.start == primary_range_start
17622                        && entry.diagnostic.message == active_diagnostics.active_message
17623                });
17624
17625            if !is_valid {
17626                self.dismiss_diagnostics(cx);
17627            }
17628        }
17629    }
17630
17631    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17632        match &self.active_diagnostics {
17633            ActiveDiagnostic::Group(group) => Some(group),
17634            _ => None,
17635        }
17636    }
17637
17638    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17639        if !self.diagnostics_enabled() {
17640            return;
17641        }
17642        self.dismiss_diagnostics(cx);
17643        self.active_diagnostics = ActiveDiagnostic::All;
17644    }
17645
17646    fn activate_diagnostics(
17647        &mut self,
17648        buffer_id: BufferId,
17649        diagnostic: DiagnosticEntryRef<'_, usize>,
17650        window: &mut Window,
17651        cx: &mut Context<Self>,
17652    ) {
17653        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17654            return;
17655        }
17656        self.dismiss_diagnostics(cx);
17657        let snapshot = self.snapshot(window, cx);
17658        let buffer = self.buffer.read(cx).snapshot(cx);
17659        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17660            return;
17661        };
17662
17663        let diagnostic_group = buffer
17664            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17665            .collect::<Vec<_>>();
17666
17667        let blocks =
17668            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17669
17670        let blocks = self.display_map.update(cx, |display_map, cx| {
17671            display_map.insert_blocks(blocks, cx).into_iter().collect()
17672        });
17673        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17674            active_range: buffer.anchor_before(diagnostic.range.start)
17675                ..buffer.anchor_after(diagnostic.range.end),
17676            active_message: diagnostic.diagnostic.message.clone(),
17677            group_id: diagnostic.diagnostic.group_id,
17678            blocks,
17679        });
17680        cx.notify();
17681    }
17682
17683    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17684        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17685            return;
17686        };
17687
17688        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17689        if let ActiveDiagnostic::Group(group) = prev {
17690            self.display_map.update(cx, |display_map, cx| {
17691                display_map.remove_blocks(group.blocks, cx);
17692            });
17693            cx.notify();
17694        }
17695    }
17696
17697    /// Disable inline diagnostics rendering for this editor.
17698    pub fn disable_inline_diagnostics(&mut self) {
17699        self.inline_diagnostics_enabled = false;
17700        self.inline_diagnostics_update = Task::ready(());
17701        self.inline_diagnostics.clear();
17702    }
17703
17704    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17705        self.diagnostics_enabled = false;
17706        self.dismiss_diagnostics(cx);
17707        self.inline_diagnostics_update = Task::ready(());
17708        self.inline_diagnostics.clear();
17709    }
17710
17711    pub fn disable_word_completions(&mut self) {
17712        self.word_completions_enabled = false;
17713    }
17714
17715    pub fn diagnostics_enabled(&self) -> bool {
17716        self.diagnostics_enabled && self.mode.is_full()
17717    }
17718
17719    pub fn inline_diagnostics_enabled(&self) -> bool {
17720        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17721    }
17722
17723    pub fn show_inline_diagnostics(&self) -> bool {
17724        self.show_inline_diagnostics
17725    }
17726
17727    pub fn toggle_inline_diagnostics(
17728        &mut self,
17729        _: &ToggleInlineDiagnostics,
17730        window: &mut Window,
17731        cx: &mut Context<Editor>,
17732    ) {
17733        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17734        self.refresh_inline_diagnostics(false, window, cx);
17735    }
17736
17737    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17738        self.diagnostics_max_severity = severity;
17739        self.display_map.update(cx, |display_map, _| {
17740            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17741        });
17742    }
17743
17744    pub fn toggle_diagnostics(
17745        &mut self,
17746        _: &ToggleDiagnostics,
17747        window: &mut Window,
17748        cx: &mut Context<Editor>,
17749    ) {
17750        if !self.diagnostics_enabled() {
17751            return;
17752        }
17753
17754        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17755            EditorSettings::get_global(cx)
17756                .diagnostics_max_severity
17757                .filter(|severity| severity != &DiagnosticSeverity::Off)
17758                .unwrap_or(DiagnosticSeverity::Hint)
17759        } else {
17760            DiagnosticSeverity::Off
17761        };
17762        self.set_max_diagnostics_severity(new_severity, cx);
17763        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17764            self.active_diagnostics = ActiveDiagnostic::None;
17765            self.inline_diagnostics_update = Task::ready(());
17766            self.inline_diagnostics.clear();
17767        } else {
17768            self.refresh_inline_diagnostics(false, window, cx);
17769        }
17770
17771        cx.notify();
17772    }
17773
17774    pub fn toggle_minimap(
17775        &mut self,
17776        _: &ToggleMinimap,
17777        window: &mut Window,
17778        cx: &mut Context<Editor>,
17779    ) {
17780        if self.supports_minimap(cx) {
17781            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17782        }
17783    }
17784
17785    fn refresh_inline_diagnostics(
17786        &mut self,
17787        debounce: bool,
17788        window: &mut Window,
17789        cx: &mut Context<Self>,
17790    ) {
17791        let max_severity = ProjectSettings::get_global(cx)
17792            .diagnostics
17793            .inline
17794            .max_severity
17795            .unwrap_or(self.diagnostics_max_severity);
17796
17797        if !self.inline_diagnostics_enabled()
17798            || !self.show_inline_diagnostics
17799            || max_severity == DiagnosticSeverity::Off
17800        {
17801            self.inline_diagnostics_update = Task::ready(());
17802            self.inline_diagnostics.clear();
17803            return;
17804        }
17805
17806        let debounce_ms = ProjectSettings::get_global(cx)
17807            .diagnostics
17808            .inline
17809            .update_debounce_ms;
17810        let debounce = if debounce && debounce_ms > 0 {
17811            Some(Duration::from_millis(debounce_ms))
17812        } else {
17813            None
17814        };
17815        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17816            if let Some(debounce) = debounce {
17817                cx.background_executor().timer(debounce).await;
17818            }
17819            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17820                editor
17821                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17822                    .ok()
17823            }) else {
17824                return;
17825            };
17826
17827            let new_inline_diagnostics = cx
17828                .background_spawn(async move {
17829                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17830                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17831                        let message = diagnostic_entry
17832                            .diagnostic
17833                            .message
17834                            .split_once('\n')
17835                            .map(|(line, _)| line)
17836                            .map(SharedString::new)
17837                            .unwrap_or_else(|| {
17838                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17839                            });
17840                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17841                        let (Ok(i) | Err(i)) = inline_diagnostics
17842                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17843                        inline_diagnostics.insert(
17844                            i,
17845                            (
17846                                start_anchor,
17847                                InlineDiagnostic {
17848                                    message,
17849                                    group_id: diagnostic_entry.diagnostic.group_id,
17850                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17851                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17852                                    severity: diagnostic_entry.diagnostic.severity,
17853                                },
17854                            ),
17855                        );
17856                    }
17857                    inline_diagnostics
17858                })
17859                .await;
17860
17861            editor
17862                .update(cx, |editor, cx| {
17863                    editor.inline_diagnostics = new_inline_diagnostics;
17864                    cx.notify();
17865                })
17866                .ok();
17867        });
17868    }
17869
17870    fn pull_diagnostics(
17871        &mut self,
17872        buffer_id: Option<BufferId>,
17873        window: &Window,
17874        cx: &mut Context<Self>,
17875    ) -> Option<()> {
17876        if self.ignore_lsp_data() {
17877            return None;
17878        }
17879        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17880            .diagnostics
17881            .lsp_pull_diagnostics;
17882        if !pull_diagnostics_settings.enabled {
17883            return None;
17884        }
17885        let project = self.project()?.downgrade();
17886        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17887        let mut buffers = self.buffer.read(cx).all_buffers();
17888        buffers.retain(|buffer| {
17889            let buffer_id_to_retain = buffer.read(cx).remote_id();
17890            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17891                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17892        });
17893        if buffers.is_empty() {
17894            self.pull_diagnostics_task = Task::ready(());
17895            return None;
17896        }
17897
17898        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17899            cx.background_executor().timer(debounce).await;
17900
17901            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17902                buffers
17903                    .into_iter()
17904                    .filter_map(|buffer| {
17905                        project
17906                            .update(cx, |project, cx| {
17907                                project.lsp_store().update(cx, |lsp_store, cx| {
17908                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17909                                })
17910                            })
17911                            .ok()
17912                    })
17913                    .collect::<FuturesUnordered<_>>()
17914            }) else {
17915                return;
17916            };
17917
17918            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17919                match pull_task {
17920                    Ok(()) => {
17921                        if editor
17922                            .update_in(cx, |editor, window, cx| {
17923                                editor.update_diagnostics_state(window, cx);
17924                            })
17925                            .is_err()
17926                        {
17927                            return;
17928                        }
17929                    }
17930                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17931                }
17932            }
17933        });
17934
17935        Some(())
17936    }
17937
17938    pub fn set_selections_from_remote(
17939        &mut self,
17940        selections: Vec<Selection<Anchor>>,
17941        pending_selection: Option<Selection<Anchor>>,
17942        window: &mut Window,
17943        cx: &mut Context<Self>,
17944    ) {
17945        let old_cursor_position = self.selections.newest_anchor().head();
17946        self.selections.change_with(cx, |s| {
17947            s.select_anchors(selections);
17948            if let Some(pending_selection) = pending_selection {
17949                s.set_pending(pending_selection, SelectMode::Character);
17950            } else {
17951                s.clear_pending();
17952            }
17953        });
17954        self.selections_did_change(
17955            false,
17956            &old_cursor_position,
17957            SelectionEffects::default(),
17958            window,
17959            cx,
17960        );
17961    }
17962
17963    pub fn transact(
17964        &mut self,
17965        window: &mut Window,
17966        cx: &mut Context<Self>,
17967        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17968    ) -> Option<TransactionId> {
17969        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17970            this.start_transaction_at(Instant::now(), window, cx);
17971            update(this, window, cx);
17972            this.end_transaction_at(Instant::now(), cx)
17973        })
17974    }
17975
17976    pub fn start_transaction_at(
17977        &mut self,
17978        now: Instant,
17979        window: &mut Window,
17980        cx: &mut Context<Self>,
17981    ) -> Option<TransactionId> {
17982        self.end_selection(window, cx);
17983        if let Some(tx_id) = self
17984            .buffer
17985            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17986        {
17987            self.selection_history
17988                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17989            cx.emit(EditorEvent::TransactionBegun {
17990                transaction_id: tx_id,
17991            });
17992            Some(tx_id)
17993        } else {
17994            None
17995        }
17996    }
17997
17998    pub fn end_transaction_at(
17999        &mut self,
18000        now: Instant,
18001        cx: &mut Context<Self>,
18002    ) -> Option<TransactionId> {
18003        if let Some(transaction_id) = self
18004            .buffer
18005            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18006        {
18007            if let Some((_, end_selections)) =
18008                self.selection_history.transaction_mut(transaction_id)
18009            {
18010                *end_selections = Some(self.selections.disjoint_anchors_arc());
18011            } else {
18012                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18013            }
18014
18015            cx.emit(EditorEvent::Edited { transaction_id });
18016            Some(transaction_id)
18017        } else {
18018            None
18019        }
18020    }
18021
18022    pub fn modify_transaction_selection_history(
18023        &mut self,
18024        transaction_id: TransactionId,
18025        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18026    ) -> bool {
18027        self.selection_history
18028            .transaction_mut(transaction_id)
18029            .map(modify)
18030            .is_some()
18031    }
18032
18033    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18034        if self.selection_mark_mode {
18035            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18036                s.move_with(|_, sel| {
18037                    sel.collapse_to(sel.head(), SelectionGoal::None);
18038                });
18039            })
18040        }
18041        self.selection_mark_mode = true;
18042        cx.notify();
18043    }
18044
18045    pub fn swap_selection_ends(
18046        &mut self,
18047        _: &actions::SwapSelectionEnds,
18048        window: &mut Window,
18049        cx: &mut Context<Self>,
18050    ) {
18051        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18052            s.move_with(|_, sel| {
18053                if sel.start != sel.end {
18054                    sel.reversed = !sel.reversed
18055                }
18056            });
18057        });
18058        self.request_autoscroll(Autoscroll::newest(), cx);
18059        cx.notify();
18060    }
18061
18062    pub fn toggle_focus(
18063        workspace: &mut Workspace,
18064        _: &actions::ToggleFocus,
18065        window: &mut Window,
18066        cx: &mut Context<Workspace>,
18067    ) {
18068        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18069            return;
18070        };
18071        workspace.activate_item(&item, true, true, window, cx);
18072    }
18073
18074    pub fn toggle_fold(
18075        &mut self,
18076        _: &actions::ToggleFold,
18077        window: &mut Window,
18078        cx: &mut Context<Self>,
18079    ) {
18080        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18081            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18082            let selection = self.selections.newest::<Point>(&display_map);
18083
18084            let range = if selection.is_empty() {
18085                let point = selection.head().to_display_point(&display_map);
18086                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18087                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18088                    .to_point(&display_map);
18089                start..end
18090            } else {
18091                selection.range()
18092            };
18093            if display_map.folds_in_range(range).next().is_some() {
18094                self.unfold_lines(&Default::default(), window, cx)
18095            } else {
18096                self.fold(&Default::default(), window, cx)
18097            }
18098        } else {
18099            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18100            let buffer_ids: HashSet<_> = self
18101                .selections
18102                .disjoint_anchor_ranges()
18103                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18104                .collect();
18105
18106            let should_unfold = buffer_ids
18107                .iter()
18108                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18109
18110            for buffer_id in buffer_ids {
18111                if should_unfold {
18112                    self.unfold_buffer(buffer_id, cx);
18113                } else {
18114                    self.fold_buffer(buffer_id, cx);
18115                }
18116            }
18117        }
18118    }
18119
18120    pub fn toggle_fold_recursive(
18121        &mut self,
18122        _: &actions::ToggleFoldRecursive,
18123        window: &mut Window,
18124        cx: &mut Context<Self>,
18125    ) {
18126        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18127
18128        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18129        let range = if selection.is_empty() {
18130            let point = selection.head().to_display_point(&display_map);
18131            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18132            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18133                .to_point(&display_map);
18134            start..end
18135        } else {
18136            selection.range()
18137        };
18138        if display_map.folds_in_range(range).next().is_some() {
18139            self.unfold_recursive(&Default::default(), window, cx)
18140        } else {
18141            self.fold_recursive(&Default::default(), window, cx)
18142        }
18143    }
18144
18145    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18146        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18147            let mut to_fold = Vec::new();
18148            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18149            let selections = self.selections.all_adjusted(&display_map);
18150
18151            for selection in selections {
18152                let range = selection.range().sorted();
18153                let buffer_start_row = range.start.row;
18154
18155                if range.start.row != range.end.row {
18156                    let mut found = false;
18157                    let mut row = range.start.row;
18158                    while row <= range.end.row {
18159                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18160                        {
18161                            found = true;
18162                            row = crease.range().end.row + 1;
18163                            to_fold.push(crease);
18164                        } else {
18165                            row += 1
18166                        }
18167                    }
18168                    if found {
18169                        continue;
18170                    }
18171                }
18172
18173                for row in (0..=range.start.row).rev() {
18174                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18175                        && crease.range().end.row >= buffer_start_row
18176                    {
18177                        to_fold.push(crease);
18178                        if row <= range.start.row {
18179                            break;
18180                        }
18181                    }
18182                }
18183            }
18184
18185            self.fold_creases(to_fold, true, window, cx);
18186        } else {
18187            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18188            let buffer_ids = self
18189                .selections
18190                .disjoint_anchor_ranges()
18191                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18192                .collect::<HashSet<_>>();
18193            for buffer_id in buffer_ids {
18194                self.fold_buffer(buffer_id, cx);
18195            }
18196        }
18197    }
18198
18199    pub fn toggle_fold_all(
18200        &mut self,
18201        _: &actions::ToggleFoldAll,
18202        window: &mut Window,
18203        cx: &mut Context<Self>,
18204    ) {
18205        if self.buffer.read(cx).is_singleton() {
18206            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18207            let has_folds = display_map
18208                .folds_in_range(0..display_map.buffer_snapshot().len())
18209                .next()
18210                .is_some();
18211
18212            if has_folds {
18213                self.unfold_all(&actions::UnfoldAll, window, cx);
18214            } else {
18215                self.fold_all(&actions::FoldAll, window, cx);
18216            }
18217        } else {
18218            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18219            let should_unfold = buffer_ids
18220                .iter()
18221                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18222
18223            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18224                editor
18225                    .update_in(cx, |editor, _, cx| {
18226                        for buffer_id in buffer_ids {
18227                            if should_unfold {
18228                                editor.unfold_buffer(buffer_id, cx);
18229                            } else {
18230                                editor.fold_buffer(buffer_id, cx);
18231                            }
18232                        }
18233                    })
18234                    .ok();
18235            });
18236        }
18237    }
18238
18239    fn fold_at_level(
18240        &mut self,
18241        fold_at: &FoldAtLevel,
18242        window: &mut Window,
18243        cx: &mut Context<Self>,
18244    ) {
18245        if !self.buffer.read(cx).is_singleton() {
18246            return;
18247        }
18248
18249        let fold_at_level = fold_at.0;
18250        let snapshot = self.buffer.read(cx).snapshot(cx);
18251        let mut to_fold = Vec::new();
18252        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18253
18254        let row_ranges_to_keep: Vec<Range<u32>> = self
18255            .selections
18256            .all::<Point>(&self.display_snapshot(cx))
18257            .into_iter()
18258            .map(|sel| sel.start.row..sel.end.row)
18259            .collect();
18260
18261        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18262            while start_row < end_row {
18263                match self
18264                    .snapshot(window, cx)
18265                    .crease_for_buffer_row(MultiBufferRow(start_row))
18266                {
18267                    Some(crease) => {
18268                        let nested_start_row = crease.range().start.row + 1;
18269                        let nested_end_row = crease.range().end.row;
18270
18271                        if current_level < fold_at_level {
18272                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18273                        } else if current_level == fold_at_level {
18274                            // Fold iff there is no selection completely contained within the fold region
18275                            if !row_ranges_to_keep.iter().any(|selection| {
18276                                selection.end >= nested_start_row
18277                                    && selection.start <= nested_end_row
18278                            }) {
18279                                to_fold.push(crease);
18280                            }
18281                        }
18282
18283                        start_row = nested_end_row + 1;
18284                    }
18285                    None => start_row += 1,
18286                }
18287            }
18288        }
18289
18290        self.fold_creases(to_fold, true, window, cx);
18291    }
18292
18293    pub fn fold_at_level_1(
18294        &mut self,
18295        _: &actions::FoldAtLevel1,
18296        window: &mut Window,
18297        cx: &mut Context<Self>,
18298    ) {
18299        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18300    }
18301
18302    pub fn fold_at_level_2(
18303        &mut self,
18304        _: &actions::FoldAtLevel2,
18305        window: &mut Window,
18306        cx: &mut Context<Self>,
18307    ) {
18308        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18309    }
18310
18311    pub fn fold_at_level_3(
18312        &mut self,
18313        _: &actions::FoldAtLevel3,
18314        window: &mut Window,
18315        cx: &mut Context<Self>,
18316    ) {
18317        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18318    }
18319
18320    pub fn fold_at_level_4(
18321        &mut self,
18322        _: &actions::FoldAtLevel4,
18323        window: &mut Window,
18324        cx: &mut Context<Self>,
18325    ) {
18326        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18327    }
18328
18329    pub fn fold_at_level_5(
18330        &mut self,
18331        _: &actions::FoldAtLevel5,
18332        window: &mut Window,
18333        cx: &mut Context<Self>,
18334    ) {
18335        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18336    }
18337
18338    pub fn fold_at_level_6(
18339        &mut self,
18340        _: &actions::FoldAtLevel6,
18341        window: &mut Window,
18342        cx: &mut Context<Self>,
18343    ) {
18344        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18345    }
18346
18347    pub fn fold_at_level_7(
18348        &mut self,
18349        _: &actions::FoldAtLevel7,
18350        window: &mut Window,
18351        cx: &mut Context<Self>,
18352    ) {
18353        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18354    }
18355
18356    pub fn fold_at_level_8(
18357        &mut self,
18358        _: &actions::FoldAtLevel8,
18359        window: &mut Window,
18360        cx: &mut Context<Self>,
18361    ) {
18362        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18363    }
18364
18365    pub fn fold_at_level_9(
18366        &mut self,
18367        _: &actions::FoldAtLevel9,
18368        window: &mut Window,
18369        cx: &mut Context<Self>,
18370    ) {
18371        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18372    }
18373
18374    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18375        if self.buffer.read(cx).is_singleton() {
18376            let mut fold_ranges = Vec::new();
18377            let snapshot = self.buffer.read(cx).snapshot(cx);
18378
18379            for row in 0..snapshot.max_row().0 {
18380                if let Some(foldable_range) = self
18381                    .snapshot(window, cx)
18382                    .crease_for_buffer_row(MultiBufferRow(row))
18383                {
18384                    fold_ranges.push(foldable_range);
18385                }
18386            }
18387
18388            self.fold_creases(fold_ranges, true, window, cx);
18389        } else {
18390            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18391                editor
18392                    .update_in(cx, |editor, _, cx| {
18393                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18394                            editor.fold_buffer(buffer_id, cx);
18395                        }
18396                    })
18397                    .ok();
18398            });
18399        }
18400    }
18401
18402    pub fn fold_function_bodies(
18403        &mut self,
18404        _: &actions::FoldFunctionBodies,
18405        window: &mut Window,
18406        cx: &mut Context<Self>,
18407    ) {
18408        let snapshot = self.buffer.read(cx).snapshot(cx);
18409
18410        let ranges = snapshot
18411            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18412            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18413            .collect::<Vec<_>>();
18414
18415        let creases = ranges
18416            .into_iter()
18417            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18418            .collect();
18419
18420        self.fold_creases(creases, true, window, cx);
18421    }
18422
18423    pub fn fold_recursive(
18424        &mut self,
18425        _: &actions::FoldRecursive,
18426        window: &mut Window,
18427        cx: &mut Context<Self>,
18428    ) {
18429        let mut to_fold = Vec::new();
18430        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18431        let selections = self.selections.all_adjusted(&display_map);
18432
18433        for selection in selections {
18434            let range = selection.range().sorted();
18435            let buffer_start_row = range.start.row;
18436
18437            if range.start.row != range.end.row {
18438                let mut found = false;
18439                for row in range.start.row..=range.end.row {
18440                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18441                        found = true;
18442                        to_fold.push(crease);
18443                    }
18444                }
18445                if found {
18446                    continue;
18447                }
18448            }
18449
18450            for row in (0..=range.start.row).rev() {
18451                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18452                    if crease.range().end.row >= buffer_start_row {
18453                        to_fold.push(crease);
18454                    } else {
18455                        break;
18456                    }
18457                }
18458            }
18459        }
18460
18461        self.fold_creases(to_fold, true, window, cx);
18462    }
18463
18464    pub fn fold_at(
18465        &mut self,
18466        buffer_row: MultiBufferRow,
18467        window: &mut Window,
18468        cx: &mut Context<Self>,
18469    ) {
18470        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18471
18472        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18473            let autoscroll = self
18474                .selections
18475                .all::<Point>(&display_map)
18476                .iter()
18477                .any(|selection| crease.range().overlaps(&selection.range()));
18478
18479            self.fold_creases(vec![crease], autoscroll, window, cx);
18480        }
18481    }
18482
18483    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18484        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18485            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18486            let buffer = display_map.buffer_snapshot();
18487            let selections = self.selections.all::<Point>(&display_map);
18488            let ranges = selections
18489                .iter()
18490                .map(|s| {
18491                    let range = s.display_range(&display_map).sorted();
18492                    let mut start = range.start.to_point(&display_map);
18493                    let mut end = range.end.to_point(&display_map);
18494                    start.column = 0;
18495                    end.column = buffer.line_len(MultiBufferRow(end.row));
18496                    start..end
18497                })
18498                .collect::<Vec<_>>();
18499
18500            self.unfold_ranges(&ranges, true, true, cx);
18501        } else {
18502            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18503            let buffer_ids = self
18504                .selections
18505                .disjoint_anchor_ranges()
18506                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18507                .collect::<HashSet<_>>();
18508            for buffer_id in buffer_ids {
18509                self.unfold_buffer(buffer_id, cx);
18510            }
18511        }
18512    }
18513
18514    pub fn unfold_recursive(
18515        &mut self,
18516        _: &UnfoldRecursive,
18517        _window: &mut Window,
18518        cx: &mut Context<Self>,
18519    ) {
18520        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18521        let selections = self.selections.all::<Point>(&display_map);
18522        let ranges = selections
18523            .iter()
18524            .map(|s| {
18525                let mut range = s.display_range(&display_map).sorted();
18526                *range.start.column_mut() = 0;
18527                *range.end.column_mut() = display_map.line_len(range.end.row());
18528                let start = range.start.to_point(&display_map);
18529                let end = range.end.to_point(&display_map);
18530                start..end
18531            })
18532            .collect::<Vec<_>>();
18533
18534        self.unfold_ranges(&ranges, true, true, cx);
18535    }
18536
18537    pub fn unfold_at(
18538        &mut self,
18539        buffer_row: MultiBufferRow,
18540        _window: &mut Window,
18541        cx: &mut Context<Self>,
18542    ) {
18543        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18544
18545        let intersection_range = Point::new(buffer_row.0, 0)
18546            ..Point::new(
18547                buffer_row.0,
18548                display_map.buffer_snapshot().line_len(buffer_row),
18549            );
18550
18551        let autoscroll = self
18552            .selections
18553            .all::<Point>(&display_map)
18554            .iter()
18555            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18556
18557        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18558    }
18559
18560    pub fn unfold_all(
18561        &mut self,
18562        _: &actions::UnfoldAll,
18563        _window: &mut Window,
18564        cx: &mut Context<Self>,
18565    ) {
18566        if self.buffer.read(cx).is_singleton() {
18567            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18568            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18569        } else {
18570            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18571                editor
18572                    .update(cx, |editor, cx| {
18573                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18574                            editor.unfold_buffer(buffer_id, cx);
18575                        }
18576                    })
18577                    .ok();
18578            });
18579        }
18580    }
18581
18582    pub fn fold_selected_ranges(
18583        &mut self,
18584        _: &FoldSelectedRanges,
18585        window: &mut Window,
18586        cx: &mut Context<Self>,
18587    ) {
18588        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18589        let selections = self.selections.all_adjusted(&display_map);
18590        let ranges = selections
18591            .into_iter()
18592            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18593            .collect::<Vec<_>>();
18594        self.fold_creases(ranges, true, window, cx);
18595    }
18596
18597    pub fn fold_ranges<T: ToOffset + Clone>(
18598        &mut self,
18599        ranges: Vec<Range<T>>,
18600        auto_scroll: bool,
18601        window: &mut Window,
18602        cx: &mut Context<Self>,
18603    ) {
18604        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18605        let ranges = ranges
18606            .into_iter()
18607            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18608            .collect::<Vec<_>>();
18609        self.fold_creases(ranges, auto_scroll, window, cx);
18610    }
18611
18612    pub fn fold_creases<T: ToOffset + Clone>(
18613        &mut self,
18614        creases: Vec<Crease<T>>,
18615        auto_scroll: bool,
18616        _window: &mut Window,
18617        cx: &mut Context<Self>,
18618    ) {
18619        if creases.is_empty() {
18620            return;
18621        }
18622
18623        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18624
18625        if auto_scroll {
18626            self.request_autoscroll(Autoscroll::fit(), cx);
18627        }
18628
18629        cx.notify();
18630
18631        self.scrollbar_marker_state.dirty = true;
18632        self.folds_did_change(cx);
18633    }
18634
18635    /// Removes any folds whose ranges intersect any of the given ranges.
18636    pub fn unfold_ranges<T: ToOffset + Clone>(
18637        &mut self,
18638        ranges: &[Range<T>],
18639        inclusive: bool,
18640        auto_scroll: bool,
18641        cx: &mut Context<Self>,
18642    ) {
18643        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18644            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18645        });
18646        self.folds_did_change(cx);
18647    }
18648
18649    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18650        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18651            return;
18652        }
18653        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18654        self.display_map.update(cx, |display_map, cx| {
18655            display_map.fold_buffers([buffer_id], cx)
18656        });
18657        cx.emit(EditorEvent::BufferFoldToggled {
18658            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18659            folded: true,
18660        });
18661        cx.notify();
18662    }
18663
18664    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18665        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18666            return;
18667        }
18668        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18669        self.display_map.update(cx, |display_map, cx| {
18670            display_map.unfold_buffers([buffer_id], cx);
18671        });
18672        cx.emit(EditorEvent::BufferFoldToggled {
18673            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18674            folded: false,
18675        });
18676        cx.notify();
18677    }
18678
18679    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18680        self.display_map.read(cx).is_buffer_folded(buffer)
18681    }
18682
18683    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18684        self.display_map.read(cx).folded_buffers()
18685    }
18686
18687    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18688        self.display_map.update(cx, |display_map, cx| {
18689            display_map.disable_header_for_buffer(buffer_id, cx);
18690        });
18691        cx.notify();
18692    }
18693
18694    /// Removes any folds with the given ranges.
18695    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18696        &mut self,
18697        ranges: &[Range<T>],
18698        type_id: TypeId,
18699        auto_scroll: bool,
18700        cx: &mut Context<Self>,
18701    ) {
18702        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18703            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18704        });
18705        self.folds_did_change(cx);
18706    }
18707
18708    fn remove_folds_with<T: ToOffset + Clone>(
18709        &mut self,
18710        ranges: &[Range<T>],
18711        auto_scroll: bool,
18712        cx: &mut Context<Self>,
18713        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18714    ) {
18715        if ranges.is_empty() {
18716            return;
18717        }
18718
18719        let mut buffers_affected = HashSet::default();
18720        let multi_buffer = self.buffer().read(cx);
18721        for range in ranges {
18722            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18723                buffers_affected.insert(buffer.read(cx).remote_id());
18724            };
18725        }
18726
18727        self.display_map.update(cx, update);
18728
18729        if auto_scroll {
18730            self.request_autoscroll(Autoscroll::fit(), cx);
18731        }
18732
18733        cx.notify();
18734        self.scrollbar_marker_state.dirty = true;
18735        self.active_indent_guides_state.dirty = true;
18736    }
18737
18738    pub fn update_renderer_widths(
18739        &mut self,
18740        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18741        cx: &mut Context<Self>,
18742    ) -> bool {
18743        self.display_map
18744            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18745    }
18746
18747    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18748        self.display_map.read(cx).fold_placeholder.clone()
18749    }
18750
18751    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18752        self.buffer.update(cx, |buffer, cx| {
18753            buffer.set_all_diff_hunks_expanded(cx);
18754        });
18755    }
18756
18757    pub fn expand_all_diff_hunks(
18758        &mut self,
18759        _: &ExpandAllDiffHunks,
18760        _window: &mut Window,
18761        cx: &mut Context<Self>,
18762    ) {
18763        self.buffer.update(cx, |buffer, cx| {
18764            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18765        });
18766    }
18767
18768    pub fn collapse_all_diff_hunks(
18769        &mut self,
18770        _: &CollapseAllDiffHunks,
18771        _window: &mut Window,
18772        cx: &mut Context<Self>,
18773    ) {
18774        self.buffer.update(cx, |buffer, cx| {
18775            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18776        });
18777    }
18778
18779    pub fn toggle_selected_diff_hunks(
18780        &mut self,
18781        _: &ToggleSelectedDiffHunks,
18782        _window: &mut Window,
18783        cx: &mut Context<Self>,
18784    ) {
18785        let ranges: Vec<_> = self
18786            .selections
18787            .disjoint_anchors()
18788            .iter()
18789            .map(|s| s.range())
18790            .collect();
18791        self.toggle_diff_hunks_in_ranges(ranges, cx);
18792    }
18793
18794    pub fn diff_hunks_in_ranges<'a>(
18795        &'a self,
18796        ranges: &'a [Range<Anchor>],
18797        buffer: &'a MultiBufferSnapshot,
18798    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18799        ranges.iter().flat_map(move |range| {
18800            let end_excerpt_id = range.end.excerpt_id;
18801            let range = range.to_point(buffer);
18802            let mut peek_end = range.end;
18803            if range.end.row < buffer.max_row().0 {
18804                peek_end = Point::new(range.end.row + 1, 0);
18805            }
18806            buffer
18807                .diff_hunks_in_range(range.start..peek_end)
18808                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18809        })
18810    }
18811
18812    pub fn has_stageable_diff_hunks_in_ranges(
18813        &self,
18814        ranges: &[Range<Anchor>],
18815        snapshot: &MultiBufferSnapshot,
18816    ) -> bool {
18817        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18818        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18819    }
18820
18821    pub fn toggle_staged_selected_diff_hunks(
18822        &mut self,
18823        _: &::git::ToggleStaged,
18824        _: &mut Window,
18825        cx: &mut Context<Self>,
18826    ) {
18827        let snapshot = self.buffer.read(cx).snapshot(cx);
18828        let ranges: Vec<_> = self
18829            .selections
18830            .disjoint_anchors()
18831            .iter()
18832            .map(|s| s.range())
18833            .collect();
18834        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18835        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18836    }
18837
18838    pub fn set_render_diff_hunk_controls(
18839        &mut self,
18840        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18841        cx: &mut Context<Self>,
18842    ) {
18843        self.render_diff_hunk_controls = render_diff_hunk_controls;
18844        cx.notify();
18845    }
18846
18847    pub fn stage_and_next(
18848        &mut self,
18849        _: &::git::StageAndNext,
18850        window: &mut Window,
18851        cx: &mut Context<Self>,
18852    ) {
18853        self.do_stage_or_unstage_and_next(true, window, cx);
18854    }
18855
18856    pub fn unstage_and_next(
18857        &mut self,
18858        _: &::git::UnstageAndNext,
18859        window: &mut Window,
18860        cx: &mut Context<Self>,
18861    ) {
18862        self.do_stage_or_unstage_and_next(false, window, cx);
18863    }
18864
18865    pub fn stage_or_unstage_diff_hunks(
18866        &mut self,
18867        stage: bool,
18868        ranges: Vec<Range<Anchor>>,
18869        cx: &mut Context<Self>,
18870    ) {
18871        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18872        cx.spawn(async move |this, cx| {
18873            task.await?;
18874            this.update(cx, |this, cx| {
18875                let snapshot = this.buffer.read(cx).snapshot(cx);
18876                let chunk_by = this
18877                    .diff_hunks_in_ranges(&ranges, &snapshot)
18878                    .chunk_by(|hunk| hunk.buffer_id);
18879                for (buffer_id, hunks) in &chunk_by {
18880                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18881                }
18882            })
18883        })
18884        .detach_and_log_err(cx);
18885    }
18886
18887    fn save_buffers_for_ranges_if_needed(
18888        &mut self,
18889        ranges: &[Range<Anchor>],
18890        cx: &mut Context<Editor>,
18891    ) -> Task<Result<()>> {
18892        let multibuffer = self.buffer.read(cx);
18893        let snapshot = multibuffer.read(cx);
18894        let buffer_ids: HashSet<_> = ranges
18895            .iter()
18896            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18897            .collect();
18898        drop(snapshot);
18899
18900        let mut buffers = HashSet::default();
18901        for buffer_id in buffer_ids {
18902            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18903                let buffer = buffer_entity.read(cx);
18904                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18905                {
18906                    buffers.insert(buffer_entity);
18907                }
18908            }
18909        }
18910
18911        if let Some(project) = &self.project {
18912            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18913        } else {
18914            Task::ready(Ok(()))
18915        }
18916    }
18917
18918    fn do_stage_or_unstage_and_next(
18919        &mut self,
18920        stage: bool,
18921        window: &mut Window,
18922        cx: &mut Context<Self>,
18923    ) {
18924        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18925
18926        if ranges.iter().any(|range| range.start != range.end) {
18927            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18928            return;
18929        }
18930
18931        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18932        let snapshot = self.snapshot(window, cx);
18933        let position = self
18934            .selections
18935            .newest::<Point>(&snapshot.display_snapshot)
18936            .head();
18937        let mut row = snapshot
18938            .buffer_snapshot()
18939            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18940            .find(|hunk| hunk.row_range.start.0 > position.row)
18941            .map(|hunk| hunk.row_range.start);
18942
18943        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18944        // Outside of the project diff editor, wrap around to the beginning.
18945        if !all_diff_hunks_expanded {
18946            row = row.or_else(|| {
18947                snapshot
18948                    .buffer_snapshot()
18949                    .diff_hunks_in_range(Point::zero()..position)
18950                    .find(|hunk| hunk.row_range.end.0 < position.row)
18951                    .map(|hunk| hunk.row_range.start)
18952            });
18953        }
18954
18955        if let Some(row) = row {
18956            let destination = Point::new(row.0, 0);
18957            let autoscroll = Autoscroll::center();
18958
18959            self.unfold_ranges(&[destination..destination], false, false, cx);
18960            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18961                s.select_ranges([destination..destination]);
18962            });
18963        }
18964    }
18965
18966    fn do_stage_or_unstage(
18967        &self,
18968        stage: bool,
18969        buffer_id: BufferId,
18970        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18971        cx: &mut App,
18972    ) -> Option<()> {
18973        let project = self.project()?;
18974        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18975        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18976        let buffer_snapshot = buffer.read(cx).snapshot();
18977        let file_exists = buffer_snapshot
18978            .file()
18979            .is_some_and(|file| file.disk_state().exists());
18980        diff.update(cx, |diff, cx| {
18981            diff.stage_or_unstage_hunks(
18982                stage,
18983                &hunks
18984                    .map(|hunk| buffer_diff::DiffHunk {
18985                        buffer_range: hunk.buffer_range,
18986                        diff_base_byte_range: hunk.diff_base_byte_range,
18987                        secondary_status: hunk.secondary_status,
18988                        range: Point::zero()..Point::zero(), // unused
18989                    })
18990                    .collect::<Vec<_>>(),
18991                &buffer_snapshot,
18992                file_exists,
18993                cx,
18994            )
18995        });
18996        None
18997    }
18998
18999    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19000        let ranges: Vec<_> = self
19001            .selections
19002            .disjoint_anchors()
19003            .iter()
19004            .map(|s| s.range())
19005            .collect();
19006        self.buffer
19007            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19008    }
19009
19010    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19011        self.buffer.update(cx, |buffer, cx| {
19012            let ranges = vec![Anchor::min()..Anchor::max()];
19013            if !buffer.all_diff_hunks_expanded()
19014                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19015            {
19016                buffer.collapse_diff_hunks(ranges, cx);
19017                true
19018            } else {
19019                false
19020            }
19021        })
19022    }
19023
19024    fn toggle_diff_hunks_in_ranges(
19025        &mut self,
19026        ranges: Vec<Range<Anchor>>,
19027        cx: &mut Context<Editor>,
19028    ) {
19029        self.buffer.update(cx, |buffer, cx| {
19030            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19031            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19032        })
19033    }
19034
19035    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19036        self.buffer.update(cx, |buffer, cx| {
19037            let snapshot = buffer.snapshot(cx);
19038            let excerpt_id = range.end.excerpt_id;
19039            let point_range = range.to_point(&snapshot);
19040            let expand = !buffer.single_hunk_is_expanded(range, cx);
19041            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19042        })
19043    }
19044
19045    pub(crate) fn apply_all_diff_hunks(
19046        &mut self,
19047        _: &ApplyAllDiffHunks,
19048        window: &mut Window,
19049        cx: &mut Context<Self>,
19050    ) {
19051        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19052
19053        let buffers = self.buffer.read(cx).all_buffers();
19054        for branch_buffer in buffers {
19055            branch_buffer.update(cx, |branch_buffer, cx| {
19056                branch_buffer.merge_into_base(Vec::new(), cx);
19057            });
19058        }
19059
19060        if let Some(project) = self.project.clone() {
19061            self.save(
19062                SaveOptions {
19063                    format: true,
19064                    autosave: false,
19065                },
19066                project,
19067                window,
19068                cx,
19069            )
19070            .detach_and_log_err(cx);
19071        }
19072    }
19073
19074    pub(crate) fn apply_selected_diff_hunks(
19075        &mut self,
19076        _: &ApplyDiffHunk,
19077        window: &mut Window,
19078        cx: &mut Context<Self>,
19079    ) {
19080        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19081        let snapshot = self.snapshot(window, cx);
19082        let hunks = snapshot.hunks_for_ranges(
19083            self.selections
19084                .all(&snapshot.display_snapshot)
19085                .into_iter()
19086                .map(|selection| selection.range()),
19087        );
19088        let mut ranges_by_buffer = HashMap::default();
19089        self.transact(window, cx, |editor, _window, cx| {
19090            for hunk in hunks {
19091                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19092                    ranges_by_buffer
19093                        .entry(buffer.clone())
19094                        .or_insert_with(Vec::new)
19095                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19096                }
19097            }
19098
19099            for (buffer, ranges) in ranges_by_buffer {
19100                buffer.update(cx, |buffer, cx| {
19101                    buffer.merge_into_base(ranges, cx);
19102                });
19103            }
19104        });
19105
19106        if let Some(project) = self.project.clone() {
19107            self.save(
19108                SaveOptions {
19109                    format: true,
19110                    autosave: false,
19111                },
19112                project,
19113                window,
19114                cx,
19115            )
19116            .detach_and_log_err(cx);
19117        }
19118    }
19119
19120    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19121        if hovered != self.gutter_hovered {
19122            self.gutter_hovered = hovered;
19123            cx.notify();
19124        }
19125    }
19126
19127    pub fn insert_blocks(
19128        &mut self,
19129        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19130        autoscroll: Option<Autoscroll>,
19131        cx: &mut Context<Self>,
19132    ) -> Vec<CustomBlockId> {
19133        let blocks = self
19134            .display_map
19135            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19136        if let Some(autoscroll) = autoscroll {
19137            self.request_autoscroll(autoscroll, cx);
19138        }
19139        cx.notify();
19140        blocks
19141    }
19142
19143    pub fn resize_blocks(
19144        &mut self,
19145        heights: HashMap<CustomBlockId, u32>,
19146        autoscroll: Option<Autoscroll>,
19147        cx: &mut Context<Self>,
19148    ) {
19149        self.display_map
19150            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19151        if let Some(autoscroll) = autoscroll {
19152            self.request_autoscroll(autoscroll, cx);
19153        }
19154        cx.notify();
19155    }
19156
19157    pub fn replace_blocks(
19158        &mut self,
19159        renderers: HashMap<CustomBlockId, RenderBlock>,
19160        autoscroll: Option<Autoscroll>,
19161        cx: &mut Context<Self>,
19162    ) {
19163        self.display_map
19164            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19165        if let Some(autoscroll) = autoscroll {
19166            self.request_autoscroll(autoscroll, cx);
19167        }
19168        cx.notify();
19169    }
19170
19171    pub fn remove_blocks(
19172        &mut self,
19173        block_ids: HashSet<CustomBlockId>,
19174        autoscroll: Option<Autoscroll>,
19175        cx: &mut Context<Self>,
19176    ) {
19177        self.display_map.update(cx, |display_map, cx| {
19178            display_map.remove_blocks(block_ids, cx)
19179        });
19180        if let Some(autoscroll) = autoscroll {
19181            self.request_autoscroll(autoscroll, cx);
19182        }
19183        cx.notify();
19184    }
19185
19186    pub fn row_for_block(
19187        &self,
19188        block_id: CustomBlockId,
19189        cx: &mut Context<Self>,
19190    ) -> Option<DisplayRow> {
19191        self.display_map
19192            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19193    }
19194
19195    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19196        self.focused_block = Some(focused_block);
19197    }
19198
19199    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19200        self.focused_block.take()
19201    }
19202
19203    pub fn insert_creases(
19204        &mut self,
19205        creases: impl IntoIterator<Item = Crease<Anchor>>,
19206        cx: &mut Context<Self>,
19207    ) -> Vec<CreaseId> {
19208        self.display_map
19209            .update(cx, |map, cx| map.insert_creases(creases, cx))
19210    }
19211
19212    pub fn remove_creases(
19213        &mut self,
19214        ids: impl IntoIterator<Item = CreaseId>,
19215        cx: &mut Context<Self>,
19216    ) -> Vec<(CreaseId, Range<Anchor>)> {
19217        self.display_map
19218            .update(cx, |map, cx| map.remove_creases(ids, cx))
19219    }
19220
19221    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19222        self.display_map
19223            .update(cx, |map, cx| map.snapshot(cx))
19224            .longest_row()
19225    }
19226
19227    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19228        self.display_map
19229            .update(cx, |map, cx| map.snapshot(cx))
19230            .max_point()
19231    }
19232
19233    pub fn text(&self, cx: &App) -> String {
19234        self.buffer.read(cx).read(cx).text()
19235    }
19236
19237    pub fn is_empty(&self, cx: &App) -> bool {
19238        self.buffer.read(cx).read(cx).is_empty()
19239    }
19240
19241    pub fn text_option(&self, cx: &App) -> Option<String> {
19242        let text = self.text(cx);
19243        let text = text.trim();
19244
19245        if text.is_empty() {
19246            return None;
19247        }
19248
19249        Some(text.to_string())
19250    }
19251
19252    pub fn set_text(
19253        &mut self,
19254        text: impl Into<Arc<str>>,
19255        window: &mut Window,
19256        cx: &mut Context<Self>,
19257    ) {
19258        self.transact(window, cx, |this, _, cx| {
19259            this.buffer
19260                .read(cx)
19261                .as_singleton()
19262                .expect("you can only call set_text on editors for singleton buffers")
19263                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19264        });
19265    }
19266
19267    pub fn display_text(&self, cx: &mut App) -> String {
19268        self.display_map
19269            .update(cx, |map, cx| map.snapshot(cx))
19270            .text()
19271    }
19272
19273    fn create_minimap(
19274        &self,
19275        minimap_settings: MinimapSettings,
19276        window: &mut Window,
19277        cx: &mut Context<Self>,
19278    ) -> Option<Entity<Self>> {
19279        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19280            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19281    }
19282
19283    fn initialize_new_minimap(
19284        &self,
19285        minimap_settings: MinimapSettings,
19286        window: &mut Window,
19287        cx: &mut Context<Self>,
19288    ) -> Entity<Self> {
19289        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19290
19291        let mut minimap = Editor::new_internal(
19292            EditorMode::Minimap {
19293                parent: cx.weak_entity(),
19294            },
19295            self.buffer.clone(),
19296            None,
19297            Some(self.display_map.clone()),
19298            window,
19299            cx,
19300        );
19301        minimap.scroll_manager.clone_state(&self.scroll_manager);
19302        minimap.set_text_style_refinement(TextStyleRefinement {
19303            font_size: Some(MINIMAP_FONT_SIZE),
19304            font_weight: Some(MINIMAP_FONT_WEIGHT),
19305            ..Default::default()
19306        });
19307        minimap.update_minimap_configuration(minimap_settings, cx);
19308        cx.new(|_| minimap)
19309    }
19310
19311    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19312        let current_line_highlight = minimap_settings
19313            .current_line_highlight
19314            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19315        self.set_current_line_highlight(Some(current_line_highlight));
19316    }
19317
19318    pub fn minimap(&self) -> Option<&Entity<Self>> {
19319        self.minimap
19320            .as_ref()
19321            .filter(|_| self.minimap_visibility.visible())
19322    }
19323
19324    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19325        let mut wrap_guides = smallvec![];
19326
19327        if self.show_wrap_guides == Some(false) {
19328            return wrap_guides;
19329        }
19330
19331        let settings = self.buffer.read(cx).language_settings(cx);
19332        if settings.show_wrap_guides {
19333            match self.soft_wrap_mode(cx) {
19334                SoftWrap::Column(soft_wrap) => {
19335                    wrap_guides.push((soft_wrap as usize, true));
19336                }
19337                SoftWrap::Bounded(soft_wrap) => {
19338                    wrap_guides.push((soft_wrap as usize, true));
19339                }
19340                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19341            }
19342            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19343        }
19344
19345        wrap_guides
19346    }
19347
19348    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19349        let settings = self.buffer.read(cx).language_settings(cx);
19350        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19351        match mode {
19352            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19353                SoftWrap::None
19354            }
19355            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19356            language_settings::SoftWrap::PreferredLineLength => {
19357                SoftWrap::Column(settings.preferred_line_length)
19358            }
19359            language_settings::SoftWrap::Bounded => {
19360                SoftWrap::Bounded(settings.preferred_line_length)
19361            }
19362        }
19363    }
19364
19365    pub fn set_soft_wrap_mode(
19366        &mut self,
19367        mode: language_settings::SoftWrap,
19368
19369        cx: &mut Context<Self>,
19370    ) {
19371        self.soft_wrap_mode_override = Some(mode);
19372        cx.notify();
19373    }
19374
19375    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19376        self.hard_wrap = hard_wrap;
19377        cx.notify();
19378    }
19379
19380    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19381        self.text_style_refinement = Some(style);
19382    }
19383
19384    /// called by the Element so we know what style we were most recently rendered with.
19385    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19386        // We intentionally do not inform the display map about the minimap style
19387        // so that wrapping is not recalculated and stays consistent for the editor
19388        // and its linked minimap.
19389        if !self.mode.is_minimap() {
19390            let font = style.text.font();
19391            let font_size = style.text.font_size.to_pixels(window.rem_size());
19392            let display_map = self
19393                .placeholder_display_map
19394                .as_ref()
19395                .filter(|_| self.is_empty(cx))
19396                .unwrap_or(&self.display_map);
19397
19398            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19399        }
19400        self.style = Some(style);
19401    }
19402
19403    pub fn style(&self) -> Option<&EditorStyle> {
19404        self.style.as_ref()
19405    }
19406
19407    // Called by the element. This method is not designed to be called outside of the editor
19408    // element's layout code because it does not notify when rewrapping is computed synchronously.
19409    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19410        if self.is_empty(cx) {
19411            self.placeholder_display_map
19412                .as_ref()
19413                .map_or(false, |display_map| {
19414                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19415                })
19416        } else {
19417            self.display_map
19418                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19419        }
19420    }
19421
19422    pub fn set_soft_wrap(&mut self) {
19423        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19424    }
19425
19426    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19427        if self.soft_wrap_mode_override.is_some() {
19428            self.soft_wrap_mode_override.take();
19429        } else {
19430            let soft_wrap = match self.soft_wrap_mode(cx) {
19431                SoftWrap::GitDiff => return,
19432                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19433                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19434                    language_settings::SoftWrap::None
19435                }
19436            };
19437            self.soft_wrap_mode_override = Some(soft_wrap);
19438        }
19439        cx.notify();
19440    }
19441
19442    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19443        let Some(workspace) = self.workspace() else {
19444            return;
19445        };
19446        let fs = workspace.read(cx).app_state().fs.clone();
19447        let current_show = TabBarSettings::get_global(cx).show;
19448        update_settings_file(fs, cx, move |setting, _| {
19449            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19450        });
19451    }
19452
19453    pub fn toggle_indent_guides(
19454        &mut self,
19455        _: &ToggleIndentGuides,
19456        _: &mut Window,
19457        cx: &mut Context<Self>,
19458    ) {
19459        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19460            self.buffer
19461                .read(cx)
19462                .language_settings(cx)
19463                .indent_guides
19464                .enabled
19465        });
19466        self.show_indent_guides = Some(!currently_enabled);
19467        cx.notify();
19468    }
19469
19470    fn should_show_indent_guides(&self) -> Option<bool> {
19471        self.show_indent_guides
19472    }
19473
19474    pub fn toggle_line_numbers(
19475        &mut self,
19476        _: &ToggleLineNumbers,
19477        _: &mut Window,
19478        cx: &mut Context<Self>,
19479    ) {
19480        let mut editor_settings = EditorSettings::get_global(cx).clone();
19481        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19482        EditorSettings::override_global(editor_settings, cx);
19483    }
19484
19485    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19486        if let Some(show_line_numbers) = self.show_line_numbers {
19487            return show_line_numbers;
19488        }
19489        EditorSettings::get_global(cx).gutter.line_numbers
19490    }
19491
19492    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19493        match (
19494            self.use_relative_line_numbers,
19495            EditorSettings::get_global(cx).relative_line_numbers,
19496        ) {
19497            (None, setting) => setting,
19498            (Some(false), _) => RelativeLineNumbers::Disabled,
19499            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19500            (Some(true), _) => RelativeLineNumbers::Enabled,
19501        }
19502    }
19503
19504    pub fn toggle_relative_line_numbers(
19505        &mut self,
19506        _: &ToggleRelativeLineNumbers,
19507        _: &mut Window,
19508        cx: &mut Context<Self>,
19509    ) {
19510        let is_relative = self.relative_line_numbers(cx);
19511        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19512    }
19513
19514    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19515        self.use_relative_line_numbers = is_relative;
19516        cx.notify();
19517    }
19518
19519    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19520        self.show_gutter = show_gutter;
19521        cx.notify();
19522    }
19523
19524    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19525        self.show_scrollbars = ScrollbarAxes {
19526            horizontal: show,
19527            vertical: show,
19528        };
19529        cx.notify();
19530    }
19531
19532    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19533        self.show_scrollbars.vertical = show;
19534        cx.notify();
19535    }
19536
19537    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19538        self.show_scrollbars.horizontal = show;
19539        cx.notify();
19540    }
19541
19542    pub fn set_minimap_visibility(
19543        &mut self,
19544        minimap_visibility: MinimapVisibility,
19545        window: &mut Window,
19546        cx: &mut Context<Self>,
19547    ) {
19548        if self.minimap_visibility != minimap_visibility {
19549            if minimap_visibility.visible() && self.minimap.is_none() {
19550                let minimap_settings = EditorSettings::get_global(cx).minimap;
19551                self.minimap =
19552                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19553            }
19554            self.minimap_visibility = minimap_visibility;
19555            cx.notify();
19556        }
19557    }
19558
19559    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19560        self.set_show_scrollbars(false, cx);
19561        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19562    }
19563
19564    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19565        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19566    }
19567
19568    /// Normally the text in full mode and auto height editors is padded on the
19569    /// left side by roughly half a character width for improved hit testing.
19570    ///
19571    /// Use this method to disable this for cases where this is not wanted (e.g.
19572    /// if you want to align the editor text with some other text above or below)
19573    /// or if you want to add this padding to single-line editors.
19574    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19575        self.offset_content = offset_content;
19576        cx.notify();
19577    }
19578
19579    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19580        self.show_line_numbers = Some(show_line_numbers);
19581        cx.notify();
19582    }
19583
19584    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19585        self.disable_expand_excerpt_buttons = true;
19586        cx.notify();
19587    }
19588
19589    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19590        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19591        cx.notify();
19592    }
19593
19594    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19595        self.show_code_actions = Some(show_code_actions);
19596        cx.notify();
19597    }
19598
19599    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19600        self.show_runnables = Some(show_runnables);
19601        cx.notify();
19602    }
19603
19604    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19605        self.show_breakpoints = Some(show_breakpoints);
19606        cx.notify();
19607    }
19608
19609    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19610        if self.display_map.read(cx).masked != masked {
19611            self.display_map.update(cx, |map, _| map.masked = masked);
19612        }
19613        cx.notify()
19614    }
19615
19616    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19617        self.show_wrap_guides = Some(show_wrap_guides);
19618        cx.notify();
19619    }
19620
19621    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19622        self.show_indent_guides = Some(show_indent_guides);
19623        cx.notify();
19624    }
19625
19626    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19627        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19628            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19629                && let Some(dir) = file.abs_path(cx).parent()
19630            {
19631                return Some(dir.to_owned());
19632            }
19633        }
19634
19635        None
19636    }
19637
19638    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19639        self.active_excerpt(cx)?
19640            .1
19641            .read(cx)
19642            .file()
19643            .and_then(|f| f.as_local())
19644    }
19645
19646    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19647        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19648            let buffer = buffer.read(cx);
19649            if let Some(project_path) = buffer.project_path(cx) {
19650                let project = self.project()?.read(cx);
19651                project.absolute_path(&project_path, cx)
19652            } else {
19653                buffer
19654                    .file()
19655                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19656            }
19657        })
19658    }
19659
19660    pub fn reveal_in_finder(
19661        &mut self,
19662        _: &RevealInFileManager,
19663        _window: &mut Window,
19664        cx: &mut Context<Self>,
19665    ) {
19666        if let Some(target) = self.target_file(cx) {
19667            cx.reveal_path(&target.abs_path(cx));
19668        }
19669    }
19670
19671    pub fn copy_path(
19672        &mut self,
19673        _: &zed_actions::workspace::CopyPath,
19674        _window: &mut Window,
19675        cx: &mut Context<Self>,
19676    ) {
19677        if let Some(path) = self.target_file_abs_path(cx)
19678            && let Some(path) = path.to_str()
19679        {
19680            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19681        } else {
19682            cx.propagate();
19683        }
19684    }
19685
19686    pub fn copy_relative_path(
19687        &mut self,
19688        _: &zed_actions::workspace::CopyRelativePath,
19689        _window: &mut Window,
19690        cx: &mut Context<Self>,
19691    ) {
19692        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19693            let project = self.project()?.read(cx);
19694            let path = buffer.read(cx).file()?.path();
19695            let path = path.display(project.path_style(cx));
19696            Some(path)
19697        }) {
19698            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19699        } else {
19700            cx.propagate();
19701        }
19702    }
19703
19704    /// Returns the project path for the editor's buffer, if any buffer is
19705    /// opened in the editor.
19706    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19707        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19708            buffer.read(cx).project_path(cx)
19709        } else {
19710            None
19711        }
19712    }
19713
19714    // Returns true if the editor handled a go-to-line request
19715    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19716        maybe!({
19717            let breakpoint_store = self.breakpoint_store.as_ref()?;
19718
19719            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19720            else {
19721                self.clear_row_highlights::<ActiveDebugLine>();
19722                return None;
19723            };
19724
19725            let position = active_stack_frame.position;
19726            let buffer_id = position.buffer_id?;
19727            let snapshot = self
19728                .project
19729                .as_ref()?
19730                .read(cx)
19731                .buffer_for_id(buffer_id, cx)?
19732                .read(cx)
19733                .snapshot();
19734
19735            let mut handled = false;
19736            for (id, ExcerptRange { context, .. }) in
19737                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19738            {
19739                if context.start.cmp(&position, &snapshot).is_ge()
19740                    || context.end.cmp(&position, &snapshot).is_lt()
19741                {
19742                    continue;
19743                }
19744                let snapshot = self.buffer.read(cx).snapshot(cx);
19745                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19746
19747                handled = true;
19748                self.clear_row_highlights::<ActiveDebugLine>();
19749
19750                self.go_to_line::<ActiveDebugLine>(
19751                    multibuffer_anchor,
19752                    Some(cx.theme().colors().editor_debugger_active_line_background),
19753                    window,
19754                    cx,
19755                );
19756
19757                cx.notify();
19758            }
19759
19760            handled.then_some(())
19761        })
19762        .is_some()
19763    }
19764
19765    pub fn copy_file_name_without_extension(
19766        &mut self,
19767        _: &CopyFileNameWithoutExtension,
19768        _: &mut Window,
19769        cx: &mut Context<Self>,
19770    ) {
19771        if let Some(file) = self.target_file(cx)
19772            && let Some(file_stem) = file.path().file_stem()
19773        {
19774            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19775        }
19776    }
19777
19778    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19779        if let Some(file) = self.target_file(cx)
19780            && let Some(name) = file.path().file_name()
19781        {
19782            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19783        }
19784    }
19785
19786    pub fn toggle_git_blame(
19787        &mut self,
19788        _: &::git::Blame,
19789        window: &mut Window,
19790        cx: &mut Context<Self>,
19791    ) {
19792        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19793
19794        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19795            self.start_git_blame(true, window, cx);
19796        }
19797
19798        cx.notify();
19799    }
19800
19801    pub fn toggle_git_blame_inline(
19802        &mut self,
19803        _: &ToggleGitBlameInline,
19804        window: &mut Window,
19805        cx: &mut Context<Self>,
19806    ) {
19807        self.toggle_git_blame_inline_internal(true, window, cx);
19808        cx.notify();
19809    }
19810
19811    pub fn open_git_blame_commit(
19812        &mut self,
19813        _: &OpenGitBlameCommit,
19814        window: &mut Window,
19815        cx: &mut Context<Self>,
19816    ) {
19817        self.open_git_blame_commit_internal(window, cx);
19818    }
19819
19820    fn open_git_blame_commit_internal(
19821        &mut self,
19822        window: &mut Window,
19823        cx: &mut Context<Self>,
19824    ) -> Option<()> {
19825        let blame = self.blame.as_ref()?;
19826        let snapshot = self.snapshot(window, cx);
19827        let cursor = self
19828            .selections
19829            .newest::<Point>(&snapshot.display_snapshot)
19830            .head();
19831        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19832        let (_, blame_entry) = blame
19833            .update(cx, |blame, cx| {
19834                blame
19835                    .blame_for_rows(
19836                        &[RowInfo {
19837                            buffer_id: Some(buffer.remote_id()),
19838                            buffer_row: Some(point.row),
19839                            ..Default::default()
19840                        }],
19841                        cx,
19842                    )
19843                    .next()
19844            })
19845            .flatten()?;
19846        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19847        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19848        let workspace = self.workspace()?.downgrade();
19849        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19850        None
19851    }
19852
19853    pub fn git_blame_inline_enabled(&self) -> bool {
19854        self.git_blame_inline_enabled
19855    }
19856
19857    pub fn toggle_selection_menu(
19858        &mut self,
19859        _: &ToggleSelectionMenu,
19860        _: &mut Window,
19861        cx: &mut Context<Self>,
19862    ) {
19863        self.show_selection_menu = self
19864            .show_selection_menu
19865            .map(|show_selections_menu| !show_selections_menu)
19866            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19867
19868        cx.notify();
19869    }
19870
19871    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19872        self.show_selection_menu
19873            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19874    }
19875
19876    fn start_git_blame(
19877        &mut self,
19878        user_triggered: bool,
19879        window: &mut Window,
19880        cx: &mut Context<Self>,
19881    ) {
19882        if let Some(project) = self.project() {
19883            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19884                && buffer.read(cx).file().is_none()
19885            {
19886                return;
19887            }
19888
19889            let focused = self.focus_handle(cx).contains_focused(window, cx);
19890
19891            let project = project.clone();
19892            let blame = cx
19893                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19894            self.blame_subscription =
19895                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19896            self.blame = Some(blame);
19897        }
19898    }
19899
19900    fn toggle_git_blame_inline_internal(
19901        &mut self,
19902        user_triggered: bool,
19903        window: &mut Window,
19904        cx: &mut Context<Self>,
19905    ) {
19906        if self.git_blame_inline_enabled {
19907            self.git_blame_inline_enabled = false;
19908            self.show_git_blame_inline = false;
19909            self.show_git_blame_inline_delay_task.take();
19910        } else {
19911            self.git_blame_inline_enabled = true;
19912            self.start_git_blame_inline(user_triggered, window, cx);
19913        }
19914
19915        cx.notify();
19916    }
19917
19918    fn start_git_blame_inline(
19919        &mut self,
19920        user_triggered: bool,
19921        window: &mut Window,
19922        cx: &mut Context<Self>,
19923    ) {
19924        self.start_git_blame(user_triggered, window, cx);
19925
19926        if ProjectSettings::get_global(cx)
19927            .git
19928            .inline_blame_delay()
19929            .is_some()
19930        {
19931            self.start_inline_blame_timer(window, cx);
19932        } else {
19933            self.show_git_blame_inline = true
19934        }
19935    }
19936
19937    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19938        self.blame.as_ref()
19939    }
19940
19941    pub fn show_git_blame_gutter(&self) -> bool {
19942        self.show_git_blame_gutter
19943    }
19944
19945    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19946        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19947    }
19948
19949    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19950        self.show_git_blame_inline
19951            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19952            && !self.newest_selection_head_on_empty_line(cx)
19953            && self.has_blame_entries(cx)
19954    }
19955
19956    fn has_blame_entries(&self, cx: &App) -> bool {
19957        self.blame()
19958            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19959    }
19960
19961    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19962        let cursor_anchor = self.selections.newest_anchor().head();
19963
19964        let snapshot = self.buffer.read(cx).snapshot(cx);
19965        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19966
19967        snapshot.line_len(buffer_row) == 0
19968    }
19969
19970    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19971        let buffer_and_selection = maybe!({
19972            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19973            let selection_range = selection.range();
19974
19975            let multi_buffer = self.buffer().read(cx);
19976            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19977            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19978
19979            let (buffer, range, _) = if selection.reversed {
19980                buffer_ranges.first()
19981            } else {
19982                buffer_ranges.last()
19983            }?;
19984
19985            let selection = text::ToPoint::to_point(&range.start, buffer).row
19986                ..text::ToPoint::to_point(&range.end, buffer).row;
19987            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19988        });
19989
19990        let Some((buffer, selection)) = buffer_and_selection else {
19991            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19992        };
19993
19994        let Some(project) = self.project() else {
19995            return Task::ready(Err(anyhow!("editor does not have project")));
19996        };
19997
19998        project.update(cx, |project, cx| {
19999            project.get_permalink_to_line(&buffer, selection, cx)
20000        })
20001    }
20002
20003    pub fn copy_permalink_to_line(
20004        &mut self,
20005        _: &CopyPermalinkToLine,
20006        window: &mut Window,
20007        cx: &mut Context<Self>,
20008    ) {
20009        let permalink_task = self.get_permalink_to_line(cx);
20010        let workspace = self.workspace();
20011
20012        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20013            Ok(permalink) => {
20014                cx.update(|_, cx| {
20015                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20016                })
20017                .ok();
20018            }
20019            Err(err) => {
20020                let message = format!("Failed to copy permalink: {err}");
20021
20022                anyhow::Result::<()>::Err(err).log_err();
20023
20024                if let Some(workspace) = workspace {
20025                    workspace
20026                        .update_in(cx, |workspace, _, cx| {
20027                            struct CopyPermalinkToLine;
20028
20029                            workspace.show_toast(
20030                                Toast::new(
20031                                    NotificationId::unique::<CopyPermalinkToLine>(),
20032                                    message,
20033                                ),
20034                                cx,
20035                            )
20036                        })
20037                        .ok();
20038                }
20039            }
20040        })
20041        .detach();
20042    }
20043
20044    pub fn copy_file_location(
20045        &mut self,
20046        _: &CopyFileLocation,
20047        _: &mut Window,
20048        cx: &mut Context<Self>,
20049    ) {
20050        let selection = self
20051            .selections
20052            .newest::<Point>(&self.display_snapshot(cx))
20053            .start
20054            .row
20055            + 1;
20056        if let Some(file) = self.target_file(cx) {
20057            let path = file.path().display(file.path_style(cx));
20058            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20059        }
20060    }
20061
20062    pub fn open_permalink_to_line(
20063        &mut self,
20064        _: &OpenPermalinkToLine,
20065        window: &mut Window,
20066        cx: &mut Context<Self>,
20067    ) {
20068        let permalink_task = self.get_permalink_to_line(cx);
20069        let workspace = self.workspace();
20070
20071        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20072            Ok(permalink) => {
20073                cx.update(|_, cx| {
20074                    cx.open_url(permalink.as_ref());
20075                })
20076                .ok();
20077            }
20078            Err(err) => {
20079                let message = format!("Failed to open permalink: {err}");
20080
20081                anyhow::Result::<()>::Err(err).log_err();
20082
20083                if let Some(workspace) = workspace {
20084                    workspace
20085                        .update(cx, |workspace, cx| {
20086                            struct OpenPermalinkToLine;
20087
20088                            workspace.show_toast(
20089                                Toast::new(
20090                                    NotificationId::unique::<OpenPermalinkToLine>(),
20091                                    message,
20092                                ),
20093                                cx,
20094                            )
20095                        })
20096                        .ok();
20097                }
20098            }
20099        })
20100        .detach();
20101    }
20102
20103    pub fn insert_uuid_v4(
20104        &mut self,
20105        _: &InsertUuidV4,
20106        window: &mut Window,
20107        cx: &mut Context<Self>,
20108    ) {
20109        self.insert_uuid(UuidVersion::V4, window, cx);
20110    }
20111
20112    pub fn insert_uuid_v7(
20113        &mut self,
20114        _: &InsertUuidV7,
20115        window: &mut Window,
20116        cx: &mut Context<Self>,
20117    ) {
20118        self.insert_uuid(UuidVersion::V7, window, cx);
20119    }
20120
20121    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20122        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20123        self.transact(window, cx, |this, window, cx| {
20124            let edits = this
20125                .selections
20126                .all::<Point>(&this.display_snapshot(cx))
20127                .into_iter()
20128                .map(|selection| {
20129                    let uuid = match version {
20130                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20131                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20132                    };
20133
20134                    (selection.range(), uuid.to_string())
20135                });
20136            this.edit(edits, cx);
20137            this.refresh_edit_prediction(true, false, window, cx);
20138        });
20139    }
20140
20141    pub fn open_selections_in_multibuffer(
20142        &mut self,
20143        _: &OpenSelectionsInMultibuffer,
20144        window: &mut Window,
20145        cx: &mut Context<Self>,
20146    ) {
20147        let multibuffer = self.buffer.read(cx);
20148
20149        let Some(buffer) = multibuffer.as_singleton() else {
20150            return;
20151        };
20152
20153        let Some(workspace) = self.workspace() else {
20154            return;
20155        };
20156
20157        let title = multibuffer.title(cx).to_string();
20158
20159        let locations = self
20160            .selections
20161            .all_anchors(cx)
20162            .iter()
20163            .map(|selection| {
20164                (
20165                    buffer.clone(),
20166                    (selection.start.text_anchor..selection.end.text_anchor)
20167                        .to_point(buffer.read(cx)),
20168                )
20169            })
20170            .into_group_map();
20171
20172        cx.spawn_in(window, async move |_, cx| {
20173            workspace.update_in(cx, |workspace, window, cx| {
20174                Self::open_locations_in_multibuffer(
20175                    workspace,
20176                    locations,
20177                    format!("Selections for '{title}'"),
20178                    false,
20179                    MultibufferSelectionMode::All,
20180                    window,
20181                    cx,
20182                );
20183            })
20184        })
20185        .detach();
20186    }
20187
20188    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20189    /// last highlight added will be used.
20190    ///
20191    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20192    pub fn highlight_rows<T: 'static>(
20193        &mut self,
20194        range: Range<Anchor>,
20195        color: Hsla,
20196        options: RowHighlightOptions,
20197        cx: &mut Context<Self>,
20198    ) {
20199        let snapshot = self.buffer().read(cx).snapshot(cx);
20200        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20201        let ix = row_highlights.binary_search_by(|highlight| {
20202            Ordering::Equal
20203                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20204                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20205        });
20206
20207        if let Err(mut ix) = ix {
20208            let index = post_inc(&mut self.highlight_order);
20209
20210            // If this range intersects with the preceding highlight, then merge it with
20211            // the preceding highlight. Otherwise insert a new highlight.
20212            let mut merged = false;
20213            if ix > 0 {
20214                let prev_highlight = &mut row_highlights[ix - 1];
20215                if prev_highlight
20216                    .range
20217                    .end
20218                    .cmp(&range.start, &snapshot)
20219                    .is_ge()
20220                {
20221                    ix -= 1;
20222                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20223                        prev_highlight.range.end = range.end;
20224                    }
20225                    merged = true;
20226                    prev_highlight.index = index;
20227                    prev_highlight.color = color;
20228                    prev_highlight.options = options;
20229                }
20230            }
20231
20232            if !merged {
20233                row_highlights.insert(
20234                    ix,
20235                    RowHighlight {
20236                        range,
20237                        index,
20238                        color,
20239                        options,
20240                        type_id: TypeId::of::<T>(),
20241                    },
20242                );
20243            }
20244
20245            // If any of the following highlights intersect with this one, merge them.
20246            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20247                let highlight = &row_highlights[ix];
20248                if next_highlight
20249                    .range
20250                    .start
20251                    .cmp(&highlight.range.end, &snapshot)
20252                    .is_le()
20253                {
20254                    if next_highlight
20255                        .range
20256                        .end
20257                        .cmp(&highlight.range.end, &snapshot)
20258                        .is_gt()
20259                    {
20260                        row_highlights[ix].range.end = next_highlight.range.end;
20261                    }
20262                    row_highlights.remove(ix + 1);
20263                } else {
20264                    break;
20265                }
20266            }
20267        }
20268    }
20269
20270    /// Remove any highlighted row ranges of the given type that intersect the
20271    /// given ranges.
20272    pub fn remove_highlighted_rows<T: 'static>(
20273        &mut self,
20274        ranges_to_remove: Vec<Range<Anchor>>,
20275        cx: &mut Context<Self>,
20276    ) {
20277        let snapshot = self.buffer().read(cx).snapshot(cx);
20278        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20279        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20280        row_highlights.retain(|highlight| {
20281            while let Some(range_to_remove) = ranges_to_remove.peek() {
20282                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20283                    Ordering::Less | Ordering::Equal => {
20284                        ranges_to_remove.next();
20285                    }
20286                    Ordering::Greater => {
20287                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20288                            Ordering::Less | Ordering::Equal => {
20289                                return false;
20290                            }
20291                            Ordering::Greater => break,
20292                        }
20293                    }
20294                }
20295            }
20296
20297            true
20298        })
20299    }
20300
20301    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20302    pub fn clear_row_highlights<T: 'static>(&mut self) {
20303        self.highlighted_rows.remove(&TypeId::of::<T>());
20304    }
20305
20306    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20307    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20308        self.highlighted_rows
20309            .get(&TypeId::of::<T>())
20310            .map_or(&[] as &[_], |vec| vec.as_slice())
20311            .iter()
20312            .map(|highlight| (highlight.range.clone(), highlight.color))
20313    }
20314
20315    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20316    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20317    /// Allows to ignore certain kinds of highlights.
20318    pub fn highlighted_display_rows(
20319        &self,
20320        window: &mut Window,
20321        cx: &mut App,
20322    ) -> BTreeMap<DisplayRow, LineHighlight> {
20323        let snapshot = self.snapshot(window, cx);
20324        let mut used_highlight_orders = HashMap::default();
20325        self.highlighted_rows
20326            .iter()
20327            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20328            .fold(
20329                BTreeMap::<DisplayRow, LineHighlight>::new(),
20330                |mut unique_rows, highlight| {
20331                    let start = highlight.range.start.to_display_point(&snapshot);
20332                    let end = highlight.range.end.to_display_point(&snapshot);
20333                    let start_row = start.row().0;
20334                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20335                        && end.column() == 0
20336                    {
20337                        end.row().0.saturating_sub(1)
20338                    } else {
20339                        end.row().0
20340                    };
20341                    for row in start_row..=end_row {
20342                        let used_index =
20343                            used_highlight_orders.entry(row).or_insert(highlight.index);
20344                        if highlight.index >= *used_index {
20345                            *used_index = highlight.index;
20346                            unique_rows.insert(
20347                                DisplayRow(row),
20348                                LineHighlight {
20349                                    include_gutter: highlight.options.include_gutter,
20350                                    border: None,
20351                                    background: highlight.color.into(),
20352                                    type_id: Some(highlight.type_id),
20353                                },
20354                            );
20355                        }
20356                    }
20357                    unique_rows
20358                },
20359            )
20360    }
20361
20362    pub fn highlighted_display_row_for_autoscroll(
20363        &self,
20364        snapshot: &DisplaySnapshot,
20365    ) -> Option<DisplayRow> {
20366        self.highlighted_rows
20367            .values()
20368            .flat_map(|highlighted_rows| highlighted_rows.iter())
20369            .filter_map(|highlight| {
20370                if highlight.options.autoscroll {
20371                    Some(highlight.range.start.to_display_point(snapshot).row())
20372                } else {
20373                    None
20374                }
20375            })
20376            .min()
20377    }
20378
20379    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20380        self.highlight_background::<SearchWithinRange>(
20381            ranges,
20382            |colors| colors.colors().editor_document_highlight_read_background,
20383            cx,
20384        )
20385    }
20386
20387    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20388        self.breadcrumb_header = Some(new_header);
20389    }
20390
20391    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20392        self.clear_background_highlights::<SearchWithinRange>(cx);
20393    }
20394
20395    pub fn highlight_background<T: 'static>(
20396        &mut self,
20397        ranges: &[Range<Anchor>],
20398        color_fetcher: fn(&Theme) -> Hsla,
20399        cx: &mut Context<Self>,
20400    ) {
20401        self.background_highlights.insert(
20402            HighlightKey::Type(TypeId::of::<T>()),
20403            (color_fetcher, Arc::from(ranges)),
20404        );
20405        self.scrollbar_marker_state.dirty = true;
20406        cx.notify();
20407    }
20408
20409    pub fn highlight_background_key<T: 'static>(
20410        &mut self,
20411        key: usize,
20412        ranges: &[Range<Anchor>],
20413        color_fetcher: fn(&Theme) -> Hsla,
20414        cx: &mut Context<Self>,
20415    ) {
20416        self.background_highlights.insert(
20417            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20418            (color_fetcher, Arc::from(ranges)),
20419        );
20420        self.scrollbar_marker_state.dirty = true;
20421        cx.notify();
20422    }
20423
20424    pub fn clear_background_highlights<T: 'static>(
20425        &mut self,
20426        cx: &mut Context<Self>,
20427    ) -> Option<BackgroundHighlight> {
20428        let text_highlights = self
20429            .background_highlights
20430            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20431        if !text_highlights.1.is_empty() {
20432            self.scrollbar_marker_state.dirty = true;
20433            cx.notify();
20434        }
20435        Some(text_highlights)
20436    }
20437
20438    pub fn highlight_gutter<T: 'static>(
20439        &mut self,
20440        ranges: impl Into<Vec<Range<Anchor>>>,
20441        color_fetcher: fn(&App) -> Hsla,
20442        cx: &mut Context<Self>,
20443    ) {
20444        self.gutter_highlights
20445            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20446        cx.notify();
20447    }
20448
20449    pub fn clear_gutter_highlights<T: 'static>(
20450        &mut self,
20451        cx: &mut Context<Self>,
20452    ) -> Option<GutterHighlight> {
20453        cx.notify();
20454        self.gutter_highlights.remove(&TypeId::of::<T>())
20455    }
20456
20457    pub fn insert_gutter_highlight<T: 'static>(
20458        &mut self,
20459        range: Range<Anchor>,
20460        color_fetcher: fn(&App) -> Hsla,
20461        cx: &mut Context<Self>,
20462    ) {
20463        let snapshot = self.buffer().read(cx).snapshot(cx);
20464        let mut highlights = self
20465            .gutter_highlights
20466            .remove(&TypeId::of::<T>())
20467            .map(|(_, highlights)| highlights)
20468            .unwrap_or_default();
20469        let ix = highlights.binary_search_by(|highlight| {
20470            Ordering::Equal
20471                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20472                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20473        });
20474        if let Err(ix) = ix {
20475            highlights.insert(ix, range);
20476        }
20477        self.gutter_highlights
20478            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20479    }
20480
20481    pub fn remove_gutter_highlights<T: 'static>(
20482        &mut self,
20483        ranges_to_remove: Vec<Range<Anchor>>,
20484        cx: &mut Context<Self>,
20485    ) {
20486        let snapshot = self.buffer().read(cx).snapshot(cx);
20487        let Some((color_fetcher, mut gutter_highlights)) =
20488            self.gutter_highlights.remove(&TypeId::of::<T>())
20489        else {
20490            return;
20491        };
20492        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20493        gutter_highlights.retain(|highlight| {
20494            while let Some(range_to_remove) = ranges_to_remove.peek() {
20495                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20496                    Ordering::Less | Ordering::Equal => {
20497                        ranges_to_remove.next();
20498                    }
20499                    Ordering::Greater => {
20500                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20501                            Ordering::Less | Ordering::Equal => {
20502                                return false;
20503                            }
20504                            Ordering::Greater => break,
20505                        }
20506                    }
20507                }
20508            }
20509
20510            true
20511        });
20512        self.gutter_highlights
20513            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20514    }
20515
20516    #[cfg(feature = "test-support")]
20517    pub fn all_text_highlights(
20518        &self,
20519        window: &mut Window,
20520        cx: &mut Context<Self>,
20521    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20522        let snapshot = self.snapshot(window, cx);
20523        self.display_map.update(cx, |display_map, _| {
20524            display_map
20525                .all_text_highlights()
20526                .map(|highlight| {
20527                    let (style, ranges) = highlight.as_ref();
20528                    (
20529                        *style,
20530                        ranges
20531                            .iter()
20532                            .map(|range| range.clone().to_display_points(&snapshot))
20533                            .collect(),
20534                    )
20535                })
20536                .collect()
20537        })
20538    }
20539
20540    #[cfg(feature = "test-support")]
20541    pub fn all_text_background_highlights(
20542        &self,
20543        window: &mut Window,
20544        cx: &mut Context<Self>,
20545    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20546        let snapshot = self.snapshot(window, cx);
20547        let buffer = &snapshot.buffer_snapshot();
20548        let start = buffer.anchor_before(0);
20549        let end = buffer.anchor_after(buffer.len());
20550        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20551    }
20552
20553    #[cfg(any(test, feature = "test-support"))]
20554    pub fn sorted_background_highlights_in_range(
20555        &self,
20556        search_range: Range<Anchor>,
20557        display_snapshot: &DisplaySnapshot,
20558        theme: &Theme,
20559    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20560        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20561        res.sort_by(|a, b| {
20562            a.0.start
20563                .cmp(&b.0.start)
20564                .then_with(|| a.0.end.cmp(&b.0.end))
20565                .then_with(|| a.1.cmp(&b.1))
20566        });
20567        res
20568    }
20569
20570    #[cfg(feature = "test-support")]
20571    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20572        let snapshot = self.buffer().read(cx).snapshot(cx);
20573
20574        let highlights = self
20575            .background_highlights
20576            .get(&HighlightKey::Type(TypeId::of::<
20577                items::BufferSearchHighlights,
20578            >()));
20579
20580        if let Some((_color, ranges)) = highlights {
20581            ranges
20582                .iter()
20583                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20584                .collect_vec()
20585        } else {
20586            vec![]
20587        }
20588    }
20589
20590    fn document_highlights_for_position<'a>(
20591        &'a self,
20592        position: Anchor,
20593        buffer: &'a MultiBufferSnapshot,
20594    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20595        let read_highlights = self
20596            .background_highlights
20597            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20598            .map(|h| &h.1);
20599        let write_highlights = self
20600            .background_highlights
20601            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20602            .map(|h| &h.1);
20603        let left_position = position.bias_left(buffer);
20604        let right_position = position.bias_right(buffer);
20605        read_highlights
20606            .into_iter()
20607            .chain(write_highlights)
20608            .flat_map(move |ranges| {
20609                let start_ix = match ranges.binary_search_by(|probe| {
20610                    let cmp = probe.end.cmp(&left_position, buffer);
20611                    if cmp.is_ge() {
20612                        Ordering::Greater
20613                    } else {
20614                        Ordering::Less
20615                    }
20616                }) {
20617                    Ok(i) | Err(i) => i,
20618                };
20619
20620                ranges[start_ix..]
20621                    .iter()
20622                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20623            })
20624    }
20625
20626    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20627        self.background_highlights
20628            .get(&HighlightKey::Type(TypeId::of::<T>()))
20629            .is_some_and(|(_, highlights)| !highlights.is_empty())
20630    }
20631
20632    /// Returns all background highlights for a given range.
20633    ///
20634    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20635    pub fn background_highlights_in_range(
20636        &self,
20637        search_range: Range<Anchor>,
20638        display_snapshot: &DisplaySnapshot,
20639        theme: &Theme,
20640    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20641        let mut results = Vec::new();
20642        for (color_fetcher, ranges) in self.background_highlights.values() {
20643            let color = color_fetcher(theme);
20644            let start_ix = match ranges.binary_search_by(|probe| {
20645                let cmp = probe
20646                    .end
20647                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20648                if cmp.is_gt() {
20649                    Ordering::Greater
20650                } else {
20651                    Ordering::Less
20652                }
20653            }) {
20654                Ok(i) | Err(i) => i,
20655            };
20656            for range in &ranges[start_ix..] {
20657                if range
20658                    .start
20659                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20660                    .is_ge()
20661                {
20662                    break;
20663                }
20664
20665                let start = range.start.to_display_point(display_snapshot);
20666                let end = range.end.to_display_point(display_snapshot);
20667                results.push((start..end, color))
20668            }
20669        }
20670        results
20671    }
20672
20673    pub fn gutter_highlights_in_range(
20674        &self,
20675        search_range: Range<Anchor>,
20676        display_snapshot: &DisplaySnapshot,
20677        cx: &App,
20678    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20679        let mut results = Vec::new();
20680        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20681            let color = color_fetcher(cx);
20682            let start_ix = match ranges.binary_search_by(|probe| {
20683                let cmp = probe
20684                    .end
20685                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20686                if cmp.is_gt() {
20687                    Ordering::Greater
20688                } else {
20689                    Ordering::Less
20690                }
20691            }) {
20692                Ok(i) | Err(i) => i,
20693            };
20694            for range in &ranges[start_ix..] {
20695                if range
20696                    .start
20697                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20698                    .is_ge()
20699                {
20700                    break;
20701                }
20702
20703                let start = range.start.to_display_point(display_snapshot);
20704                let end = range.end.to_display_point(display_snapshot);
20705                results.push((start..end, color))
20706            }
20707        }
20708        results
20709    }
20710
20711    /// Get the text ranges corresponding to the redaction query
20712    pub fn redacted_ranges(
20713        &self,
20714        search_range: Range<Anchor>,
20715        display_snapshot: &DisplaySnapshot,
20716        cx: &App,
20717    ) -> Vec<Range<DisplayPoint>> {
20718        display_snapshot
20719            .buffer_snapshot()
20720            .redacted_ranges(search_range, |file| {
20721                if let Some(file) = file {
20722                    file.is_private()
20723                        && EditorSettings::get(
20724                            Some(SettingsLocation {
20725                                worktree_id: file.worktree_id(cx),
20726                                path: file.path().as_ref(),
20727                            }),
20728                            cx,
20729                        )
20730                        .redact_private_values
20731                } else {
20732                    false
20733                }
20734            })
20735            .map(|range| {
20736                range.start.to_display_point(display_snapshot)
20737                    ..range.end.to_display_point(display_snapshot)
20738            })
20739            .collect()
20740    }
20741
20742    pub fn highlight_text_key<T: 'static>(
20743        &mut self,
20744        key: usize,
20745        ranges: Vec<Range<Anchor>>,
20746        style: HighlightStyle,
20747        cx: &mut Context<Self>,
20748    ) {
20749        self.display_map.update(cx, |map, _| {
20750            map.highlight_text(
20751                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20752                ranges,
20753                style,
20754            );
20755        });
20756        cx.notify();
20757    }
20758
20759    pub fn highlight_text<T: 'static>(
20760        &mut self,
20761        ranges: Vec<Range<Anchor>>,
20762        style: HighlightStyle,
20763        cx: &mut Context<Self>,
20764    ) {
20765        self.display_map.update(cx, |map, _| {
20766            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20767        });
20768        cx.notify();
20769    }
20770
20771    pub fn text_highlights<'a, T: 'static>(
20772        &'a self,
20773        cx: &'a App,
20774    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20775        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20776    }
20777
20778    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20779        let cleared = self
20780            .display_map
20781            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20782        if cleared {
20783            cx.notify();
20784        }
20785    }
20786
20787    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20788        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20789            && self.focus_handle.is_focused(window)
20790    }
20791
20792    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20793        self.show_cursor_when_unfocused = is_enabled;
20794        cx.notify();
20795    }
20796
20797    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20798        cx.notify();
20799    }
20800
20801    fn on_debug_session_event(
20802        &mut self,
20803        _session: Entity<Session>,
20804        event: &SessionEvent,
20805        cx: &mut Context<Self>,
20806    ) {
20807        if let SessionEvent::InvalidateInlineValue = event {
20808            self.refresh_inline_values(cx);
20809        }
20810    }
20811
20812    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20813        let Some(project) = self.project.clone() else {
20814            return;
20815        };
20816
20817        if !self.inline_value_cache.enabled {
20818            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20819            self.splice_inlays(&inlays, Vec::new(), cx);
20820            return;
20821        }
20822
20823        let current_execution_position = self
20824            .highlighted_rows
20825            .get(&TypeId::of::<ActiveDebugLine>())
20826            .and_then(|lines| lines.last().map(|line| line.range.end));
20827
20828        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20829            let inline_values = editor
20830                .update(cx, |editor, cx| {
20831                    let Some(current_execution_position) = current_execution_position else {
20832                        return Some(Task::ready(Ok(Vec::new())));
20833                    };
20834
20835                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20836                        let snapshot = buffer.snapshot(cx);
20837
20838                        let excerpt = snapshot.excerpt_containing(
20839                            current_execution_position..current_execution_position,
20840                        )?;
20841
20842                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20843                    })?;
20844
20845                    let range =
20846                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20847
20848                    project.inline_values(buffer, range, cx)
20849                })
20850                .ok()
20851                .flatten()?
20852                .await
20853                .context("refreshing debugger inlays")
20854                .log_err()?;
20855
20856            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20857
20858            for (buffer_id, inline_value) in inline_values
20859                .into_iter()
20860                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20861            {
20862                buffer_inline_values
20863                    .entry(buffer_id)
20864                    .or_default()
20865                    .push(inline_value);
20866            }
20867
20868            editor
20869                .update(cx, |editor, cx| {
20870                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20871                    let mut new_inlays = Vec::default();
20872
20873                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20874                        let buffer_id = buffer_snapshot.remote_id();
20875                        buffer_inline_values
20876                            .get(&buffer_id)
20877                            .into_iter()
20878                            .flatten()
20879                            .for_each(|hint| {
20880                                let inlay = Inlay::debugger(
20881                                    post_inc(&mut editor.next_inlay_id),
20882                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20883                                    hint.text(),
20884                                );
20885                                if !inlay.text().chars().contains(&'\n') {
20886                                    new_inlays.push(inlay);
20887                                }
20888                            });
20889                    }
20890
20891                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20892                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20893
20894                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20895                })
20896                .ok()?;
20897            Some(())
20898        });
20899    }
20900
20901    fn on_buffer_event(
20902        &mut self,
20903        multibuffer: &Entity<MultiBuffer>,
20904        event: &multi_buffer::Event,
20905        window: &mut Window,
20906        cx: &mut Context<Self>,
20907    ) {
20908        match event {
20909            multi_buffer::Event::Edited { edited_buffer } => {
20910                self.scrollbar_marker_state.dirty = true;
20911                self.active_indent_guides_state.dirty = true;
20912                self.refresh_active_diagnostics(cx);
20913                self.refresh_code_actions(window, cx);
20914                self.refresh_selected_text_highlights(true, window, cx);
20915                self.refresh_single_line_folds(window, cx);
20916                self.refresh_matching_bracket_highlights(window, cx);
20917                if self.has_active_edit_prediction() {
20918                    self.update_visible_edit_prediction(window, cx);
20919                }
20920
20921                if let Some(buffer) = edited_buffer {
20922                    if buffer.read(cx).file().is_none() {
20923                        cx.emit(EditorEvent::TitleChanged);
20924                    }
20925
20926                    if self.project.is_some() {
20927                        let buffer_id = buffer.read(cx).remote_id();
20928                        self.register_buffer(buffer_id, cx);
20929                        self.update_lsp_data(Some(buffer_id), window, cx);
20930                        self.refresh_inlay_hints(
20931                            InlayHintRefreshReason::BufferEdited(buffer_id),
20932                            cx,
20933                        );
20934                    }
20935                }
20936
20937                cx.emit(EditorEvent::BufferEdited);
20938                cx.emit(SearchEvent::MatchesInvalidated);
20939
20940                let Some(project) = &self.project else { return };
20941                let (telemetry, is_via_ssh) = {
20942                    let project = project.read(cx);
20943                    let telemetry = project.client().telemetry().clone();
20944                    let is_via_ssh = project.is_via_remote_server();
20945                    (telemetry, is_via_ssh)
20946                };
20947                telemetry.log_edit_event("editor", is_via_ssh);
20948            }
20949            multi_buffer::Event::ExcerptsAdded {
20950                buffer,
20951                predecessor,
20952                excerpts,
20953            } => {
20954                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20955                let buffer_id = buffer.read(cx).remote_id();
20956                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20957                    && let Some(project) = &self.project
20958                {
20959                    update_uncommitted_diff_for_buffer(
20960                        cx.entity(),
20961                        project,
20962                        [buffer.clone()],
20963                        self.buffer.clone(),
20964                        cx,
20965                    )
20966                    .detach();
20967                }
20968                self.update_lsp_data(Some(buffer_id), window, cx);
20969                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20970                cx.emit(EditorEvent::ExcerptsAdded {
20971                    buffer: buffer.clone(),
20972                    predecessor: *predecessor,
20973                    excerpts: excerpts.clone(),
20974                });
20975            }
20976            multi_buffer::Event::ExcerptsRemoved {
20977                ids,
20978                removed_buffer_ids,
20979            } => {
20980                if let Some(inlay_hints) = &mut self.inlay_hints {
20981                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
20982                }
20983                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20984                for buffer_id in removed_buffer_ids {
20985                    self.registered_buffers.remove(buffer_id);
20986                }
20987                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20988                cx.emit(EditorEvent::ExcerptsRemoved {
20989                    ids: ids.clone(),
20990                    removed_buffer_ids: removed_buffer_ids.clone(),
20991                });
20992            }
20993            multi_buffer::Event::ExcerptsEdited {
20994                excerpt_ids,
20995                buffer_ids,
20996            } => {
20997                self.display_map.update(cx, |map, cx| {
20998                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20999                });
21000                cx.emit(EditorEvent::ExcerptsEdited {
21001                    ids: excerpt_ids.clone(),
21002                });
21003            }
21004            multi_buffer::Event::ExcerptsExpanded { ids } => {
21005                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21006                self.refresh_document_highlights(cx);
21007                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21008            }
21009            multi_buffer::Event::Reparsed(buffer_id) => {
21010                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21011                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21012
21013                cx.emit(EditorEvent::Reparsed(*buffer_id));
21014            }
21015            multi_buffer::Event::DiffHunksToggled => {
21016                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21017            }
21018            multi_buffer::Event::LanguageChanged(buffer_id) => {
21019                self.registered_buffers.remove(&buffer_id);
21020                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21021                cx.emit(EditorEvent::Reparsed(*buffer_id));
21022                cx.notify();
21023            }
21024            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21025            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21026            multi_buffer::Event::FileHandleChanged
21027            | multi_buffer::Event::Reloaded
21028            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21029            multi_buffer::Event::DiagnosticsUpdated => {
21030                self.update_diagnostics_state(window, cx);
21031            }
21032            _ => {}
21033        };
21034    }
21035
21036    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21037        if !self.diagnostics_enabled() {
21038            return;
21039        }
21040        self.refresh_active_diagnostics(cx);
21041        self.refresh_inline_diagnostics(true, window, cx);
21042        self.scrollbar_marker_state.dirty = true;
21043        cx.notify();
21044    }
21045
21046    pub fn start_temporary_diff_override(&mut self) {
21047        self.load_diff_task.take();
21048        self.temporary_diff_override = true;
21049    }
21050
21051    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21052        self.temporary_diff_override = false;
21053        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21054        self.buffer.update(cx, |buffer, cx| {
21055            buffer.set_all_diff_hunks_collapsed(cx);
21056        });
21057
21058        if let Some(project) = self.project.clone() {
21059            self.load_diff_task = Some(
21060                update_uncommitted_diff_for_buffer(
21061                    cx.entity(),
21062                    &project,
21063                    self.buffer.read(cx).all_buffers(),
21064                    self.buffer.clone(),
21065                    cx,
21066                )
21067                .shared(),
21068            );
21069        }
21070    }
21071
21072    fn on_display_map_changed(
21073        &mut self,
21074        _: Entity<DisplayMap>,
21075        _: &mut Window,
21076        cx: &mut Context<Self>,
21077    ) {
21078        cx.notify();
21079    }
21080
21081    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21082        if self.diagnostics_enabled() {
21083            let new_severity = EditorSettings::get_global(cx)
21084                .diagnostics_max_severity
21085                .unwrap_or(DiagnosticSeverity::Hint);
21086            self.set_max_diagnostics_severity(new_severity, cx);
21087        }
21088        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21089        self.update_edit_prediction_settings(cx);
21090        self.refresh_edit_prediction(true, false, window, cx);
21091        self.refresh_inline_values(cx);
21092        self.refresh_inlay_hints(
21093            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21094                self.selections.newest_anchor().head(),
21095                &self.buffer.read(cx).snapshot(cx),
21096                cx,
21097            )),
21098            cx,
21099        );
21100
21101        let old_cursor_shape = self.cursor_shape;
21102        let old_show_breadcrumbs = self.show_breadcrumbs;
21103
21104        {
21105            let editor_settings = EditorSettings::get_global(cx);
21106            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21107            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21108            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21109            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21110        }
21111
21112        if old_cursor_shape != self.cursor_shape {
21113            cx.emit(EditorEvent::CursorShapeChanged);
21114        }
21115
21116        if old_show_breadcrumbs != self.show_breadcrumbs {
21117            cx.emit(EditorEvent::BreadcrumbsChanged);
21118        }
21119
21120        let project_settings = ProjectSettings::get_global(cx);
21121        self.serialize_dirty_buffers =
21122            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21123
21124        if self.mode.is_full() {
21125            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21126            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21127            if self.show_inline_diagnostics != show_inline_diagnostics {
21128                self.show_inline_diagnostics = show_inline_diagnostics;
21129                self.refresh_inline_diagnostics(false, window, cx);
21130            }
21131
21132            if self.git_blame_inline_enabled != inline_blame_enabled {
21133                self.toggle_git_blame_inline_internal(false, window, cx);
21134            }
21135
21136            let minimap_settings = EditorSettings::get_global(cx).minimap;
21137            if self.minimap_visibility != MinimapVisibility::Disabled {
21138                if self.minimap_visibility.settings_visibility()
21139                    != minimap_settings.minimap_enabled()
21140                {
21141                    self.set_minimap_visibility(
21142                        MinimapVisibility::for_mode(self.mode(), cx),
21143                        window,
21144                        cx,
21145                    );
21146                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21147                    minimap_entity.update(cx, |minimap_editor, cx| {
21148                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21149                    })
21150                }
21151            }
21152        }
21153
21154        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21155            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21156        }) {
21157            if !inlay_splice.is_empty() {
21158                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21159            }
21160            self.refresh_colors_for_visible_range(None, window, cx);
21161        }
21162
21163        cx.notify();
21164    }
21165
21166    pub fn set_searchable(&mut self, searchable: bool) {
21167        self.searchable = searchable;
21168    }
21169
21170    pub fn searchable(&self) -> bool {
21171        self.searchable
21172    }
21173
21174    pub fn open_excerpts_in_split(
21175        &mut self,
21176        _: &OpenExcerptsSplit,
21177        window: &mut Window,
21178        cx: &mut Context<Self>,
21179    ) {
21180        self.open_excerpts_common(None, true, window, cx)
21181    }
21182
21183    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21184        self.open_excerpts_common(None, false, window, cx)
21185    }
21186
21187    fn open_excerpts_common(
21188        &mut self,
21189        jump_data: Option<JumpData>,
21190        split: bool,
21191        window: &mut Window,
21192        cx: &mut Context<Self>,
21193    ) {
21194        let Some(workspace) = self.workspace() else {
21195            cx.propagate();
21196            return;
21197        };
21198
21199        if self.buffer.read(cx).is_singleton() {
21200            cx.propagate();
21201            return;
21202        }
21203
21204        let mut new_selections_by_buffer = HashMap::default();
21205        match &jump_data {
21206            Some(JumpData::MultiBufferPoint {
21207                excerpt_id,
21208                position,
21209                anchor,
21210                line_offset_from_top,
21211            }) => {
21212                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21213                if let Some(buffer) = multi_buffer_snapshot
21214                    .buffer_id_for_excerpt(*excerpt_id)
21215                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21216                {
21217                    let buffer_snapshot = buffer.read(cx).snapshot();
21218                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21219                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21220                    } else {
21221                        buffer_snapshot.clip_point(*position, Bias::Left)
21222                    };
21223                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21224                    new_selections_by_buffer.insert(
21225                        buffer,
21226                        (
21227                            vec![jump_to_offset..jump_to_offset],
21228                            Some(*line_offset_from_top),
21229                        ),
21230                    );
21231                }
21232            }
21233            Some(JumpData::MultiBufferRow {
21234                row,
21235                line_offset_from_top,
21236            }) => {
21237                let point = MultiBufferPoint::new(row.0, 0);
21238                if let Some((buffer, buffer_point, _)) =
21239                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21240                {
21241                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21242                    new_selections_by_buffer
21243                        .entry(buffer)
21244                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21245                        .0
21246                        .push(buffer_offset..buffer_offset)
21247                }
21248            }
21249            None => {
21250                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21251                let multi_buffer = self.buffer.read(cx);
21252                for selection in selections {
21253                    for (snapshot, range, _, anchor) in multi_buffer
21254                        .snapshot(cx)
21255                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21256                    {
21257                        if let Some(anchor) = anchor {
21258                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21259                            else {
21260                                continue;
21261                            };
21262                            let offset = text::ToOffset::to_offset(
21263                                &anchor.text_anchor,
21264                                &buffer_handle.read(cx).snapshot(),
21265                            );
21266                            let range = offset..offset;
21267                            new_selections_by_buffer
21268                                .entry(buffer_handle)
21269                                .or_insert((Vec::new(), None))
21270                                .0
21271                                .push(range)
21272                        } else {
21273                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21274                            else {
21275                                continue;
21276                            };
21277                            new_selections_by_buffer
21278                                .entry(buffer_handle)
21279                                .or_insert((Vec::new(), None))
21280                                .0
21281                                .push(range)
21282                        }
21283                    }
21284                }
21285            }
21286        }
21287
21288        new_selections_by_buffer
21289            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21290
21291        if new_selections_by_buffer.is_empty() {
21292            return;
21293        }
21294
21295        // We defer the pane interaction because we ourselves are a workspace item
21296        // and activating a new item causes the pane to call a method on us reentrantly,
21297        // which panics if we're on the stack.
21298        window.defer(cx, move |window, cx| {
21299            workspace.update(cx, |workspace, cx| {
21300                let pane = if split {
21301                    workspace.adjacent_pane(window, cx)
21302                } else {
21303                    workspace.active_pane().clone()
21304                };
21305
21306                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21307                    let editor = buffer
21308                        .read(cx)
21309                        .file()
21310                        .is_none()
21311                        .then(|| {
21312                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21313                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21314                            // Instead, we try to activate the existing editor in the pane first.
21315                            let (editor, pane_item_index) =
21316                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21317                                    let editor = item.downcast::<Editor>()?;
21318                                    let singleton_buffer =
21319                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21320                                    if singleton_buffer == buffer {
21321                                        Some((editor, i))
21322                                    } else {
21323                                        None
21324                                    }
21325                                })?;
21326                            pane.update(cx, |pane, cx| {
21327                                pane.activate_item(pane_item_index, true, true, window, cx)
21328                            });
21329                            Some(editor)
21330                        })
21331                        .flatten()
21332                        .unwrap_or_else(|| {
21333                            workspace.open_project_item::<Self>(
21334                                pane.clone(),
21335                                buffer,
21336                                true,
21337                                true,
21338                                window,
21339                                cx,
21340                            )
21341                        });
21342
21343                    editor.update(cx, |editor, cx| {
21344                        let autoscroll = match scroll_offset {
21345                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21346                            None => Autoscroll::newest(),
21347                        };
21348                        let nav_history = editor.nav_history.take();
21349                        editor.change_selections(
21350                            SelectionEffects::scroll(autoscroll),
21351                            window,
21352                            cx,
21353                            |s| {
21354                                s.select_ranges(ranges);
21355                            },
21356                        );
21357                        editor.nav_history = nav_history;
21358                    });
21359                }
21360            })
21361        });
21362    }
21363
21364    // For now, don't allow opening excerpts in buffers that aren't backed by
21365    // regular project files.
21366    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21367        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21368    }
21369
21370    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21371        let snapshot = self.buffer.read(cx).read(cx);
21372        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21373        Some(
21374            ranges
21375                .iter()
21376                .map(move |range| {
21377                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21378                })
21379                .collect(),
21380        )
21381    }
21382
21383    fn selection_replacement_ranges(
21384        &self,
21385        range: Range<OffsetUtf16>,
21386        cx: &mut App,
21387    ) -> Vec<Range<OffsetUtf16>> {
21388        let selections = self
21389            .selections
21390            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21391        let newest_selection = selections
21392            .iter()
21393            .max_by_key(|selection| selection.id)
21394            .unwrap();
21395        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21396        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21397        let snapshot = self.buffer.read(cx).read(cx);
21398        selections
21399            .into_iter()
21400            .map(|mut selection| {
21401                selection.start.0 =
21402                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21403                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21404                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21405                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21406            })
21407            .collect()
21408    }
21409
21410    fn report_editor_event(
21411        &self,
21412        reported_event: ReportEditorEvent,
21413        file_extension: Option<String>,
21414        cx: &App,
21415    ) {
21416        if cfg!(any(test, feature = "test-support")) {
21417            return;
21418        }
21419
21420        let Some(project) = &self.project else { return };
21421
21422        // If None, we are in a file without an extension
21423        let file = self
21424            .buffer
21425            .read(cx)
21426            .as_singleton()
21427            .and_then(|b| b.read(cx).file());
21428        let file_extension = file_extension.or(file
21429            .as_ref()
21430            .and_then(|file| Path::new(file.file_name(cx)).extension())
21431            .and_then(|e| e.to_str())
21432            .map(|a| a.to_string()));
21433
21434        let vim_mode = vim_enabled(cx);
21435
21436        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21437        let copilot_enabled = edit_predictions_provider
21438            == language::language_settings::EditPredictionProvider::Copilot;
21439        let copilot_enabled_for_language = self
21440            .buffer
21441            .read(cx)
21442            .language_settings(cx)
21443            .show_edit_predictions;
21444
21445        let project = project.read(cx);
21446        let event_type = reported_event.event_type();
21447
21448        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21449            telemetry::event!(
21450                event_type,
21451                type = if auto_saved {"autosave"} else {"manual"},
21452                file_extension,
21453                vim_mode,
21454                copilot_enabled,
21455                copilot_enabled_for_language,
21456                edit_predictions_provider,
21457                is_via_ssh = project.is_via_remote_server(),
21458            );
21459        } else {
21460            telemetry::event!(
21461                event_type,
21462                file_extension,
21463                vim_mode,
21464                copilot_enabled,
21465                copilot_enabled_for_language,
21466                edit_predictions_provider,
21467                is_via_ssh = project.is_via_remote_server(),
21468            );
21469        };
21470    }
21471
21472    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21473    /// with each line being an array of {text, highlight} objects.
21474    fn copy_highlight_json(
21475        &mut self,
21476        _: &CopyHighlightJson,
21477        window: &mut Window,
21478        cx: &mut Context<Self>,
21479    ) {
21480        #[derive(Serialize)]
21481        struct Chunk<'a> {
21482            text: String,
21483            highlight: Option<&'a str>,
21484        }
21485
21486        let snapshot = self.buffer.read(cx).snapshot(cx);
21487        let range = self
21488            .selected_text_range(false, window, cx)
21489            .and_then(|selection| {
21490                if selection.range.is_empty() {
21491                    None
21492                } else {
21493                    Some(
21494                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21495                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21496                    )
21497                }
21498            })
21499            .unwrap_or_else(|| 0..snapshot.len());
21500
21501        let chunks = snapshot.chunks(range, true);
21502        let mut lines = Vec::new();
21503        let mut line: VecDeque<Chunk> = VecDeque::new();
21504
21505        let Some(style) = self.style.as_ref() else {
21506            return;
21507        };
21508
21509        for chunk in chunks {
21510            let highlight = chunk
21511                .syntax_highlight_id
21512                .and_then(|id| id.name(&style.syntax));
21513            let mut chunk_lines = chunk.text.split('\n').peekable();
21514            while let Some(text) = chunk_lines.next() {
21515                let mut merged_with_last_token = false;
21516                if let Some(last_token) = line.back_mut()
21517                    && last_token.highlight == highlight
21518                {
21519                    last_token.text.push_str(text);
21520                    merged_with_last_token = true;
21521                }
21522
21523                if !merged_with_last_token {
21524                    line.push_back(Chunk {
21525                        text: text.into(),
21526                        highlight,
21527                    });
21528                }
21529
21530                if chunk_lines.peek().is_some() {
21531                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21532                        line.pop_front();
21533                    }
21534                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21535                        line.pop_back();
21536                    }
21537
21538                    lines.push(mem::take(&mut line));
21539                }
21540            }
21541        }
21542
21543        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21544            return;
21545        };
21546        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21547    }
21548
21549    pub fn open_context_menu(
21550        &mut self,
21551        _: &OpenContextMenu,
21552        window: &mut Window,
21553        cx: &mut Context<Self>,
21554    ) {
21555        self.request_autoscroll(Autoscroll::newest(), cx);
21556        let position = self
21557            .selections
21558            .newest_display(&self.display_snapshot(cx))
21559            .start;
21560        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21561    }
21562
21563    pub fn replay_insert_event(
21564        &mut self,
21565        text: &str,
21566        relative_utf16_range: Option<Range<isize>>,
21567        window: &mut Window,
21568        cx: &mut Context<Self>,
21569    ) {
21570        if !self.input_enabled {
21571            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21572            return;
21573        }
21574        if let Some(relative_utf16_range) = relative_utf16_range {
21575            let selections = self
21576                .selections
21577                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21578            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21579                let new_ranges = selections.into_iter().map(|range| {
21580                    let start = OffsetUtf16(
21581                        range
21582                            .head()
21583                            .0
21584                            .saturating_add_signed(relative_utf16_range.start),
21585                    );
21586                    let end = OffsetUtf16(
21587                        range
21588                            .head()
21589                            .0
21590                            .saturating_add_signed(relative_utf16_range.end),
21591                    );
21592                    start..end
21593                });
21594                s.select_ranges(new_ranges);
21595            });
21596        }
21597
21598        self.handle_input(text, window, cx);
21599    }
21600
21601    pub fn is_focused(&self, window: &Window) -> bool {
21602        self.focus_handle.is_focused(window)
21603    }
21604
21605    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21606        cx.emit(EditorEvent::Focused);
21607
21608        if let Some(descendant) = self
21609            .last_focused_descendant
21610            .take()
21611            .and_then(|descendant| descendant.upgrade())
21612        {
21613            window.focus(&descendant);
21614        } else {
21615            if let Some(blame) = self.blame.as_ref() {
21616                blame.update(cx, GitBlame::focus)
21617            }
21618
21619            self.blink_manager.update(cx, BlinkManager::enable);
21620            self.show_cursor_names(window, cx);
21621            self.buffer.update(cx, |buffer, cx| {
21622                buffer.finalize_last_transaction(cx);
21623                if self.leader_id.is_none() {
21624                    buffer.set_active_selections(
21625                        &self.selections.disjoint_anchors_arc(),
21626                        self.selections.line_mode(),
21627                        self.cursor_shape,
21628                        cx,
21629                    );
21630                }
21631            });
21632        }
21633    }
21634
21635    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21636        cx.emit(EditorEvent::FocusedIn)
21637    }
21638
21639    fn handle_focus_out(
21640        &mut self,
21641        event: FocusOutEvent,
21642        _window: &mut Window,
21643        cx: &mut Context<Self>,
21644    ) {
21645        if event.blurred != self.focus_handle {
21646            self.last_focused_descendant = Some(event.blurred);
21647        }
21648        self.selection_drag_state = SelectionDragState::None;
21649        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21650    }
21651
21652    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21653        self.blink_manager.update(cx, BlinkManager::disable);
21654        self.buffer
21655            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21656
21657        if let Some(blame) = self.blame.as_ref() {
21658            blame.update(cx, GitBlame::blur)
21659        }
21660        if !self.hover_state.focused(window, cx) {
21661            hide_hover(self, cx);
21662        }
21663        if !self
21664            .context_menu
21665            .borrow()
21666            .as_ref()
21667            .is_some_and(|context_menu| context_menu.focused(window, cx))
21668        {
21669            self.hide_context_menu(window, cx);
21670        }
21671        self.take_active_edit_prediction(cx);
21672        cx.emit(EditorEvent::Blurred);
21673        cx.notify();
21674    }
21675
21676    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21677        let mut pending: String = window
21678            .pending_input_keystrokes()
21679            .into_iter()
21680            .flatten()
21681            .filter_map(|keystroke| {
21682                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21683                    keystroke.key_char.clone()
21684                } else {
21685                    None
21686                }
21687            })
21688            .collect();
21689
21690        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21691            pending = "".to_string();
21692        }
21693
21694        let existing_pending = self
21695            .text_highlights::<PendingInput>(cx)
21696            .map(|(_, ranges)| ranges.to_vec());
21697        if existing_pending.is_none() && pending.is_empty() {
21698            return;
21699        }
21700        let transaction =
21701            self.transact(window, cx, |this, window, cx| {
21702                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21703                let edits = selections
21704                    .iter()
21705                    .map(|selection| (selection.end..selection.end, pending.clone()));
21706                this.edit(edits, cx);
21707                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21708                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21709                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21710                    }));
21711                });
21712                if let Some(existing_ranges) = existing_pending {
21713                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21714                    this.edit(edits, cx);
21715                }
21716            });
21717
21718        let snapshot = self.snapshot(window, cx);
21719        let ranges = self
21720            .selections
21721            .all::<usize>(&snapshot.display_snapshot)
21722            .into_iter()
21723            .map(|selection| {
21724                snapshot.buffer_snapshot().anchor_after(selection.end)
21725                    ..snapshot
21726                        .buffer_snapshot()
21727                        .anchor_before(selection.end + pending.len())
21728            })
21729            .collect();
21730
21731        if pending.is_empty() {
21732            self.clear_highlights::<PendingInput>(cx);
21733        } else {
21734            self.highlight_text::<PendingInput>(
21735                ranges,
21736                HighlightStyle {
21737                    underline: Some(UnderlineStyle {
21738                        thickness: px(1.),
21739                        color: None,
21740                        wavy: false,
21741                    }),
21742                    ..Default::default()
21743                },
21744                cx,
21745            );
21746        }
21747
21748        self.ime_transaction = self.ime_transaction.or(transaction);
21749        if let Some(transaction) = self.ime_transaction {
21750            self.buffer.update(cx, |buffer, cx| {
21751                buffer.group_until_transaction(transaction, cx);
21752            });
21753        }
21754
21755        if self.text_highlights::<PendingInput>(cx).is_none() {
21756            self.ime_transaction.take();
21757        }
21758    }
21759
21760    pub fn register_action_renderer(
21761        &mut self,
21762        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21763    ) -> Subscription {
21764        let id = self.next_editor_action_id.post_inc();
21765        self.editor_actions
21766            .borrow_mut()
21767            .insert(id, Box::new(listener));
21768
21769        let editor_actions = self.editor_actions.clone();
21770        Subscription::new(move || {
21771            editor_actions.borrow_mut().remove(&id);
21772        })
21773    }
21774
21775    pub fn register_action<A: Action>(
21776        &mut self,
21777        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21778    ) -> Subscription {
21779        let id = self.next_editor_action_id.post_inc();
21780        let listener = Arc::new(listener);
21781        self.editor_actions.borrow_mut().insert(
21782            id,
21783            Box::new(move |_, window, _| {
21784                let listener = listener.clone();
21785                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21786                    let action = action.downcast_ref().unwrap();
21787                    if phase == DispatchPhase::Bubble {
21788                        listener(action, window, cx)
21789                    }
21790                })
21791            }),
21792        );
21793
21794        let editor_actions = self.editor_actions.clone();
21795        Subscription::new(move || {
21796            editor_actions.borrow_mut().remove(&id);
21797        })
21798    }
21799
21800    pub fn file_header_size(&self) -> u32 {
21801        FILE_HEADER_HEIGHT
21802    }
21803
21804    pub fn restore(
21805        &mut self,
21806        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21807        window: &mut Window,
21808        cx: &mut Context<Self>,
21809    ) {
21810        let workspace = self.workspace();
21811        let project = self.project();
21812        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21813            let mut tasks = Vec::new();
21814            for (buffer_id, changes) in revert_changes {
21815                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21816                    buffer.update(cx, |buffer, cx| {
21817                        buffer.edit(
21818                            changes
21819                                .into_iter()
21820                                .map(|(range, text)| (range, text.to_string())),
21821                            None,
21822                            cx,
21823                        );
21824                    });
21825
21826                    if let Some(project) =
21827                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21828                    {
21829                        project.update(cx, |project, cx| {
21830                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21831                        })
21832                    }
21833                }
21834            }
21835            tasks
21836        });
21837        cx.spawn_in(window, async move |_, cx| {
21838            for (buffer, task) in save_tasks {
21839                let result = task.await;
21840                if result.is_err() {
21841                    let Some(path) = buffer
21842                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21843                        .ok()
21844                    else {
21845                        continue;
21846                    };
21847                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21848                        let Some(task) = cx
21849                            .update_window_entity(workspace, |workspace, window, cx| {
21850                                workspace
21851                                    .open_path_preview(path, None, false, false, false, window, cx)
21852                            })
21853                            .ok()
21854                        else {
21855                            continue;
21856                        };
21857                        task.await.log_err();
21858                    }
21859                }
21860            }
21861        })
21862        .detach();
21863        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21864            selections.refresh()
21865        });
21866    }
21867
21868    pub fn to_pixel_point(
21869        &self,
21870        source: multi_buffer::Anchor,
21871        editor_snapshot: &EditorSnapshot,
21872        window: &mut Window,
21873    ) -> Option<gpui::Point<Pixels>> {
21874        let source_point = source.to_display_point(editor_snapshot);
21875        self.display_to_pixel_point(source_point, editor_snapshot, window)
21876    }
21877
21878    pub fn display_to_pixel_point(
21879        &self,
21880        source: DisplayPoint,
21881        editor_snapshot: &EditorSnapshot,
21882        window: &mut Window,
21883    ) -> Option<gpui::Point<Pixels>> {
21884        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21885        let text_layout_details = self.text_layout_details(window);
21886        let scroll_top = text_layout_details
21887            .scroll_anchor
21888            .scroll_position(editor_snapshot)
21889            .y;
21890
21891        if source.row().as_f64() < scroll_top.floor() {
21892            return None;
21893        }
21894        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21895        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21896        Some(gpui::Point::new(source_x, source_y))
21897    }
21898
21899    pub fn has_visible_completions_menu(&self) -> bool {
21900        !self.edit_prediction_preview_is_active()
21901            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21902                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21903            })
21904    }
21905
21906    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21907        if self.mode.is_minimap() {
21908            return;
21909        }
21910        self.addons
21911            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21912    }
21913
21914    pub fn unregister_addon<T: Addon>(&mut self) {
21915        self.addons.remove(&std::any::TypeId::of::<T>());
21916    }
21917
21918    pub fn addon<T: Addon>(&self) -> Option<&T> {
21919        let type_id = std::any::TypeId::of::<T>();
21920        self.addons
21921            .get(&type_id)
21922            .and_then(|item| item.to_any().downcast_ref::<T>())
21923    }
21924
21925    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21926        let type_id = std::any::TypeId::of::<T>();
21927        self.addons
21928            .get_mut(&type_id)
21929            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21930    }
21931
21932    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21933        let text_layout_details = self.text_layout_details(window);
21934        let style = &text_layout_details.editor_style;
21935        let font_id = window.text_system().resolve_font(&style.text.font());
21936        let font_size = style.text.font_size.to_pixels(window.rem_size());
21937        let line_height = style.text.line_height_in_pixels(window.rem_size());
21938        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21939        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21940
21941        CharacterDimensions {
21942            em_width,
21943            em_advance,
21944            line_height,
21945        }
21946    }
21947
21948    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21949        self.load_diff_task.clone()
21950    }
21951
21952    fn read_metadata_from_db(
21953        &mut self,
21954        item_id: u64,
21955        workspace_id: WorkspaceId,
21956        window: &mut Window,
21957        cx: &mut Context<Editor>,
21958    ) {
21959        if self.buffer_kind(cx) == ItemBufferKind::Singleton
21960            && !self.mode.is_minimap()
21961            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21962        {
21963            let buffer_snapshot = OnceCell::new();
21964
21965            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21966                && !folds.is_empty()
21967            {
21968                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21969                self.fold_ranges(
21970                    folds
21971                        .into_iter()
21972                        .map(|(start, end)| {
21973                            snapshot.clip_offset(start, Bias::Left)
21974                                ..snapshot.clip_offset(end, Bias::Right)
21975                        })
21976                        .collect(),
21977                    false,
21978                    window,
21979                    cx,
21980                );
21981            }
21982
21983            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21984                && !selections.is_empty()
21985            {
21986                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21987                // skip adding the initial selection to selection history
21988                self.selection_history.mode = SelectionHistoryMode::Skipping;
21989                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21990                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21991                        snapshot.clip_offset(start, Bias::Left)
21992                            ..snapshot.clip_offset(end, Bias::Right)
21993                    }));
21994                });
21995                self.selection_history.mode = SelectionHistoryMode::Normal;
21996            };
21997        }
21998
21999        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22000    }
22001
22002    fn update_lsp_data(
22003        &mut self,
22004        for_buffer: Option<BufferId>,
22005        window: &mut Window,
22006        cx: &mut Context<'_, Self>,
22007    ) {
22008        self.pull_diagnostics(for_buffer, window, cx);
22009        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22010    }
22011
22012    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22013        if self.ignore_lsp_data() {
22014            return;
22015        }
22016        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22017            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22018        }
22019    }
22020
22021    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22022        if !self.registered_buffers.contains_key(&buffer_id)
22023            && let Some(project) = self.project.as_ref()
22024        {
22025            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22026                project.update(cx, |project, cx| {
22027                    self.registered_buffers.insert(
22028                        buffer_id,
22029                        project.register_buffer_with_language_servers(&buffer, cx),
22030                    );
22031                });
22032            } else {
22033                self.registered_buffers.remove(&buffer_id);
22034            }
22035        }
22036    }
22037
22038    fn ignore_lsp_data(&self) -> bool {
22039        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22040        // skip any LSP updates for it.
22041        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22042    }
22043}
22044
22045fn edit_for_markdown_paste<'a>(
22046    buffer: &MultiBufferSnapshot,
22047    range: Range<usize>,
22048    to_insert: &'a str,
22049    url: Option<url::Url>,
22050) -> (Range<usize>, Cow<'a, str>) {
22051    if url.is_none() {
22052        return (range, Cow::Borrowed(to_insert));
22053    };
22054
22055    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22056
22057    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22058        Cow::Borrowed(to_insert)
22059    } else {
22060        Cow::Owned(format!("[{old_text}]({to_insert})"))
22061    };
22062    (range, new_text)
22063}
22064
22065fn vim_enabled(cx: &App) -> bool {
22066    vim_mode_setting::VimModeSetting::try_get(cx)
22067        .map(|vim_mode| vim_mode.0)
22068        .unwrap_or(false)
22069}
22070
22071fn process_completion_for_edit(
22072    completion: &Completion,
22073    intent: CompletionIntent,
22074    buffer: &Entity<Buffer>,
22075    cursor_position: &text::Anchor,
22076    cx: &mut Context<Editor>,
22077) -> CompletionEdit {
22078    let buffer = buffer.read(cx);
22079    let buffer_snapshot = buffer.snapshot();
22080    let (snippet, new_text) = if completion.is_snippet() {
22081        let mut snippet_source = completion.new_text.clone();
22082        // Workaround for typescript language server issues so that methods don't expand within
22083        // strings and functions with type expressions. The previous point is used because the query
22084        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22085        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22086        let previous_point = if previous_point.column > 0 {
22087            cursor_position.to_previous_offset(&buffer_snapshot)
22088        } else {
22089            cursor_position.to_offset(&buffer_snapshot)
22090        };
22091        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22092            && scope.prefers_label_for_snippet_in_completion()
22093            && let Some(label) = completion.label()
22094            && matches!(
22095                completion.kind(),
22096                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22097            )
22098        {
22099            snippet_source = label;
22100        }
22101        match Snippet::parse(&snippet_source).log_err() {
22102            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22103            None => (None, completion.new_text.clone()),
22104        }
22105    } else {
22106        (None, completion.new_text.clone())
22107    };
22108
22109    let mut range_to_replace = {
22110        let replace_range = &completion.replace_range;
22111        if let CompletionSource::Lsp {
22112            insert_range: Some(insert_range),
22113            ..
22114        } = &completion.source
22115        {
22116            debug_assert_eq!(
22117                insert_range.start, replace_range.start,
22118                "insert_range and replace_range should start at the same position"
22119            );
22120            debug_assert!(
22121                insert_range
22122                    .start
22123                    .cmp(cursor_position, &buffer_snapshot)
22124                    .is_le(),
22125                "insert_range should start before or at cursor position"
22126            );
22127            debug_assert!(
22128                replace_range
22129                    .start
22130                    .cmp(cursor_position, &buffer_snapshot)
22131                    .is_le(),
22132                "replace_range should start before or at cursor position"
22133            );
22134
22135            let should_replace = match intent {
22136                CompletionIntent::CompleteWithInsert => false,
22137                CompletionIntent::CompleteWithReplace => true,
22138                CompletionIntent::Complete | CompletionIntent::Compose => {
22139                    let insert_mode =
22140                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22141                            .completions
22142                            .lsp_insert_mode;
22143                    match insert_mode {
22144                        LspInsertMode::Insert => false,
22145                        LspInsertMode::Replace => true,
22146                        LspInsertMode::ReplaceSubsequence => {
22147                            let mut text_to_replace = buffer.chars_for_range(
22148                                buffer.anchor_before(replace_range.start)
22149                                    ..buffer.anchor_after(replace_range.end),
22150                            );
22151                            let mut current_needle = text_to_replace.next();
22152                            for haystack_ch in completion.label.text.chars() {
22153                                if let Some(needle_ch) = current_needle
22154                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22155                                {
22156                                    current_needle = text_to_replace.next();
22157                                }
22158                            }
22159                            current_needle.is_none()
22160                        }
22161                        LspInsertMode::ReplaceSuffix => {
22162                            if replace_range
22163                                .end
22164                                .cmp(cursor_position, &buffer_snapshot)
22165                                .is_gt()
22166                            {
22167                                let range_after_cursor = *cursor_position..replace_range.end;
22168                                let text_after_cursor = buffer
22169                                    .text_for_range(
22170                                        buffer.anchor_before(range_after_cursor.start)
22171                                            ..buffer.anchor_after(range_after_cursor.end),
22172                                    )
22173                                    .collect::<String>()
22174                                    .to_ascii_lowercase();
22175                                completion
22176                                    .label
22177                                    .text
22178                                    .to_ascii_lowercase()
22179                                    .ends_with(&text_after_cursor)
22180                            } else {
22181                                true
22182                            }
22183                        }
22184                    }
22185                }
22186            };
22187
22188            if should_replace {
22189                replace_range.clone()
22190            } else {
22191                insert_range.clone()
22192            }
22193        } else {
22194            replace_range.clone()
22195        }
22196    };
22197
22198    if range_to_replace
22199        .end
22200        .cmp(cursor_position, &buffer_snapshot)
22201        .is_lt()
22202    {
22203        range_to_replace.end = *cursor_position;
22204    }
22205
22206    CompletionEdit {
22207        new_text,
22208        replace_range: range_to_replace.to_offset(buffer),
22209        snippet,
22210    }
22211}
22212
22213struct CompletionEdit {
22214    new_text: String,
22215    replace_range: Range<usize>,
22216    snippet: Option<Snippet>,
22217}
22218
22219fn insert_extra_newline_brackets(
22220    buffer: &MultiBufferSnapshot,
22221    range: Range<usize>,
22222    language: &language::LanguageScope,
22223) -> bool {
22224    let leading_whitespace_len = buffer
22225        .reversed_chars_at(range.start)
22226        .take_while(|c| c.is_whitespace() && *c != '\n')
22227        .map(|c| c.len_utf8())
22228        .sum::<usize>();
22229    let trailing_whitespace_len = buffer
22230        .chars_at(range.end)
22231        .take_while(|c| c.is_whitespace() && *c != '\n')
22232        .map(|c| c.len_utf8())
22233        .sum::<usize>();
22234    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22235
22236    language.brackets().any(|(pair, enabled)| {
22237        let pair_start = pair.start.trim_end();
22238        let pair_end = pair.end.trim_start();
22239
22240        enabled
22241            && pair.newline
22242            && buffer.contains_str_at(range.end, pair_end)
22243            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22244    })
22245}
22246
22247fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22248    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22249        [(buffer, range, _)] => (*buffer, range.clone()),
22250        _ => return false,
22251    };
22252    let pair = {
22253        let mut result: Option<BracketMatch> = None;
22254
22255        for pair in buffer
22256            .all_bracket_ranges(range.clone())
22257            .filter(move |pair| {
22258                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22259            })
22260        {
22261            let len = pair.close_range.end - pair.open_range.start;
22262
22263            if let Some(existing) = &result {
22264                let existing_len = existing.close_range.end - existing.open_range.start;
22265                if len > existing_len {
22266                    continue;
22267                }
22268            }
22269
22270            result = Some(pair);
22271        }
22272
22273        result
22274    };
22275    let Some(pair) = pair else {
22276        return false;
22277    };
22278    pair.newline_only
22279        && buffer
22280            .chars_for_range(pair.open_range.end..range.start)
22281            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22282            .all(|c| c.is_whitespace() && c != '\n')
22283}
22284
22285fn update_uncommitted_diff_for_buffer(
22286    editor: Entity<Editor>,
22287    project: &Entity<Project>,
22288    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22289    buffer: Entity<MultiBuffer>,
22290    cx: &mut App,
22291) -> Task<()> {
22292    let mut tasks = Vec::new();
22293    project.update(cx, |project, cx| {
22294        for buffer in buffers {
22295            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22296                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22297            }
22298        }
22299    });
22300    cx.spawn(async move |cx| {
22301        let diffs = future::join_all(tasks).await;
22302        if editor
22303            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22304            .unwrap_or(false)
22305        {
22306            return;
22307        }
22308
22309        buffer
22310            .update(cx, |buffer, cx| {
22311                for diff in diffs.into_iter().flatten() {
22312                    buffer.add_diff(diff, cx);
22313                }
22314            })
22315            .ok();
22316    })
22317}
22318
22319fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22320    let tab_size = tab_size.get() as usize;
22321    let mut width = offset;
22322
22323    for ch in text.chars() {
22324        width += if ch == '\t' {
22325            tab_size - (width % tab_size)
22326        } else {
22327            1
22328        };
22329    }
22330
22331    width - offset
22332}
22333
22334#[cfg(test)]
22335mod tests {
22336    use super::*;
22337
22338    #[test]
22339    fn test_string_size_with_expanded_tabs() {
22340        let nz = |val| NonZeroU32::new(val).unwrap();
22341        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22342        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22343        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22344        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22345        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22346        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22347        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22348        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22349    }
22350}
22351
22352/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22353struct WordBreakingTokenizer<'a> {
22354    input: &'a str,
22355}
22356
22357impl<'a> WordBreakingTokenizer<'a> {
22358    fn new(input: &'a str) -> Self {
22359        Self { input }
22360    }
22361}
22362
22363fn is_char_ideographic(ch: char) -> bool {
22364    use unicode_script::Script::*;
22365    use unicode_script::UnicodeScript;
22366    matches!(ch.script(), Han | Tangut | Yi)
22367}
22368
22369fn is_grapheme_ideographic(text: &str) -> bool {
22370    text.chars().any(is_char_ideographic)
22371}
22372
22373fn is_grapheme_whitespace(text: &str) -> bool {
22374    text.chars().any(|x| x.is_whitespace())
22375}
22376
22377fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22378    text.chars()
22379        .next()
22380        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22381}
22382
22383#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22384enum WordBreakToken<'a> {
22385    Word { token: &'a str, grapheme_len: usize },
22386    InlineWhitespace { token: &'a str, grapheme_len: usize },
22387    Newline,
22388}
22389
22390impl<'a> Iterator for WordBreakingTokenizer<'a> {
22391    /// Yields a span, the count of graphemes in the token, and whether it was
22392    /// whitespace. Note that it also breaks at word boundaries.
22393    type Item = WordBreakToken<'a>;
22394
22395    fn next(&mut self) -> Option<Self::Item> {
22396        use unicode_segmentation::UnicodeSegmentation;
22397        if self.input.is_empty() {
22398            return None;
22399        }
22400
22401        let mut iter = self.input.graphemes(true).peekable();
22402        let mut offset = 0;
22403        let mut grapheme_len = 0;
22404        if let Some(first_grapheme) = iter.next() {
22405            let is_newline = first_grapheme == "\n";
22406            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22407            offset += first_grapheme.len();
22408            grapheme_len += 1;
22409            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22410                if let Some(grapheme) = iter.peek().copied()
22411                    && should_stay_with_preceding_ideograph(grapheme)
22412                {
22413                    offset += grapheme.len();
22414                    grapheme_len += 1;
22415                }
22416            } else {
22417                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22418                let mut next_word_bound = words.peek().copied();
22419                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22420                    next_word_bound = words.next();
22421                }
22422                while let Some(grapheme) = iter.peek().copied() {
22423                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22424                        break;
22425                    };
22426                    if is_grapheme_whitespace(grapheme) != is_whitespace
22427                        || (grapheme == "\n") != is_newline
22428                    {
22429                        break;
22430                    };
22431                    offset += grapheme.len();
22432                    grapheme_len += 1;
22433                    iter.next();
22434                }
22435            }
22436            let token = &self.input[..offset];
22437            self.input = &self.input[offset..];
22438            if token == "\n" {
22439                Some(WordBreakToken::Newline)
22440            } else if is_whitespace {
22441                Some(WordBreakToken::InlineWhitespace {
22442                    token,
22443                    grapheme_len,
22444                })
22445            } else {
22446                Some(WordBreakToken::Word {
22447                    token,
22448                    grapheme_len,
22449                })
22450            }
22451        } else {
22452            None
22453        }
22454    }
22455}
22456
22457#[test]
22458fn test_word_breaking_tokenizer() {
22459    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22460        ("", &[]),
22461        ("  ", &[whitespace("  ", 2)]),
22462        ("Ʒ", &[word("Ʒ", 1)]),
22463        ("Ǽ", &[word("Ǽ", 1)]),
22464        ("⋑", &[word("⋑", 1)]),
22465        ("⋑⋑", &[word("⋑⋑", 2)]),
22466        (
22467            "原理,进而",
22468            &[word("原", 1), word("理,", 2), word("进", 1), word("而", 1)],
22469        ),
22470        (
22471            "hello world",
22472            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22473        ),
22474        (
22475            "hello, world",
22476            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22477        ),
22478        (
22479            "  hello world",
22480            &[
22481                whitespace("  ", 2),
22482                word("hello", 5),
22483                whitespace(" ", 1),
22484                word("world", 5),
22485            ],
22486        ),
22487        (
22488            "这是什么 \n 钢笔",
22489            &[
22490                word("这", 1),
22491                word("是", 1),
22492                word("什", 1),
22493                word("么", 1),
22494                whitespace(" ", 1),
22495                newline(),
22496                whitespace(" ", 1),
22497                word("钢", 1),
22498                word("笔", 1),
22499            ],
22500        ),
22501        (" mutton", &[whitespace(" ", 1), word("mutton", 6)]),
22502    ];
22503
22504    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22505        WordBreakToken::Word {
22506            token,
22507            grapheme_len,
22508        }
22509    }
22510
22511    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22512        WordBreakToken::InlineWhitespace {
22513            token,
22514            grapheme_len,
22515        }
22516    }
22517
22518    fn newline() -> WordBreakToken<'static> {
22519        WordBreakToken::Newline
22520    }
22521
22522    for (input, result) in tests {
22523        assert_eq!(
22524            WordBreakingTokenizer::new(input)
22525                .collect::<Vec<_>>()
22526                .as_slice(),
22527            *result,
22528        );
22529    }
22530}
22531
22532fn wrap_with_prefix(
22533    first_line_prefix: String,
22534    subsequent_lines_prefix: String,
22535    unwrapped_text: String,
22536    wrap_column: usize,
22537    tab_size: NonZeroU32,
22538    preserve_existing_whitespace: bool,
22539) -> String {
22540    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22541    let subsequent_lines_prefix_len =
22542        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22543    let mut wrapped_text = String::new();
22544    let mut current_line = first_line_prefix;
22545    let mut is_first_line = true;
22546
22547    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22548    let mut current_line_len = first_line_prefix_len;
22549    let mut in_whitespace = false;
22550    for token in tokenizer {
22551        let have_preceding_whitespace = in_whitespace;
22552        match token {
22553            WordBreakToken::Word {
22554                token,
22555                grapheme_len,
22556            } => {
22557                in_whitespace = false;
22558                let current_prefix_len = if is_first_line {
22559                    first_line_prefix_len
22560                } else {
22561                    subsequent_lines_prefix_len
22562                };
22563                if current_line_len + grapheme_len > wrap_column
22564                    && current_line_len != current_prefix_len
22565                {
22566                    wrapped_text.push_str(current_line.trim_end());
22567                    wrapped_text.push('\n');
22568                    is_first_line = false;
22569                    current_line = subsequent_lines_prefix.clone();
22570                    current_line_len = subsequent_lines_prefix_len;
22571                }
22572                current_line.push_str(token);
22573                current_line_len += grapheme_len;
22574            }
22575            WordBreakToken::InlineWhitespace {
22576                mut token,
22577                mut grapheme_len,
22578            } => {
22579                in_whitespace = true;
22580                if have_preceding_whitespace && !preserve_existing_whitespace {
22581                    continue;
22582                }
22583                if !preserve_existing_whitespace {
22584                    // Keep a single whitespace grapheme as-is
22585                    if let Some(first) =
22586                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22587                    {
22588                        token = first;
22589                    } else {
22590                        token = " ";
22591                    }
22592                    grapheme_len = 1;
22593                }
22594                let current_prefix_len = if is_first_line {
22595                    first_line_prefix_len
22596                } else {
22597                    subsequent_lines_prefix_len
22598                };
22599                if current_line_len + grapheme_len > wrap_column {
22600                    wrapped_text.push_str(current_line.trim_end());
22601                    wrapped_text.push('\n');
22602                    is_first_line = false;
22603                    current_line = subsequent_lines_prefix.clone();
22604                    current_line_len = subsequent_lines_prefix_len;
22605                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22606                    current_line.push_str(token);
22607                    current_line_len += grapheme_len;
22608                }
22609            }
22610            WordBreakToken::Newline => {
22611                in_whitespace = true;
22612                let current_prefix_len = if is_first_line {
22613                    first_line_prefix_len
22614                } else {
22615                    subsequent_lines_prefix_len
22616                };
22617                if preserve_existing_whitespace {
22618                    wrapped_text.push_str(current_line.trim_end());
22619                    wrapped_text.push('\n');
22620                    is_first_line = false;
22621                    current_line = subsequent_lines_prefix.clone();
22622                    current_line_len = subsequent_lines_prefix_len;
22623                } else if have_preceding_whitespace {
22624                    continue;
22625                } else if current_line_len + 1 > wrap_column
22626                    && current_line_len != current_prefix_len
22627                {
22628                    wrapped_text.push_str(current_line.trim_end());
22629                    wrapped_text.push('\n');
22630                    is_first_line = false;
22631                    current_line = subsequent_lines_prefix.clone();
22632                    current_line_len = subsequent_lines_prefix_len;
22633                } else if current_line_len != current_prefix_len {
22634                    current_line.push(' ');
22635                    current_line_len += 1;
22636                }
22637            }
22638        }
22639    }
22640
22641    if !current_line.is_empty() {
22642        wrapped_text.push_str(¤t_line);
22643    }
22644    wrapped_text
22645}
22646
22647#[test]
22648fn test_wrap_with_prefix() {
22649    assert_eq!(
22650        wrap_with_prefix(
22651            "# ".to_string(),
22652            "# ".to_string(),
22653            "abcdefg".to_string(),
22654            4,
22655            NonZeroU32::new(4).unwrap(),
22656            false,
22657        ),
22658        "# abcdefg"
22659    );
22660    assert_eq!(
22661        wrap_with_prefix(
22662            "".to_string(),
22663            "".to_string(),
22664            "\thello world".to_string(),
22665            8,
22666            NonZeroU32::new(4).unwrap(),
22667            false,
22668        ),
22669        "hello\nworld"
22670    );
22671    assert_eq!(
22672        wrap_with_prefix(
22673            "// ".to_string(),
22674            "// ".to_string(),
22675            "xx \nyy zz aa bb cc".to_string(),
22676            12,
22677            NonZeroU32::new(4).unwrap(),
22678            false,
22679        ),
22680        "// xx yy zz\n// aa bb cc"
22681    );
22682    assert_eq!(
22683        wrap_with_prefix(
22684            String::new(),
22685            String::new(),
22686            "这是什么 \n 钢笔".to_string(),
22687            3,
22688            NonZeroU32::new(4).unwrap(),
22689            false,
22690        ),
22691        "这是什\n么 钢\n笔"
22692    );
22693    assert_eq!(
22694        wrap_with_prefix(
22695            String::new(),
22696            String::new(),
22697            format!("foo{}bar", '\u{2009}'), // thin space
22698            80,
22699            NonZeroU32::new(4).unwrap(),
22700            false,
22701        ),
22702        format!("foo{}bar", '\u{2009}')
22703    );
22704}
22705
22706pub trait CollaborationHub {
22707    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22708    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22709    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22710}
22711
22712impl CollaborationHub for Entity<Project> {
22713    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22714        self.read(cx).collaborators()
22715    }
22716
22717    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22718        self.read(cx).user_store().read(cx).participant_indices()
22719    }
22720
22721    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22722        let this = self.read(cx);
22723        let user_ids = this.collaborators().values().map(|c| c.user_id);
22724        this.user_store().read(cx).participant_names(user_ids, cx)
22725    }
22726}
22727
22728pub trait SemanticsProvider {
22729    fn hover(
22730        &self,
22731        buffer: &Entity<Buffer>,
22732        position: text::Anchor,
22733        cx: &mut App,
22734    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22735
22736    fn inline_values(
22737        &self,
22738        buffer_handle: Entity<Buffer>,
22739        range: Range<text::Anchor>,
22740        cx: &mut App,
22741    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22742
22743    fn applicable_inlay_chunks(
22744        &self,
22745        buffer: &Entity<Buffer>,
22746        ranges: &[Range<text::Anchor>],
22747        cx: &mut App,
22748    ) -> Vec<Range<BufferRow>>;
22749
22750    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22751
22752    fn inlay_hints(
22753        &self,
22754        invalidate: InvalidationStrategy,
22755        buffer: Entity<Buffer>,
22756        ranges: Vec<Range<text::Anchor>>,
22757        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22758        cx: &mut App,
22759    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22760
22761    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22762
22763    fn document_highlights(
22764        &self,
22765        buffer: &Entity<Buffer>,
22766        position: text::Anchor,
22767        cx: &mut App,
22768    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22769
22770    fn definitions(
22771        &self,
22772        buffer: &Entity<Buffer>,
22773        position: text::Anchor,
22774        kind: GotoDefinitionKind,
22775        cx: &mut App,
22776    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22777
22778    fn range_for_rename(
22779        &self,
22780        buffer: &Entity<Buffer>,
22781        position: text::Anchor,
22782        cx: &mut App,
22783    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22784
22785    fn perform_rename(
22786        &self,
22787        buffer: &Entity<Buffer>,
22788        position: text::Anchor,
22789        new_name: String,
22790        cx: &mut App,
22791    ) -> Option<Task<Result<ProjectTransaction>>>;
22792}
22793
22794pub trait CompletionProvider {
22795    fn completions(
22796        &self,
22797        excerpt_id: ExcerptId,
22798        buffer: &Entity<Buffer>,
22799        buffer_position: text::Anchor,
22800        trigger: CompletionContext,
22801        window: &mut Window,
22802        cx: &mut Context<Editor>,
22803    ) -> Task<Result<Vec<CompletionResponse>>>;
22804
22805    fn resolve_completions(
22806        &self,
22807        _buffer: Entity<Buffer>,
22808        _completion_indices: Vec<usize>,
22809        _completions: Rc<RefCell<Box<[Completion]>>>,
22810        _cx: &mut Context<Editor>,
22811    ) -> Task<Result<bool>> {
22812        Task::ready(Ok(false))
22813    }
22814
22815    fn apply_additional_edits_for_completion(
22816        &self,
22817        _buffer: Entity<Buffer>,
22818        _completions: Rc<RefCell<Box<[Completion]>>>,
22819        _completion_index: usize,
22820        _push_to_history: bool,
22821        _cx: &mut Context<Editor>,
22822    ) -> Task<Result<Option<language::Transaction>>> {
22823        Task::ready(Ok(None))
22824    }
22825
22826    fn is_completion_trigger(
22827        &self,
22828        buffer: &Entity<Buffer>,
22829        position: language::Anchor,
22830        text: &str,
22831        trigger_in_words: bool,
22832        menu_is_open: bool,
22833        cx: &mut Context<Editor>,
22834    ) -> bool;
22835
22836    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22837
22838    fn sort_completions(&self) -> bool {
22839        true
22840    }
22841
22842    fn filter_completions(&self) -> bool {
22843        true
22844    }
22845}
22846
22847pub trait CodeActionProvider {
22848    fn id(&self) -> Arc<str>;
22849
22850    fn code_actions(
22851        &self,
22852        buffer: &Entity<Buffer>,
22853        range: Range<text::Anchor>,
22854        window: &mut Window,
22855        cx: &mut App,
22856    ) -> Task<Result<Vec<CodeAction>>>;
22857
22858    fn apply_code_action(
22859        &self,
22860        buffer_handle: Entity<Buffer>,
22861        action: CodeAction,
22862        excerpt_id: ExcerptId,
22863        push_to_history: bool,
22864        window: &mut Window,
22865        cx: &mut App,
22866    ) -> Task<Result<ProjectTransaction>>;
22867}
22868
22869impl CodeActionProvider for Entity<Project> {
22870    fn id(&self) -> Arc<str> {
22871        "project".into()
22872    }
22873
22874    fn code_actions(
22875        &self,
22876        buffer: &Entity<Buffer>,
22877        range: Range<text::Anchor>,
22878        _window: &mut Window,
22879        cx: &mut App,
22880    ) -> Task<Result<Vec<CodeAction>>> {
22881        self.update(cx, |project, cx| {
22882            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22883            let code_actions = project.code_actions(buffer, range, None, cx);
22884            cx.background_spawn(async move {
22885                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22886                Ok(code_lens_actions
22887                    .context("code lens fetch")?
22888                    .into_iter()
22889                    .flatten()
22890                    .chain(
22891                        code_actions
22892                            .context("code action fetch")?
22893                            .into_iter()
22894                            .flatten(),
22895                    )
22896                    .collect())
22897            })
22898        })
22899    }
22900
22901    fn apply_code_action(
22902        &self,
22903        buffer_handle: Entity<Buffer>,
22904        action: CodeAction,
22905        _excerpt_id: ExcerptId,
22906        push_to_history: bool,
22907        _window: &mut Window,
22908        cx: &mut App,
22909    ) -> Task<Result<ProjectTransaction>> {
22910        self.update(cx, |project, cx| {
22911            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22912        })
22913    }
22914}
22915
22916fn snippet_completions(
22917    project: &Project,
22918    buffer: &Entity<Buffer>,
22919    buffer_position: text::Anchor,
22920    cx: &mut App,
22921) -> Task<Result<CompletionResponse>> {
22922    let languages = buffer.read(cx).languages_at(buffer_position);
22923    let snippet_store = project.snippets().read(cx);
22924
22925    let scopes: Vec<_> = languages
22926        .iter()
22927        .filter_map(|language| {
22928            let language_name = language.lsp_id();
22929            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22930
22931            if snippets.is_empty() {
22932                None
22933            } else {
22934                Some((language.default_scope(), snippets))
22935            }
22936        })
22937        .collect();
22938
22939    if scopes.is_empty() {
22940        return Task::ready(Ok(CompletionResponse {
22941            completions: vec![],
22942            display_options: CompletionDisplayOptions::default(),
22943            is_incomplete: false,
22944        }));
22945    }
22946
22947    let snapshot = buffer.read(cx).text_snapshot();
22948    let executor = cx.background_executor().clone();
22949
22950    cx.background_spawn(async move {
22951        let mut is_incomplete = false;
22952        let mut completions: Vec<Completion> = Vec::new();
22953        for (scope, snippets) in scopes.into_iter() {
22954            let classifier =
22955                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22956
22957            const MAX_WORD_PREFIX_LEN: usize = 128;
22958            let last_word: String = snapshot
22959                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22960                .take(MAX_WORD_PREFIX_LEN)
22961                .take_while(|c| classifier.is_word(*c))
22962                .collect::<String>()
22963                .chars()
22964                .rev()
22965                .collect();
22966
22967            if last_word.is_empty() {
22968                return Ok(CompletionResponse {
22969                    completions: vec![],
22970                    display_options: CompletionDisplayOptions::default(),
22971                    is_incomplete: true,
22972                });
22973            }
22974
22975            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22976            let to_lsp = |point: &text::Anchor| {
22977                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22978                point_to_lsp(end)
22979            };
22980            let lsp_end = to_lsp(&buffer_position);
22981
22982            let candidates = snippets
22983                .iter()
22984                .enumerate()
22985                .flat_map(|(ix, snippet)| {
22986                    snippet
22987                        .prefix
22988                        .iter()
22989                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22990                })
22991                .collect::<Vec<StringMatchCandidate>>();
22992
22993            const MAX_RESULTS: usize = 100;
22994            let mut matches = fuzzy::match_strings(
22995                &candidates,
22996                &last_word,
22997                last_word.chars().any(|c| c.is_uppercase()),
22998                true,
22999                MAX_RESULTS,
23000                &Default::default(),
23001                executor.clone(),
23002            )
23003            .await;
23004
23005            if matches.len() >= MAX_RESULTS {
23006                is_incomplete = true;
23007            }
23008
23009            // Remove all candidates where the query's start does not match the start of any word in the candidate
23010            if let Some(query_start) = last_word.chars().next() {
23011                matches.retain(|string_match| {
23012                    split_words(&string_match.string).any(|word| {
23013                        // Check that the first codepoint of the word as lowercase matches the first
23014                        // codepoint of the query as lowercase
23015                        word.chars()
23016                            .flat_map(|codepoint| codepoint.to_lowercase())
23017                            .zip(query_start.to_lowercase())
23018                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23019                    })
23020                });
23021            }
23022
23023            let matched_strings = matches
23024                .into_iter()
23025                .map(|m| m.string)
23026                .collect::<HashSet<_>>();
23027
23028            completions.extend(snippets.iter().filter_map(|snippet| {
23029                let matching_prefix = snippet
23030                    .prefix
23031                    .iter()
23032                    .find(|prefix| matched_strings.contains(*prefix))?;
23033                let start = as_offset - last_word.len();
23034                let start = snapshot.anchor_before(start);
23035                let range = start..buffer_position;
23036                let lsp_start = to_lsp(&start);
23037                let lsp_range = lsp::Range {
23038                    start: lsp_start,
23039                    end: lsp_end,
23040                };
23041                Some(Completion {
23042                    replace_range: range,
23043                    new_text: snippet.body.clone(),
23044                    source: CompletionSource::Lsp {
23045                        insert_range: None,
23046                        server_id: LanguageServerId(usize::MAX),
23047                        resolved: true,
23048                        lsp_completion: Box::new(lsp::CompletionItem {
23049                            label: snippet.prefix.first().unwrap().clone(),
23050                            kind: Some(CompletionItemKind::SNIPPET),
23051                            label_details: snippet.description.as_ref().map(|description| {
23052                                lsp::CompletionItemLabelDetails {
23053                                    detail: Some(description.clone()),
23054                                    description: None,
23055                                }
23056                            }),
23057                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23058                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23059                                lsp::InsertReplaceEdit {
23060                                    new_text: snippet.body.clone(),
23061                                    insert: lsp_range,
23062                                    replace: lsp_range,
23063                                },
23064                            )),
23065                            filter_text: Some(snippet.body.clone()),
23066                            sort_text: Some(char::MAX.to_string()),
23067                            ..lsp::CompletionItem::default()
23068                        }),
23069                        lsp_defaults: None,
23070                    },
23071                    label: CodeLabel::plain(matching_prefix.clone(), None),
23072                    icon_path: None,
23073                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23074                        single_line: snippet.name.clone().into(),
23075                        plain_text: snippet
23076                            .description
23077                            .clone()
23078                            .map(|description| description.into()),
23079                    }),
23080                    insert_text_mode: None,
23081                    confirm: None,
23082                })
23083            }))
23084        }
23085
23086        Ok(CompletionResponse {
23087            completions,
23088            display_options: CompletionDisplayOptions::default(),
23089            is_incomplete,
23090        })
23091    })
23092}
23093
23094impl CompletionProvider for Entity<Project> {
23095    fn completions(
23096        &self,
23097        _excerpt_id: ExcerptId,
23098        buffer: &Entity<Buffer>,
23099        buffer_position: text::Anchor,
23100        options: CompletionContext,
23101        _window: &mut Window,
23102        cx: &mut Context<Editor>,
23103    ) -> Task<Result<Vec<CompletionResponse>>> {
23104        self.update(cx, |project, cx| {
23105            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23106            let project_completions = project.completions(buffer, buffer_position, options, cx);
23107            cx.background_spawn(async move {
23108                let mut responses = project_completions.await?;
23109                let snippets = snippets.await?;
23110                if !snippets.completions.is_empty() {
23111                    responses.push(snippets);
23112                }
23113                Ok(responses)
23114            })
23115        })
23116    }
23117
23118    fn resolve_completions(
23119        &self,
23120        buffer: Entity<Buffer>,
23121        completion_indices: Vec<usize>,
23122        completions: Rc<RefCell<Box<[Completion]>>>,
23123        cx: &mut Context<Editor>,
23124    ) -> Task<Result<bool>> {
23125        self.update(cx, |project, cx| {
23126            project.lsp_store().update(cx, |lsp_store, cx| {
23127                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23128            })
23129        })
23130    }
23131
23132    fn apply_additional_edits_for_completion(
23133        &self,
23134        buffer: Entity<Buffer>,
23135        completions: Rc<RefCell<Box<[Completion]>>>,
23136        completion_index: usize,
23137        push_to_history: bool,
23138        cx: &mut Context<Editor>,
23139    ) -> Task<Result<Option<language::Transaction>>> {
23140        self.update(cx, |project, cx| {
23141            project.lsp_store().update(cx, |lsp_store, cx| {
23142                lsp_store.apply_additional_edits_for_completion(
23143                    buffer,
23144                    completions,
23145                    completion_index,
23146                    push_to_history,
23147                    cx,
23148                )
23149            })
23150        })
23151    }
23152
23153    fn is_completion_trigger(
23154        &self,
23155        buffer: &Entity<Buffer>,
23156        position: language::Anchor,
23157        text: &str,
23158        trigger_in_words: bool,
23159        menu_is_open: bool,
23160        cx: &mut Context<Editor>,
23161    ) -> bool {
23162        let mut chars = text.chars();
23163        let char = if let Some(char) = chars.next() {
23164            char
23165        } else {
23166            return false;
23167        };
23168        if chars.next().is_some() {
23169            return false;
23170        }
23171
23172        let buffer = buffer.read(cx);
23173        let snapshot = buffer.snapshot();
23174        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23175            return false;
23176        }
23177        let classifier = snapshot
23178            .char_classifier_at(position)
23179            .scope_context(Some(CharScopeContext::Completion));
23180        if trigger_in_words && classifier.is_word(char) {
23181            return true;
23182        }
23183
23184        buffer.completion_triggers().contains(text)
23185    }
23186}
23187
23188impl SemanticsProvider for Entity<Project> {
23189    fn hover(
23190        &self,
23191        buffer: &Entity<Buffer>,
23192        position: text::Anchor,
23193        cx: &mut App,
23194    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23195        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23196    }
23197
23198    fn document_highlights(
23199        &self,
23200        buffer: &Entity<Buffer>,
23201        position: text::Anchor,
23202        cx: &mut App,
23203    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23204        Some(self.update(cx, |project, cx| {
23205            project.document_highlights(buffer, position, cx)
23206        }))
23207    }
23208
23209    fn definitions(
23210        &self,
23211        buffer: &Entity<Buffer>,
23212        position: text::Anchor,
23213        kind: GotoDefinitionKind,
23214        cx: &mut App,
23215    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23216        Some(self.update(cx, |project, cx| match kind {
23217            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23218            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23219            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23220            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23221        }))
23222    }
23223
23224    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23225        self.update(cx, |project, cx| {
23226            if project
23227                .active_debug_session(cx)
23228                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23229            {
23230                return true;
23231            }
23232
23233            buffer.update(cx, |buffer, cx| {
23234                project.any_language_server_supports_inlay_hints(buffer, cx)
23235            })
23236        })
23237    }
23238
23239    fn inline_values(
23240        &self,
23241        buffer_handle: Entity<Buffer>,
23242        range: Range<text::Anchor>,
23243        cx: &mut App,
23244    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23245        self.update(cx, |project, cx| {
23246            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23247
23248            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23249        })
23250    }
23251
23252    fn applicable_inlay_chunks(
23253        &self,
23254        buffer: &Entity<Buffer>,
23255        ranges: &[Range<text::Anchor>],
23256        cx: &mut App,
23257    ) -> Vec<Range<BufferRow>> {
23258        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23259            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23260        })
23261    }
23262
23263    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23264        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23265            lsp_store.invalidate_inlay_hints(for_buffers)
23266        });
23267    }
23268
23269    fn inlay_hints(
23270        &self,
23271        invalidate: InvalidationStrategy,
23272        buffer: Entity<Buffer>,
23273        ranges: Vec<Range<text::Anchor>>,
23274        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23275        cx: &mut App,
23276    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23277        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23278            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23279        }))
23280    }
23281
23282    fn range_for_rename(
23283        &self,
23284        buffer: &Entity<Buffer>,
23285        position: text::Anchor,
23286        cx: &mut App,
23287    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23288        Some(self.update(cx, |project, cx| {
23289            let buffer = buffer.clone();
23290            let task = project.prepare_rename(buffer.clone(), position, cx);
23291            cx.spawn(async move |_, cx| {
23292                Ok(match task.await? {
23293                    PrepareRenameResponse::Success(range) => Some(range),
23294                    PrepareRenameResponse::InvalidPosition => None,
23295                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23296                        // Fallback on using TreeSitter info to determine identifier range
23297                        buffer.read_with(cx, |buffer, _| {
23298                            let snapshot = buffer.snapshot();
23299                            let (range, kind) = snapshot.surrounding_word(position, None);
23300                            if kind != Some(CharKind::Word) {
23301                                return None;
23302                            }
23303                            Some(
23304                                snapshot.anchor_before(range.start)
23305                                    ..snapshot.anchor_after(range.end),
23306                            )
23307                        })?
23308                    }
23309                })
23310            })
23311        }))
23312    }
23313
23314    fn perform_rename(
23315        &self,
23316        buffer: &Entity<Buffer>,
23317        position: text::Anchor,
23318        new_name: String,
23319        cx: &mut App,
23320    ) -> Option<Task<Result<ProjectTransaction>>> {
23321        Some(self.update(cx, |project, cx| {
23322            project.perform_rename(buffer.clone(), position, new_name, cx)
23323        }))
23324    }
23325}
23326
23327fn consume_contiguous_rows(
23328    contiguous_row_selections: &mut Vec<Selection<Point>>,
23329    selection: &Selection<Point>,
23330    display_map: &DisplaySnapshot,
23331    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23332) -> (MultiBufferRow, MultiBufferRow) {
23333    contiguous_row_selections.push(selection.clone());
23334    let start_row = starting_row(selection, display_map);
23335    let mut end_row = ending_row(selection, display_map);
23336
23337    while let Some(next_selection) = selections.peek() {
23338        if next_selection.start.row <= end_row.0 {
23339            end_row = ending_row(next_selection, display_map);
23340            contiguous_row_selections.push(selections.next().unwrap().clone());
23341        } else {
23342            break;
23343        }
23344    }
23345    (start_row, end_row)
23346}
23347
23348fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23349    if selection.start.column > 0 {
23350        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23351    } else {
23352        MultiBufferRow(selection.start.row)
23353    }
23354}
23355
23356fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23357    if next_selection.end.column > 0 || next_selection.is_empty() {
23358        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23359    } else {
23360        MultiBufferRow(next_selection.end.row)
23361    }
23362}
23363
23364impl EditorSnapshot {
23365    pub fn remote_selections_in_range<'a>(
23366        &'a self,
23367        range: &'a Range<Anchor>,
23368        collaboration_hub: &dyn CollaborationHub,
23369        cx: &'a App,
23370    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23371        let participant_names = collaboration_hub.user_names(cx);
23372        let participant_indices = collaboration_hub.user_participant_indices(cx);
23373        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23374        let collaborators_by_replica_id = collaborators_by_peer_id
23375            .values()
23376            .map(|collaborator| (collaborator.replica_id, collaborator))
23377            .collect::<HashMap<_, _>>();
23378        self.buffer_snapshot()
23379            .selections_in_range(range, false)
23380            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23381                if replica_id == ReplicaId::AGENT {
23382                    Some(RemoteSelection {
23383                        replica_id,
23384                        selection,
23385                        cursor_shape,
23386                        line_mode,
23387                        collaborator_id: CollaboratorId::Agent,
23388                        user_name: Some("Agent".into()),
23389                        color: cx.theme().players().agent(),
23390                    })
23391                } else {
23392                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23393                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23394                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23395                    Some(RemoteSelection {
23396                        replica_id,
23397                        selection,
23398                        cursor_shape,
23399                        line_mode,
23400                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23401                        user_name,
23402                        color: if let Some(index) = participant_index {
23403                            cx.theme().players().color_for_participant(index.0)
23404                        } else {
23405                            cx.theme().players().absent()
23406                        },
23407                    })
23408                }
23409            })
23410    }
23411
23412    pub fn hunks_for_ranges(
23413        &self,
23414        ranges: impl IntoIterator<Item = Range<Point>>,
23415    ) -> Vec<MultiBufferDiffHunk> {
23416        let mut hunks = Vec::new();
23417        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23418            HashMap::default();
23419        for query_range in ranges {
23420            let query_rows =
23421                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23422            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23423                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23424            ) {
23425                // Include deleted hunks that are adjacent to the query range, because
23426                // otherwise they would be missed.
23427                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23428                if hunk.status().is_deleted() {
23429                    intersects_range |= hunk.row_range.start == query_rows.end;
23430                    intersects_range |= hunk.row_range.end == query_rows.start;
23431                }
23432                if intersects_range {
23433                    if !processed_buffer_rows
23434                        .entry(hunk.buffer_id)
23435                        .or_default()
23436                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23437                    {
23438                        continue;
23439                    }
23440                    hunks.push(hunk);
23441                }
23442            }
23443        }
23444
23445        hunks
23446    }
23447
23448    fn display_diff_hunks_for_rows<'a>(
23449        &'a self,
23450        display_rows: Range<DisplayRow>,
23451        folded_buffers: &'a HashSet<BufferId>,
23452    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23453        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23454        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23455
23456        self.buffer_snapshot()
23457            .diff_hunks_in_range(buffer_start..buffer_end)
23458            .filter_map(|hunk| {
23459                if folded_buffers.contains(&hunk.buffer_id) {
23460                    return None;
23461                }
23462
23463                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23464                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23465
23466                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23467                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23468
23469                let display_hunk = if hunk_display_start.column() != 0 {
23470                    DisplayDiffHunk::Folded {
23471                        display_row: hunk_display_start.row(),
23472                    }
23473                } else {
23474                    let mut end_row = hunk_display_end.row();
23475                    if hunk_display_end.column() > 0 {
23476                        end_row.0 += 1;
23477                    }
23478                    let is_created_file = hunk.is_created_file();
23479                    DisplayDiffHunk::Unfolded {
23480                        status: hunk.status(),
23481                        diff_base_byte_range: hunk.diff_base_byte_range,
23482                        display_row_range: hunk_display_start.row()..end_row,
23483                        multi_buffer_range: Anchor::range_in_buffer(
23484                            hunk.excerpt_id,
23485                            hunk.buffer_id,
23486                            hunk.buffer_range,
23487                        ),
23488                        is_created_file,
23489                    }
23490                };
23491
23492                Some(display_hunk)
23493            })
23494    }
23495
23496    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23497        self.display_snapshot
23498            .buffer_snapshot()
23499            .language_at(position)
23500    }
23501
23502    pub fn is_focused(&self) -> bool {
23503        self.is_focused
23504    }
23505
23506    pub fn placeholder_text(&self) -> Option<String> {
23507        self.placeholder_display_snapshot
23508            .as_ref()
23509            .map(|display_map| display_map.text())
23510    }
23511
23512    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23513        self.scroll_anchor.scroll_position(&self.display_snapshot)
23514    }
23515
23516    fn gutter_dimensions(
23517        &self,
23518        font_id: FontId,
23519        font_size: Pixels,
23520        max_line_number_width: Pixels,
23521        cx: &App,
23522    ) -> Option<GutterDimensions> {
23523        if !self.show_gutter {
23524            return None;
23525        }
23526
23527        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23528        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23529
23530        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23531            matches!(
23532                ProjectSettings::get_global(cx).git.git_gutter,
23533                GitGutterSetting::TrackedFiles
23534            )
23535        });
23536        let gutter_settings = EditorSettings::get_global(cx).gutter;
23537        let show_line_numbers = self
23538            .show_line_numbers
23539            .unwrap_or(gutter_settings.line_numbers);
23540        let line_gutter_width = if show_line_numbers {
23541            // Avoid flicker-like gutter resizes when the line number gains another digit by
23542            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23543            let min_width_for_number_on_gutter =
23544                ch_advance * gutter_settings.min_line_number_digits as f32;
23545            max_line_number_width.max(min_width_for_number_on_gutter)
23546        } else {
23547            0.0.into()
23548        };
23549
23550        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23551        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23552
23553        let git_blame_entries_width =
23554            self.git_blame_gutter_max_author_length
23555                .map(|max_author_length| {
23556                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23557                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23558
23559                    /// The number of characters to dedicate to gaps and margins.
23560                    const SPACING_WIDTH: usize = 4;
23561
23562                    let max_char_count = max_author_length.min(renderer.max_author_length())
23563                        + ::git::SHORT_SHA_LENGTH
23564                        + MAX_RELATIVE_TIMESTAMP.len()
23565                        + SPACING_WIDTH;
23566
23567                    ch_advance * max_char_count
23568                });
23569
23570        let is_singleton = self.buffer_snapshot().is_singleton();
23571
23572        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23573        left_padding += if !is_singleton {
23574            ch_width * 4.0
23575        } else if show_runnables || show_breakpoints {
23576            ch_width * 3.0
23577        } else if show_git_gutter && show_line_numbers {
23578            ch_width * 2.0
23579        } else if show_git_gutter || show_line_numbers {
23580            ch_width
23581        } else {
23582            px(0.)
23583        };
23584
23585        let shows_folds = is_singleton && gutter_settings.folds;
23586
23587        let right_padding = if shows_folds && show_line_numbers {
23588            ch_width * 4.0
23589        } else if shows_folds || (!is_singleton && show_line_numbers) {
23590            ch_width * 3.0
23591        } else if show_line_numbers {
23592            ch_width
23593        } else {
23594            px(0.)
23595        };
23596
23597        Some(GutterDimensions {
23598            left_padding,
23599            right_padding,
23600            width: line_gutter_width + left_padding + right_padding,
23601            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23602            git_blame_entries_width,
23603        })
23604    }
23605
23606    pub fn render_crease_toggle(
23607        &self,
23608        buffer_row: MultiBufferRow,
23609        row_contains_cursor: bool,
23610        editor: Entity<Editor>,
23611        window: &mut Window,
23612        cx: &mut App,
23613    ) -> Option<AnyElement> {
23614        let folded = self.is_line_folded(buffer_row);
23615        let mut is_foldable = false;
23616
23617        if let Some(crease) = self
23618            .crease_snapshot
23619            .query_row(buffer_row, self.buffer_snapshot())
23620        {
23621            is_foldable = true;
23622            match crease {
23623                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23624                    if let Some(render_toggle) = render_toggle {
23625                        let toggle_callback =
23626                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23627                                if folded {
23628                                    editor.update(cx, |editor, cx| {
23629                                        editor.fold_at(buffer_row, window, cx)
23630                                    });
23631                                } else {
23632                                    editor.update(cx, |editor, cx| {
23633                                        editor.unfold_at(buffer_row, window, cx)
23634                                    });
23635                                }
23636                            });
23637                        return Some((render_toggle)(
23638                            buffer_row,
23639                            folded,
23640                            toggle_callback,
23641                            window,
23642                            cx,
23643                        ));
23644                    }
23645                }
23646            }
23647        }
23648
23649        is_foldable |= self.starts_indent(buffer_row);
23650
23651        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23652            Some(
23653                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23654                    .toggle_state(folded)
23655                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23656                        if folded {
23657                            this.unfold_at(buffer_row, window, cx);
23658                        } else {
23659                            this.fold_at(buffer_row, window, cx);
23660                        }
23661                    }))
23662                    .into_any_element(),
23663            )
23664        } else {
23665            None
23666        }
23667    }
23668
23669    pub fn render_crease_trailer(
23670        &self,
23671        buffer_row: MultiBufferRow,
23672        window: &mut Window,
23673        cx: &mut App,
23674    ) -> Option<AnyElement> {
23675        let folded = self.is_line_folded(buffer_row);
23676        if let Crease::Inline { render_trailer, .. } = self
23677            .crease_snapshot
23678            .query_row(buffer_row, self.buffer_snapshot())?
23679        {
23680            let render_trailer = render_trailer.as_ref()?;
23681            Some(render_trailer(buffer_row, folded, window, cx))
23682        } else {
23683            None
23684        }
23685    }
23686}
23687
23688impl Deref for EditorSnapshot {
23689    type Target = DisplaySnapshot;
23690
23691    fn deref(&self) -> &Self::Target {
23692        &self.display_snapshot
23693    }
23694}
23695
23696#[derive(Clone, Debug, PartialEq, Eq)]
23697pub enum EditorEvent {
23698    InputIgnored {
23699        text: Arc<str>,
23700    },
23701    InputHandled {
23702        utf16_range_to_replace: Option<Range<isize>>,
23703        text: Arc<str>,
23704    },
23705    ExcerptsAdded {
23706        buffer: Entity<Buffer>,
23707        predecessor: ExcerptId,
23708        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23709    },
23710    ExcerptsRemoved {
23711        ids: Vec<ExcerptId>,
23712        removed_buffer_ids: Vec<BufferId>,
23713    },
23714    BufferFoldToggled {
23715        ids: Vec<ExcerptId>,
23716        folded: bool,
23717    },
23718    ExcerptsEdited {
23719        ids: Vec<ExcerptId>,
23720    },
23721    ExcerptsExpanded {
23722        ids: Vec<ExcerptId>,
23723    },
23724    BufferEdited,
23725    Edited {
23726        transaction_id: clock::Lamport,
23727    },
23728    Reparsed(BufferId),
23729    Focused,
23730    FocusedIn,
23731    Blurred,
23732    DirtyChanged,
23733    Saved,
23734    TitleChanged,
23735    SelectionsChanged {
23736        local: bool,
23737    },
23738    ScrollPositionChanged {
23739        local: bool,
23740        autoscroll: bool,
23741    },
23742    TransactionUndone {
23743        transaction_id: clock::Lamport,
23744    },
23745    TransactionBegun {
23746        transaction_id: clock::Lamport,
23747    },
23748    CursorShapeChanged,
23749    BreadcrumbsChanged,
23750    PushedToNavHistory {
23751        anchor: Anchor,
23752        is_deactivate: bool,
23753    },
23754}
23755
23756impl EventEmitter<EditorEvent> for Editor {}
23757
23758impl Focusable for Editor {
23759    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23760        self.focus_handle.clone()
23761    }
23762}
23763
23764impl Render for Editor {
23765    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23766        let settings = ThemeSettings::get_global(cx);
23767
23768        let mut text_style = match self.mode {
23769            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23770                color: cx.theme().colors().editor_foreground,
23771                font_family: settings.ui_font.family.clone(),
23772                font_features: settings.ui_font.features.clone(),
23773                font_fallbacks: settings.ui_font.fallbacks.clone(),
23774                font_size: rems(0.875).into(),
23775                font_weight: settings.ui_font.weight,
23776                line_height: relative(settings.buffer_line_height.value()),
23777                ..Default::default()
23778            },
23779            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23780                color: cx.theme().colors().editor_foreground,
23781                font_family: settings.buffer_font.family.clone(),
23782                font_features: settings.buffer_font.features.clone(),
23783                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23784                font_size: settings.buffer_font_size(cx).into(),
23785                font_weight: settings.buffer_font.weight,
23786                line_height: relative(settings.buffer_line_height.value()),
23787                ..Default::default()
23788            },
23789        };
23790        if let Some(text_style_refinement) = &self.text_style_refinement {
23791            text_style.refine(text_style_refinement)
23792        }
23793
23794        let background = match self.mode {
23795            EditorMode::SingleLine => cx.theme().system().transparent,
23796            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23797            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23798            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23799        };
23800
23801        EditorElement::new(
23802            &cx.entity(),
23803            EditorStyle {
23804                background,
23805                border: cx.theme().colors().border,
23806                local_player: cx.theme().players().local(),
23807                text: text_style,
23808                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23809                syntax: cx.theme().syntax().clone(),
23810                status: cx.theme().status().clone(),
23811                inlay_hints_style: make_inlay_hints_style(cx),
23812                edit_prediction_styles: make_suggestion_styles(cx),
23813                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23814                show_underlines: self.diagnostics_enabled(),
23815            },
23816        )
23817    }
23818}
23819
23820impl EntityInputHandler for Editor {
23821    fn text_for_range(
23822        &mut self,
23823        range_utf16: Range<usize>,
23824        adjusted_range: &mut Option<Range<usize>>,
23825        _: &mut Window,
23826        cx: &mut Context<Self>,
23827    ) -> Option<String> {
23828        let snapshot = self.buffer.read(cx).read(cx);
23829        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23830        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23831        if (start.0..end.0) != range_utf16 {
23832            adjusted_range.replace(start.0..end.0);
23833        }
23834        Some(snapshot.text_for_range(start..end).collect())
23835    }
23836
23837    fn selected_text_range(
23838        &mut self,
23839        ignore_disabled_input: bool,
23840        _: &mut Window,
23841        cx: &mut Context<Self>,
23842    ) -> Option<UTF16Selection> {
23843        // Prevent the IME menu from appearing when holding down an alphabetic key
23844        // while input is disabled.
23845        if !ignore_disabled_input && !self.input_enabled {
23846            return None;
23847        }
23848
23849        let selection = self
23850            .selections
23851            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
23852        let range = selection.range();
23853
23854        Some(UTF16Selection {
23855            range: range.start.0..range.end.0,
23856            reversed: selection.reversed,
23857        })
23858    }
23859
23860    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23861        let snapshot = self.buffer.read(cx).read(cx);
23862        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23863        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23864    }
23865
23866    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23867        self.clear_highlights::<InputComposition>(cx);
23868        self.ime_transaction.take();
23869    }
23870
23871    fn replace_text_in_range(
23872        &mut self,
23873        range_utf16: Option<Range<usize>>,
23874        text: &str,
23875        window: &mut Window,
23876        cx: &mut Context<Self>,
23877    ) {
23878        if !self.input_enabled {
23879            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23880            return;
23881        }
23882
23883        self.transact(window, cx, |this, window, cx| {
23884            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23885                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23886                Some(this.selection_replacement_ranges(range_utf16, cx))
23887            } else {
23888                this.marked_text_ranges(cx)
23889            };
23890
23891            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23892                let newest_selection_id = this.selections.newest_anchor().id;
23893                this.selections
23894                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23895                    .iter()
23896                    .zip(ranges_to_replace.iter())
23897                    .find_map(|(selection, range)| {
23898                        if selection.id == newest_selection_id {
23899                            Some(
23900                                (range.start.0 as isize - selection.head().0 as isize)
23901                                    ..(range.end.0 as isize - selection.head().0 as isize),
23902                            )
23903                        } else {
23904                            None
23905                        }
23906                    })
23907            });
23908
23909            cx.emit(EditorEvent::InputHandled {
23910                utf16_range_to_replace: range_to_replace,
23911                text: text.into(),
23912            });
23913
23914            if let Some(new_selected_ranges) = new_selected_ranges {
23915                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23916                    selections.select_ranges(new_selected_ranges)
23917                });
23918                this.backspace(&Default::default(), window, cx);
23919            }
23920
23921            this.handle_input(text, window, cx);
23922        });
23923
23924        if let Some(transaction) = self.ime_transaction {
23925            self.buffer.update(cx, |buffer, cx| {
23926                buffer.group_until_transaction(transaction, cx);
23927            });
23928        }
23929
23930        self.unmark_text(window, cx);
23931    }
23932
23933    fn replace_and_mark_text_in_range(
23934        &mut self,
23935        range_utf16: Option<Range<usize>>,
23936        text: &str,
23937        new_selected_range_utf16: Option<Range<usize>>,
23938        window: &mut Window,
23939        cx: &mut Context<Self>,
23940    ) {
23941        if !self.input_enabled {
23942            return;
23943        }
23944
23945        let transaction = self.transact(window, cx, |this, window, cx| {
23946            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23947                let snapshot = this.buffer.read(cx).read(cx);
23948                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23949                    for marked_range in &mut marked_ranges {
23950                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23951                        marked_range.start.0 += relative_range_utf16.start;
23952                        marked_range.start =
23953                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23954                        marked_range.end =
23955                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23956                    }
23957                }
23958                Some(marked_ranges)
23959            } else if let Some(range_utf16) = range_utf16 {
23960                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23961                Some(this.selection_replacement_ranges(range_utf16, cx))
23962            } else {
23963                None
23964            };
23965
23966            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23967                let newest_selection_id = this.selections.newest_anchor().id;
23968                this.selections
23969                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23970                    .iter()
23971                    .zip(ranges_to_replace.iter())
23972                    .find_map(|(selection, range)| {
23973                        if selection.id == newest_selection_id {
23974                            Some(
23975                                (range.start.0 as isize - selection.head().0 as isize)
23976                                    ..(range.end.0 as isize - selection.head().0 as isize),
23977                            )
23978                        } else {
23979                            None
23980                        }
23981                    })
23982            });
23983
23984            cx.emit(EditorEvent::InputHandled {
23985                utf16_range_to_replace: range_to_replace,
23986                text: text.into(),
23987            });
23988
23989            if let Some(ranges) = ranges_to_replace {
23990                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23991                    s.select_ranges(ranges)
23992                });
23993            }
23994
23995            let marked_ranges = {
23996                let snapshot = this.buffer.read(cx).read(cx);
23997                this.selections
23998                    .disjoint_anchors_arc()
23999                    .iter()
24000                    .map(|selection| {
24001                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24002                    })
24003                    .collect::<Vec<_>>()
24004            };
24005
24006            if text.is_empty() {
24007                this.unmark_text(window, cx);
24008            } else {
24009                this.highlight_text::<InputComposition>(
24010                    marked_ranges.clone(),
24011                    HighlightStyle {
24012                        underline: Some(UnderlineStyle {
24013                            thickness: px(1.),
24014                            color: None,
24015                            wavy: false,
24016                        }),
24017                        ..Default::default()
24018                    },
24019                    cx,
24020                );
24021            }
24022
24023            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24024            let use_autoclose = this.use_autoclose;
24025            let use_auto_surround = this.use_auto_surround;
24026            this.set_use_autoclose(false);
24027            this.set_use_auto_surround(false);
24028            this.handle_input(text, window, cx);
24029            this.set_use_autoclose(use_autoclose);
24030            this.set_use_auto_surround(use_auto_surround);
24031
24032            if let Some(new_selected_range) = new_selected_range_utf16 {
24033                let snapshot = this.buffer.read(cx).read(cx);
24034                let new_selected_ranges = marked_ranges
24035                    .into_iter()
24036                    .map(|marked_range| {
24037                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24038                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24039                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24040                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24041                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24042                    })
24043                    .collect::<Vec<_>>();
24044
24045                drop(snapshot);
24046                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24047                    selections.select_ranges(new_selected_ranges)
24048                });
24049            }
24050        });
24051
24052        self.ime_transaction = self.ime_transaction.or(transaction);
24053        if let Some(transaction) = self.ime_transaction {
24054            self.buffer.update(cx, |buffer, cx| {
24055                buffer.group_until_transaction(transaction, cx);
24056            });
24057        }
24058
24059        if self.text_highlights::<InputComposition>(cx).is_none() {
24060            self.ime_transaction.take();
24061        }
24062    }
24063
24064    fn bounds_for_range(
24065        &mut self,
24066        range_utf16: Range<usize>,
24067        element_bounds: gpui::Bounds<Pixels>,
24068        window: &mut Window,
24069        cx: &mut Context<Self>,
24070    ) -> Option<gpui::Bounds<Pixels>> {
24071        let text_layout_details = self.text_layout_details(window);
24072        let CharacterDimensions {
24073            em_width,
24074            em_advance,
24075            line_height,
24076        } = self.character_dimensions(window);
24077
24078        let snapshot = self.snapshot(window, cx);
24079        let scroll_position = snapshot.scroll_position();
24080        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24081
24082        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24083        let x = Pixels::from(
24084            ScrollOffset::from(
24085                snapshot.x_for_display_point(start, &text_layout_details)
24086                    + self.gutter_dimensions.full_width(),
24087            ) - scroll_left,
24088        );
24089        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24090
24091        Some(Bounds {
24092            origin: element_bounds.origin + point(x, y),
24093            size: size(em_width, line_height),
24094        })
24095    }
24096
24097    fn character_index_for_point(
24098        &mut self,
24099        point: gpui::Point<Pixels>,
24100        _window: &mut Window,
24101        _cx: &mut Context<Self>,
24102    ) -> Option<usize> {
24103        let position_map = self.last_position_map.as_ref()?;
24104        if !position_map.text_hitbox.contains(&point) {
24105            return None;
24106        }
24107        let display_point = position_map.point_for_position(point).previous_valid;
24108        let anchor = position_map
24109            .snapshot
24110            .display_point_to_anchor(display_point, Bias::Left);
24111        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24112        Some(utf16_offset.0)
24113    }
24114}
24115
24116trait SelectionExt {
24117    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24118    fn spanned_rows(
24119        &self,
24120        include_end_if_at_line_start: bool,
24121        map: &DisplaySnapshot,
24122    ) -> Range<MultiBufferRow>;
24123}
24124
24125impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24126    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24127        let start = self
24128            .start
24129            .to_point(map.buffer_snapshot())
24130            .to_display_point(map);
24131        let end = self
24132            .end
24133            .to_point(map.buffer_snapshot())
24134            .to_display_point(map);
24135        if self.reversed {
24136            end..start
24137        } else {
24138            start..end
24139        }
24140    }
24141
24142    fn spanned_rows(
24143        &self,
24144        include_end_if_at_line_start: bool,
24145        map: &DisplaySnapshot,
24146    ) -> Range<MultiBufferRow> {
24147        let start = self.start.to_point(map.buffer_snapshot());
24148        let mut end = self.end.to_point(map.buffer_snapshot());
24149        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24150            end.row -= 1;
24151        }
24152
24153        let buffer_start = map.prev_line_boundary(start).0;
24154        let buffer_end = map.next_line_boundary(end).0;
24155        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24156    }
24157}
24158
24159impl<T: InvalidationRegion> InvalidationStack<T> {
24160    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24161    where
24162        S: Clone + ToOffset,
24163    {
24164        while let Some(region) = self.last() {
24165            let all_selections_inside_invalidation_ranges =
24166                if selections.len() == region.ranges().len() {
24167                    selections
24168                        .iter()
24169                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24170                        .all(|(selection, invalidation_range)| {
24171                            let head = selection.head().to_offset(buffer);
24172                            invalidation_range.start <= head && invalidation_range.end >= head
24173                        })
24174                } else {
24175                    false
24176                };
24177
24178            if all_selections_inside_invalidation_ranges {
24179                break;
24180            } else {
24181                self.pop();
24182            }
24183        }
24184    }
24185}
24186
24187impl<T> Default for InvalidationStack<T> {
24188    fn default() -> Self {
24189        Self(Default::default())
24190    }
24191}
24192
24193impl<T> Deref for InvalidationStack<T> {
24194    type Target = Vec<T>;
24195
24196    fn deref(&self) -> &Self::Target {
24197        &self.0
24198    }
24199}
24200
24201impl<T> DerefMut for InvalidationStack<T> {
24202    fn deref_mut(&mut self) -> &mut Self::Target {
24203        &mut self.0
24204    }
24205}
24206
24207impl InvalidationRegion for SnippetState {
24208    fn ranges(&self) -> &[Range<Anchor>] {
24209        &self.ranges[self.active_index]
24210    }
24211}
24212
24213fn edit_prediction_edit_text(
24214    current_snapshot: &BufferSnapshot,
24215    edits: &[(Range<Anchor>, String)],
24216    edit_preview: &EditPreview,
24217    include_deletions: bool,
24218    cx: &App,
24219) -> HighlightedText {
24220    let edits = edits
24221        .iter()
24222        .map(|(anchor, text)| {
24223            (
24224                anchor.start.text_anchor..anchor.end.text_anchor,
24225                text.clone(),
24226            )
24227        })
24228        .collect::<Vec<_>>();
24229
24230    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24231}
24232
24233fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24234    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24235    // Just show the raw edit text with basic styling
24236    let mut text = String::new();
24237    let mut highlights = Vec::new();
24238
24239    let insertion_highlight_style = HighlightStyle {
24240        color: Some(cx.theme().colors().text),
24241        ..Default::default()
24242    };
24243
24244    for (_, edit_text) in edits {
24245        let start_offset = text.len();
24246        text.push_str(edit_text);
24247        let end_offset = text.len();
24248
24249        if start_offset < end_offset {
24250            highlights.push((start_offset..end_offset, insertion_highlight_style));
24251        }
24252    }
24253
24254    HighlightedText {
24255        text: text.into(),
24256        highlights,
24257    }
24258}
24259
24260pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24261    match severity {
24262        lsp::DiagnosticSeverity::ERROR => colors.error,
24263        lsp::DiagnosticSeverity::WARNING => colors.warning,
24264        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24265        lsp::DiagnosticSeverity::HINT => colors.info,
24266        _ => colors.ignored,
24267    }
24268}
24269
24270pub fn styled_runs_for_code_label<'a>(
24271    label: &'a CodeLabel,
24272    syntax_theme: &'a theme::SyntaxTheme,
24273) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24274    let fade_out = HighlightStyle {
24275        fade_out: Some(0.35),
24276        ..Default::default()
24277    };
24278
24279    let mut prev_end = label.filter_range.end;
24280    label
24281        .runs
24282        .iter()
24283        .enumerate()
24284        .flat_map(move |(ix, (range, highlight_id))| {
24285            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24286                style
24287            } else {
24288                return Default::default();
24289            };
24290            let muted_style = style.highlight(fade_out);
24291
24292            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24293            if range.start >= label.filter_range.end {
24294                if range.start > prev_end {
24295                    runs.push((prev_end..range.start, fade_out));
24296                }
24297                runs.push((range.clone(), muted_style));
24298            } else if range.end <= label.filter_range.end {
24299                runs.push((range.clone(), style));
24300            } else {
24301                runs.push((range.start..label.filter_range.end, style));
24302                runs.push((label.filter_range.end..range.end, muted_style));
24303            }
24304            prev_end = cmp::max(prev_end, range.end);
24305
24306            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24307                runs.push((prev_end..label.text.len(), fade_out));
24308            }
24309
24310            runs
24311        })
24312}
24313
24314pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24315    let mut prev_index = 0;
24316    let mut prev_codepoint: Option<char> = None;
24317    text.char_indices()
24318        .chain([(text.len(), '\0')])
24319        .filter_map(move |(index, codepoint)| {
24320            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24321            let is_boundary = index == text.len()
24322                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24323                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24324            if is_boundary {
24325                let chunk = &text[prev_index..index];
24326                prev_index = index;
24327                Some(chunk)
24328            } else {
24329                None
24330            }
24331        })
24332}
24333
24334pub trait RangeToAnchorExt: Sized {
24335    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24336
24337    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24338        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24339        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24340    }
24341}
24342
24343impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24344    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24345        let start_offset = self.start.to_offset(snapshot);
24346        let end_offset = self.end.to_offset(snapshot);
24347        if start_offset == end_offset {
24348            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24349        } else {
24350            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24351        }
24352    }
24353}
24354
24355pub trait RowExt {
24356    fn as_f64(&self) -> f64;
24357
24358    fn next_row(&self) -> Self;
24359
24360    fn previous_row(&self) -> Self;
24361
24362    fn minus(&self, other: Self) -> u32;
24363}
24364
24365impl RowExt for DisplayRow {
24366    fn as_f64(&self) -> f64 {
24367        self.0 as _
24368    }
24369
24370    fn next_row(&self) -> Self {
24371        Self(self.0 + 1)
24372    }
24373
24374    fn previous_row(&self) -> Self {
24375        Self(self.0.saturating_sub(1))
24376    }
24377
24378    fn minus(&self, other: Self) -> u32 {
24379        self.0 - other.0
24380    }
24381}
24382
24383impl RowExt for MultiBufferRow {
24384    fn as_f64(&self) -> f64 {
24385        self.0 as _
24386    }
24387
24388    fn next_row(&self) -> Self {
24389        Self(self.0 + 1)
24390    }
24391
24392    fn previous_row(&self) -> Self {
24393        Self(self.0.saturating_sub(1))
24394    }
24395
24396    fn minus(&self, other: Self) -> u32 {
24397        self.0 - other.0
24398    }
24399}
24400
24401trait RowRangeExt {
24402    type Row;
24403
24404    fn len(&self) -> usize;
24405
24406    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24407}
24408
24409impl RowRangeExt for Range<MultiBufferRow> {
24410    type Row = MultiBufferRow;
24411
24412    fn len(&self) -> usize {
24413        (self.end.0 - self.start.0) as usize
24414    }
24415
24416    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24417        (self.start.0..self.end.0).map(MultiBufferRow)
24418    }
24419}
24420
24421impl RowRangeExt for Range<DisplayRow> {
24422    type Row = DisplayRow;
24423
24424    fn len(&self) -> usize {
24425        (self.end.0 - self.start.0) as usize
24426    }
24427
24428    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24429        (self.start.0..self.end.0).map(DisplayRow)
24430    }
24431}
24432
24433/// If select range has more than one line, we
24434/// just point the cursor to range.start.
24435fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24436    if range.start.row == range.end.row {
24437        range
24438    } else {
24439        range.start..range.start
24440    }
24441}
24442pub struct KillRing(ClipboardItem);
24443impl Global for KillRing {}
24444
24445const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24446
24447enum BreakpointPromptEditAction {
24448    Log,
24449    Condition,
24450    HitCondition,
24451}
24452
24453struct BreakpointPromptEditor {
24454    pub(crate) prompt: Entity<Editor>,
24455    editor: WeakEntity<Editor>,
24456    breakpoint_anchor: Anchor,
24457    breakpoint: Breakpoint,
24458    edit_action: BreakpointPromptEditAction,
24459    block_ids: HashSet<CustomBlockId>,
24460    editor_margins: Arc<Mutex<EditorMargins>>,
24461    _subscriptions: Vec<Subscription>,
24462}
24463
24464impl BreakpointPromptEditor {
24465    const MAX_LINES: u8 = 4;
24466
24467    fn new(
24468        editor: WeakEntity<Editor>,
24469        breakpoint_anchor: Anchor,
24470        breakpoint: Breakpoint,
24471        edit_action: BreakpointPromptEditAction,
24472        window: &mut Window,
24473        cx: &mut Context<Self>,
24474    ) -> Self {
24475        let base_text = match edit_action {
24476            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24477            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24478            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24479        }
24480        .map(|msg| msg.to_string())
24481        .unwrap_or_default();
24482
24483        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24484        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24485
24486        let prompt = cx.new(|cx| {
24487            let mut prompt = Editor::new(
24488                EditorMode::AutoHeight {
24489                    min_lines: 1,
24490                    max_lines: Some(Self::MAX_LINES as usize),
24491                },
24492                buffer,
24493                None,
24494                window,
24495                cx,
24496            );
24497            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24498            prompt.set_show_cursor_when_unfocused(false, cx);
24499            prompt.set_placeholder_text(
24500                match edit_action {
24501                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24502                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24503                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24504                },
24505                window,
24506                cx,
24507            );
24508
24509            prompt
24510        });
24511
24512        Self {
24513            prompt,
24514            editor,
24515            breakpoint_anchor,
24516            breakpoint,
24517            edit_action,
24518            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24519            block_ids: Default::default(),
24520            _subscriptions: vec![],
24521        }
24522    }
24523
24524    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24525        self.block_ids.extend(block_ids)
24526    }
24527
24528    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24529        if let Some(editor) = self.editor.upgrade() {
24530            let message = self
24531                .prompt
24532                .read(cx)
24533                .buffer
24534                .read(cx)
24535                .as_singleton()
24536                .expect("A multi buffer in breakpoint prompt isn't possible")
24537                .read(cx)
24538                .as_rope()
24539                .to_string();
24540
24541            editor.update(cx, |editor, cx| {
24542                editor.edit_breakpoint_at_anchor(
24543                    self.breakpoint_anchor,
24544                    self.breakpoint.clone(),
24545                    match self.edit_action {
24546                        BreakpointPromptEditAction::Log => {
24547                            BreakpointEditAction::EditLogMessage(message.into())
24548                        }
24549                        BreakpointPromptEditAction::Condition => {
24550                            BreakpointEditAction::EditCondition(message.into())
24551                        }
24552                        BreakpointPromptEditAction::HitCondition => {
24553                            BreakpointEditAction::EditHitCondition(message.into())
24554                        }
24555                    },
24556                    cx,
24557                );
24558
24559                editor.remove_blocks(self.block_ids.clone(), None, cx);
24560                cx.focus_self(window);
24561            });
24562        }
24563    }
24564
24565    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24566        self.editor
24567            .update(cx, |editor, cx| {
24568                editor.remove_blocks(self.block_ids.clone(), None, cx);
24569                window.focus(&editor.focus_handle);
24570            })
24571            .log_err();
24572    }
24573
24574    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24575        let settings = ThemeSettings::get_global(cx);
24576        let text_style = TextStyle {
24577            color: if self.prompt.read(cx).read_only(cx) {
24578                cx.theme().colors().text_disabled
24579            } else {
24580                cx.theme().colors().text
24581            },
24582            font_family: settings.buffer_font.family.clone(),
24583            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24584            font_size: settings.buffer_font_size(cx).into(),
24585            font_weight: settings.buffer_font.weight,
24586            line_height: relative(settings.buffer_line_height.value()),
24587            ..Default::default()
24588        };
24589        EditorElement::new(
24590            &self.prompt,
24591            EditorStyle {
24592                background: cx.theme().colors().editor_background,
24593                local_player: cx.theme().players().local(),
24594                text: text_style,
24595                ..Default::default()
24596            },
24597        )
24598    }
24599}
24600
24601impl Render for BreakpointPromptEditor {
24602    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24603        let editor_margins = *self.editor_margins.lock();
24604        let gutter_dimensions = editor_margins.gutter;
24605        h_flex()
24606            .key_context("Editor")
24607            .bg(cx.theme().colors().editor_background)
24608            .border_y_1()
24609            .border_color(cx.theme().status().info_border)
24610            .size_full()
24611            .py(window.line_height() / 2.5)
24612            .on_action(cx.listener(Self::confirm))
24613            .on_action(cx.listener(Self::cancel))
24614            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24615            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24616    }
24617}
24618
24619impl Focusable for BreakpointPromptEditor {
24620    fn focus_handle(&self, cx: &App) -> FocusHandle {
24621        self.prompt.focus_handle(cx)
24622    }
24623}
24624
24625fn all_edits_insertions_or_deletions(
24626    edits: &Vec<(Range<Anchor>, String)>,
24627    snapshot: &MultiBufferSnapshot,
24628) -> bool {
24629    let mut all_insertions = true;
24630    let mut all_deletions = true;
24631
24632    for (range, new_text) in edits.iter() {
24633        let range_is_empty = range.to_offset(snapshot).is_empty();
24634        let text_is_empty = new_text.is_empty();
24635
24636        if range_is_empty != text_is_empty {
24637            if range_is_empty {
24638                all_deletions = false;
24639            } else {
24640                all_insertions = false;
24641            }
24642        } else {
24643            return false;
24644        }
24645
24646        if !all_insertions && !all_deletions {
24647            return false;
24648        }
24649    }
24650    all_insertions || all_deletions
24651}
24652
24653struct MissingEditPredictionKeybindingTooltip;
24654
24655impl Render for MissingEditPredictionKeybindingTooltip {
24656    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24657        ui::tooltip_container(cx, |container, cx| {
24658            container
24659                .flex_shrink_0()
24660                .max_w_80()
24661                .min_h(rems_from_px(124.))
24662                .justify_between()
24663                .child(
24664                    v_flex()
24665                        .flex_1()
24666                        .text_ui_sm(cx)
24667                        .child(Label::new("Conflict with Accept Keybinding"))
24668                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24669                )
24670                .child(
24671                    h_flex()
24672                        .pb_1()
24673                        .gap_1()
24674                        .items_end()
24675                        .w_full()
24676                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24677                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24678                        }))
24679                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24680                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24681                        })),
24682                )
24683        })
24684    }
24685}
24686
24687#[derive(Debug, Clone, Copy, PartialEq)]
24688pub struct LineHighlight {
24689    pub background: Background,
24690    pub border: Option<gpui::Hsla>,
24691    pub include_gutter: bool,
24692    pub type_id: Option<TypeId>,
24693}
24694
24695struct LineManipulationResult {
24696    pub new_text: String,
24697    pub line_count_before: usize,
24698    pub line_count_after: usize,
24699}
24700
24701fn render_diff_hunk_controls(
24702    row: u32,
24703    status: &DiffHunkStatus,
24704    hunk_range: Range<Anchor>,
24705    is_created_file: bool,
24706    line_height: Pixels,
24707    editor: &Entity<Editor>,
24708    _window: &mut Window,
24709    cx: &mut App,
24710) -> AnyElement {
24711    h_flex()
24712        .h(line_height)
24713        .mr_1()
24714        .gap_1()
24715        .px_0p5()
24716        .pb_1()
24717        .border_x_1()
24718        .border_b_1()
24719        .border_color(cx.theme().colors().border_variant)
24720        .rounded_b_lg()
24721        .bg(cx.theme().colors().editor_background)
24722        .gap_1()
24723        .block_mouse_except_scroll()
24724        .shadow_md()
24725        .child(if status.has_secondary_hunk() {
24726            Button::new(("stage", row as u64), "Stage")
24727                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24728                .tooltip({
24729                    let focus_handle = editor.focus_handle(cx);
24730                    move |_window, cx| {
24731                        Tooltip::for_action_in(
24732                            "Stage Hunk",
24733                            &::git::ToggleStaged,
24734                            &focus_handle,
24735                            cx,
24736                        )
24737                    }
24738                })
24739                .on_click({
24740                    let editor = editor.clone();
24741                    move |_event, _window, cx| {
24742                        editor.update(cx, |editor, cx| {
24743                            editor.stage_or_unstage_diff_hunks(
24744                                true,
24745                                vec![hunk_range.start..hunk_range.start],
24746                                cx,
24747                            );
24748                        });
24749                    }
24750                })
24751        } else {
24752            Button::new(("unstage", row as u64), "Unstage")
24753                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24754                .tooltip({
24755                    let focus_handle = editor.focus_handle(cx);
24756                    move |_window, cx| {
24757                        Tooltip::for_action_in(
24758                            "Unstage Hunk",
24759                            &::git::ToggleStaged,
24760                            &focus_handle,
24761                            cx,
24762                        )
24763                    }
24764                })
24765                .on_click({
24766                    let editor = editor.clone();
24767                    move |_event, _window, cx| {
24768                        editor.update(cx, |editor, cx| {
24769                            editor.stage_or_unstage_diff_hunks(
24770                                false,
24771                                vec![hunk_range.start..hunk_range.start],
24772                                cx,
24773                            );
24774                        });
24775                    }
24776                })
24777        })
24778        .child(
24779            Button::new(("restore", row as u64), "Restore")
24780                .tooltip({
24781                    let focus_handle = editor.focus_handle(cx);
24782                    move |_window, cx| {
24783                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
24784                    }
24785                })
24786                .on_click({
24787                    let editor = editor.clone();
24788                    move |_event, window, cx| {
24789                        editor.update(cx, |editor, cx| {
24790                            let snapshot = editor.snapshot(window, cx);
24791                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24792                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24793                        });
24794                    }
24795                })
24796                .disabled(is_created_file),
24797        )
24798        .when(
24799            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24800            |el| {
24801                el.child(
24802                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24803                        .shape(IconButtonShape::Square)
24804                        .icon_size(IconSize::Small)
24805                        // .disabled(!has_multiple_hunks)
24806                        .tooltip({
24807                            let focus_handle = editor.focus_handle(cx);
24808                            move |_window, cx| {
24809                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
24810                            }
24811                        })
24812                        .on_click({
24813                            let editor = editor.clone();
24814                            move |_event, window, cx| {
24815                                editor.update(cx, |editor, cx| {
24816                                    let snapshot = editor.snapshot(window, cx);
24817                                    let position =
24818                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24819                                    editor.go_to_hunk_before_or_after_position(
24820                                        &snapshot,
24821                                        position,
24822                                        Direction::Next,
24823                                        window,
24824                                        cx,
24825                                    );
24826                                    editor.expand_selected_diff_hunks(cx);
24827                                });
24828                            }
24829                        }),
24830                )
24831                .child(
24832                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24833                        .shape(IconButtonShape::Square)
24834                        .icon_size(IconSize::Small)
24835                        // .disabled(!has_multiple_hunks)
24836                        .tooltip({
24837                            let focus_handle = editor.focus_handle(cx);
24838                            move |_window, cx| {
24839                                Tooltip::for_action_in(
24840                                    "Previous Hunk",
24841                                    &GoToPreviousHunk,
24842                                    &focus_handle,
24843                                    cx,
24844                                )
24845                            }
24846                        })
24847                        .on_click({
24848                            let editor = editor.clone();
24849                            move |_event, window, cx| {
24850                                editor.update(cx, |editor, cx| {
24851                                    let snapshot = editor.snapshot(window, cx);
24852                                    let point =
24853                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24854                                    editor.go_to_hunk_before_or_after_position(
24855                                        &snapshot,
24856                                        point,
24857                                        Direction::Prev,
24858                                        window,
24859                                        cx,
24860                                    );
24861                                    editor.expand_selected_diff_hunks(cx);
24862                                });
24863                            }
24864                        }),
24865                )
24866            },
24867        )
24868        .into_any_element()
24869}
24870
24871pub fn multibuffer_context_lines(cx: &App) -> u32 {
24872    EditorSettings::try_get(cx)
24873        .map(|settings| settings.excerpt_context_lines)
24874        .unwrap_or(2)
24875        .min(32)
24876}