editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//!
   11//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   12//!
   13//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   14pub mod actions;
   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(&current_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(&current_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, &region.pair.start)
 5023                            && buffer.contains_str_at(range.end, &region.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 = &regions[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 should_scroll_up = false;
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                should_scroll_up = lines_below >= lines_to_expand;
15862            }
15863        }
15864
15865        self.buffer.update(cx, |buffer, cx| {
15866            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15867        });
15868
15869        if should_scroll_up {
15870            let new_scroll_position =
15871                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
15872            self.set_scroll_position(new_scroll_position, window, cx);
15873        }
15874    }
15875
15876    pub fn go_to_singleton_buffer_point(
15877        &mut self,
15878        point: Point,
15879        window: &mut Window,
15880        cx: &mut Context<Self>,
15881    ) {
15882        self.go_to_singleton_buffer_range(point..point, window, cx);
15883    }
15884
15885    pub fn go_to_singleton_buffer_range(
15886        &mut self,
15887        range: Range<Point>,
15888        window: &mut Window,
15889        cx: &mut Context<Self>,
15890    ) {
15891        let multibuffer = self.buffer().read(cx);
15892        let Some(buffer) = multibuffer.as_singleton() else {
15893            return;
15894        };
15895        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15896            return;
15897        };
15898        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15899            return;
15900        };
15901        self.change_selections(
15902            SelectionEffects::default().nav_history(true),
15903            window,
15904            cx,
15905            |s| s.select_anchor_ranges([start..end]),
15906        );
15907    }
15908
15909    pub fn go_to_diagnostic(
15910        &mut self,
15911        action: &GoToDiagnostic,
15912        window: &mut Window,
15913        cx: &mut Context<Self>,
15914    ) {
15915        if !self.diagnostics_enabled() {
15916            return;
15917        }
15918        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15919        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15920    }
15921
15922    pub fn go_to_prev_diagnostic(
15923        &mut self,
15924        action: &GoToPreviousDiagnostic,
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::Prev, action.severity, window, cx)
15933    }
15934
15935    pub fn go_to_diagnostic_impl(
15936        &mut self,
15937        direction: Direction,
15938        severity: GoToDiagnosticSeverityFilter,
15939        window: &mut Window,
15940        cx: &mut Context<Self>,
15941    ) {
15942        let buffer = self.buffer.read(cx).snapshot(cx);
15943        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
15944
15945        let mut active_group_id = None;
15946        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15947            && active_group.active_range.start.to_offset(&buffer) == selection.start
15948        {
15949            active_group_id = Some(active_group.group_id);
15950        }
15951
15952        fn filtered<'a>(
15953            snapshot: EditorSnapshot,
15954            severity: GoToDiagnosticSeverityFilter,
15955            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
15956        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
15957            diagnostics
15958                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15959                .filter(|entry| entry.range.start != entry.range.end)
15960                .filter(|entry| !entry.diagnostic.is_unnecessary)
15961                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15962        }
15963
15964        let snapshot = self.snapshot(window, cx);
15965        let before = filtered(
15966            snapshot.clone(),
15967            severity,
15968            buffer
15969                .diagnostics_in_range(0..selection.start)
15970                .filter(|entry| entry.range.start <= selection.start),
15971        );
15972        let after = filtered(
15973            snapshot,
15974            severity,
15975            buffer
15976                .diagnostics_in_range(selection.start..buffer.len())
15977                .filter(|entry| entry.range.start >= selection.start),
15978        );
15979
15980        let mut found: Option<DiagnosticEntryRef<usize>> = None;
15981        if direction == Direction::Prev {
15982            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15983            {
15984                for diagnostic in prev_diagnostics.into_iter().rev() {
15985                    if diagnostic.range.start != selection.start
15986                        || active_group_id
15987                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15988                    {
15989                        found = Some(diagnostic);
15990                        break 'outer;
15991                    }
15992                }
15993            }
15994        } else {
15995            for diagnostic in after.chain(before) {
15996                if diagnostic.range.start != selection.start
15997                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15998                {
15999                    found = Some(diagnostic);
16000                    break;
16001                }
16002            }
16003        }
16004        let Some(next_diagnostic) = found else {
16005            return;
16006        };
16007
16008        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16009        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16010            return;
16011        };
16012        self.change_selections(Default::default(), window, cx, |s| {
16013            s.select_ranges(vec![
16014                next_diagnostic.range.start..next_diagnostic.range.start,
16015            ])
16016        });
16017        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16018        self.refresh_edit_prediction(false, true, window, cx);
16019    }
16020
16021    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16022        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16023        let snapshot = self.snapshot(window, cx);
16024        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16025        self.go_to_hunk_before_or_after_position(
16026            &snapshot,
16027            selection.head(),
16028            Direction::Next,
16029            window,
16030            cx,
16031        );
16032    }
16033
16034    pub fn go_to_hunk_before_or_after_position(
16035        &mut self,
16036        snapshot: &EditorSnapshot,
16037        position: Point,
16038        direction: Direction,
16039        window: &mut Window,
16040        cx: &mut Context<Editor>,
16041    ) {
16042        let row = if direction == Direction::Next {
16043            self.hunk_after_position(snapshot, position)
16044                .map(|hunk| hunk.row_range.start)
16045        } else {
16046            self.hunk_before_position(snapshot, position)
16047        };
16048
16049        if let Some(row) = row {
16050            let destination = Point::new(row.0, 0);
16051            let autoscroll = Autoscroll::center();
16052
16053            self.unfold_ranges(&[destination..destination], false, false, cx);
16054            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16055                s.select_ranges([destination..destination]);
16056            });
16057        }
16058    }
16059
16060    fn hunk_after_position(
16061        &mut self,
16062        snapshot: &EditorSnapshot,
16063        position: Point,
16064    ) -> Option<MultiBufferDiffHunk> {
16065        snapshot
16066            .buffer_snapshot()
16067            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16068            .find(|hunk| hunk.row_range.start.0 > position.row)
16069            .or_else(|| {
16070                snapshot
16071                    .buffer_snapshot()
16072                    .diff_hunks_in_range(Point::zero()..position)
16073                    .find(|hunk| hunk.row_range.end.0 < position.row)
16074            })
16075    }
16076
16077    fn go_to_prev_hunk(
16078        &mut self,
16079        _: &GoToPreviousHunk,
16080        window: &mut Window,
16081        cx: &mut Context<Self>,
16082    ) {
16083        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16084        let snapshot = self.snapshot(window, cx);
16085        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16086        self.go_to_hunk_before_or_after_position(
16087            &snapshot,
16088            selection.head(),
16089            Direction::Prev,
16090            window,
16091            cx,
16092        );
16093    }
16094
16095    fn hunk_before_position(
16096        &mut self,
16097        snapshot: &EditorSnapshot,
16098        position: Point,
16099    ) -> Option<MultiBufferRow> {
16100        snapshot
16101            .buffer_snapshot()
16102            .diff_hunk_before(position)
16103            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16104    }
16105
16106    fn go_to_next_change(
16107        &mut self,
16108        _: &GoToNextChange,
16109        window: &mut Window,
16110        cx: &mut Context<Self>,
16111    ) {
16112        if let Some(selections) = self
16113            .change_list
16114            .next_change(1, Direction::Next)
16115            .map(|s| s.to_vec())
16116        {
16117            self.change_selections(Default::default(), window, cx, |s| {
16118                let map = s.display_map();
16119                s.select_display_ranges(selections.iter().map(|a| {
16120                    let point = a.to_display_point(&map);
16121                    point..point
16122                }))
16123            })
16124        }
16125    }
16126
16127    fn go_to_previous_change(
16128        &mut self,
16129        _: &GoToPreviousChange,
16130        window: &mut Window,
16131        cx: &mut Context<Self>,
16132    ) {
16133        if let Some(selections) = self
16134            .change_list
16135            .next_change(1, Direction::Prev)
16136            .map(|s| s.to_vec())
16137        {
16138            self.change_selections(Default::default(), window, cx, |s| {
16139                let map = s.display_map();
16140                s.select_display_ranges(selections.iter().map(|a| {
16141                    let point = a.to_display_point(&map);
16142                    point..point
16143                }))
16144            })
16145        }
16146    }
16147
16148    pub fn go_to_next_document_highlight(
16149        &mut self,
16150        _: &GoToNextDocumentHighlight,
16151        window: &mut Window,
16152        cx: &mut Context<Self>,
16153    ) {
16154        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16155    }
16156
16157    pub fn go_to_prev_document_highlight(
16158        &mut self,
16159        _: &GoToPreviousDocumentHighlight,
16160        window: &mut Window,
16161        cx: &mut Context<Self>,
16162    ) {
16163        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16164    }
16165
16166    pub fn go_to_document_highlight_before_or_after_position(
16167        &mut self,
16168        direction: Direction,
16169        window: &mut Window,
16170        cx: &mut Context<Editor>,
16171    ) {
16172        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16173        let snapshot = self.snapshot(window, cx);
16174        let buffer = &snapshot.buffer_snapshot();
16175        let position = self
16176            .selections
16177            .newest::<Point>(&snapshot.display_snapshot)
16178            .head();
16179        let anchor_position = buffer.anchor_after(position);
16180
16181        // Get all document highlights (both read and write)
16182        let mut all_highlights = Vec::new();
16183
16184        if let Some((_, read_highlights)) = self
16185            .background_highlights
16186            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16187        {
16188            all_highlights.extend(read_highlights.iter());
16189        }
16190
16191        if let Some((_, write_highlights)) = self
16192            .background_highlights
16193            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16194        {
16195            all_highlights.extend(write_highlights.iter());
16196        }
16197
16198        if all_highlights.is_empty() {
16199            return;
16200        }
16201
16202        // Sort highlights by position
16203        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16204
16205        let target_highlight = match direction {
16206            Direction::Next => {
16207                // Find the first highlight after the current position
16208                all_highlights
16209                    .iter()
16210                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16211            }
16212            Direction::Prev => {
16213                // Find the last highlight before the current position
16214                all_highlights
16215                    .iter()
16216                    .rev()
16217                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16218            }
16219        };
16220
16221        if let Some(highlight) = target_highlight {
16222            let destination = highlight.start.to_point(buffer);
16223            let autoscroll = Autoscroll::center();
16224
16225            self.unfold_ranges(&[destination..destination], false, false, cx);
16226            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16227                s.select_ranges([destination..destination]);
16228            });
16229        }
16230    }
16231
16232    fn go_to_line<T: 'static>(
16233        &mut self,
16234        position: Anchor,
16235        highlight_color: Option<Hsla>,
16236        window: &mut Window,
16237        cx: &mut Context<Self>,
16238    ) {
16239        let snapshot = self.snapshot(window, cx).display_snapshot;
16240        let position = position.to_point(&snapshot.buffer_snapshot());
16241        let start = snapshot
16242            .buffer_snapshot()
16243            .clip_point(Point::new(position.row, 0), Bias::Left);
16244        let end = start + Point::new(1, 0);
16245        let start = snapshot.buffer_snapshot().anchor_before(start);
16246        let end = snapshot.buffer_snapshot().anchor_before(end);
16247
16248        self.highlight_rows::<T>(
16249            start..end,
16250            highlight_color
16251                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16252            Default::default(),
16253            cx,
16254        );
16255
16256        if self.buffer.read(cx).is_singleton() {
16257            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16258        }
16259    }
16260
16261    pub fn go_to_definition(
16262        &mut self,
16263        _: &GoToDefinition,
16264        window: &mut Window,
16265        cx: &mut Context<Self>,
16266    ) -> Task<Result<Navigated>> {
16267        let definition =
16268            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16269        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16270        cx.spawn_in(window, async move |editor, cx| {
16271            if definition.await? == Navigated::Yes {
16272                return Ok(Navigated::Yes);
16273            }
16274            match fallback_strategy {
16275                GoToDefinitionFallback::None => Ok(Navigated::No),
16276                GoToDefinitionFallback::FindAllReferences => {
16277                    match editor.update_in(cx, |editor, window, cx| {
16278                        editor.find_all_references(&FindAllReferences, window, cx)
16279                    })? {
16280                        Some(references) => references.await,
16281                        None => Ok(Navigated::No),
16282                    }
16283                }
16284            }
16285        })
16286    }
16287
16288    pub fn go_to_declaration(
16289        &mut self,
16290        _: &GoToDeclaration,
16291        window: &mut Window,
16292        cx: &mut Context<Self>,
16293    ) -> Task<Result<Navigated>> {
16294        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16295    }
16296
16297    pub fn go_to_declaration_split(
16298        &mut self,
16299        _: &GoToDeclaration,
16300        window: &mut Window,
16301        cx: &mut Context<Self>,
16302    ) -> Task<Result<Navigated>> {
16303        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16304    }
16305
16306    pub fn go_to_implementation(
16307        &mut self,
16308        _: &GoToImplementation,
16309        window: &mut Window,
16310        cx: &mut Context<Self>,
16311    ) -> Task<Result<Navigated>> {
16312        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16313    }
16314
16315    pub fn go_to_implementation_split(
16316        &mut self,
16317        _: &GoToImplementationSplit,
16318        window: &mut Window,
16319        cx: &mut Context<Self>,
16320    ) -> Task<Result<Navigated>> {
16321        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16322    }
16323
16324    pub fn go_to_type_definition(
16325        &mut self,
16326        _: &GoToTypeDefinition,
16327        window: &mut Window,
16328        cx: &mut Context<Self>,
16329    ) -> Task<Result<Navigated>> {
16330        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16331    }
16332
16333    pub fn go_to_definition_split(
16334        &mut self,
16335        _: &GoToDefinitionSplit,
16336        window: &mut Window,
16337        cx: &mut Context<Self>,
16338    ) -> Task<Result<Navigated>> {
16339        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16340    }
16341
16342    pub fn go_to_type_definition_split(
16343        &mut self,
16344        _: &GoToTypeDefinitionSplit,
16345        window: &mut Window,
16346        cx: &mut Context<Self>,
16347    ) -> Task<Result<Navigated>> {
16348        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16349    }
16350
16351    fn go_to_definition_of_kind(
16352        &mut self,
16353        kind: GotoDefinitionKind,
16354        split: bool,
16355        window: &mut Window,
16356        cx: &mut Context<Self>,
16357    ) -> Task<Result<Navigated>> {
16358        let Some(provider) = self.semantics_provider.clone() else {
16359            return Task::ready(Ok(Navigated::No));
16360        };
16361        let head = self
16362            .selections
16363            .newest::<usize>(&self.display_snapshot(cx))
16364            .head();
16365        let buffer = self.buffer.read(cx);
16366        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16367            return Task::ready(Ok(Navigated::No));
16368        };
16369        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16370            return Task::ready(Ok(Navigated::No));
16371        };
16372
16373        cx.spawn_in(window, async move |editor, cx| {
16374            let Some(definitions) = definitions.await? else {
16375                return Ok(Navigated::No);
16376            };
16377            let navigated = editor
16378                .update_in(cx, |editor, window, cx| {
16379                    editor.navigate_to_hover_links(
16380                        Some(kind),
16381                        definitions
16382                            .into_iter()
16383                            .filter(|location| {
16384                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16385                            })
16386                            .map(HoverLink::Text)
16387                            .collect::<Vec<_>>(),
16388                        split,
16389                        window,
16390                        cx,
16391                    )
16392                })?
16393                .await?;
16394            anyhow::Ok(navigated)
16395        })
16396    }
16397
16398    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16399        let selection = self.selections.newest_anchor();
16400        let head = selection.head();
16401        let tail = selection.tail();
16402
16403        let Some((buffer, start_position)) =
16404            self.buffer.read(cx).text_anchor_for_position(head, cx)
16405        else {
16406            return;
16407        };
16408
16409        let end_position = if head != tail {
16410            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16411                return;
16412            };
16413            Some(pos)
16414        } else {
16415            None
16416        };
16417
16418        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16419            let url = if let Some(end_pos) = end_position {
16420                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16421            } else {
16422                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16423            };
16424
16425            if let Some(url) = url {
16426                cx.update(|window, cx| {
16427                    if parse_zed_link(&url, cx).is_some() {
16428                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16429                    } else {
16430                        cx.open_url(&url);
16431                    }
16432                })?;
16433            }
16434
16435            anyhow::Ok(())
16436        });
16437
16438        url_finder.detach();
16439    }
16440
16441    pub fn open_selected_filename(
16442        &mut self,
16443        _: &OpenSelectedFilename,
16444        window: &mut Window,
16445        cx: &mut Context<Self>,
16446    ) {
16447        let Some(workspace) = self.workspace() else {
16448            return;
16449        };
16450
16451        let position = self.selections.newest_anchor().head();
16452
16453        let Some((buffer, buffer_position)) =
16454            self.buffer.read(cx).text_anchor_for_position(position, cx)
16455        else {
16456            return;
16457        };
16458
16459        let project = self.project.clone();
16460
16461        cx.spawn_in(window, async move |_, cx| {
16462            let result = find_file(&buffer, project, buffer_position, cx).await;
16463
16464            if let Some((_, path)) = result {
16465                workspace
16466                    .update_in(cx, |workspace, window, cx| {
16467                        workspace.open_resolved_path(path, window, cx)
16468                    })?
16469                    .await?;
16470            }
16471            anyhow::Ok(())
16472        })
16473        .detach();
16474    }
16475
16476    pub(crate) fn navigate_to_hover_links(
16477        &mut self,
16478        kind: Option<GotoDefinitionKind>,
16479        definitions: Vec<HoverLink>,
16480        split: bool,
16481        window: &mut Window,
16482        cx: &mut Context<Editor>,
16483    ) -> Task<Result<Navigated>> {
16484        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16485        let mut first_url_or_file = None;
16486        let definitions: Vec<_> = definitions
16487            .into_iter()
16488            .filter_map(|def| match def {
16489                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16490                HoverLink::InlayHint(lsp_location, server_id) => {
16491                    let computation =
16492                        self.compute_target_location(lsp_location, server_id, window, cx);
16493                    Some(cx.background_spawn(computation))
16494                }
16495                HoverLink::Url(url) => {
16496                    first_url_or_file = Some(Either::Left(url));
16497                    None
16498                }
16499                HoverLink::File(path) => {
16500                    first_url_or_file = Some(Either::Right(path));
16501                    None
16502                }
16503            })
16504            .collect();
16505
16506        let workspace = self.workspace();
16507
16508        cx.spawn_in(window, async move |editor, cx| {
16509            let locations: Vec<Location> = future::join_all(definitions)
16510                .await
16511                .into_iter()
16512                .filter_map(|location| location.transpose())
16513                .collect::<Result<_>>()
16514                .context("location tasks")?;
16515            let mut locations = cx.update(|_, cx| {
16516                locations
16517                    .into_iter()
16518                    .map(|location| {
16519                        let buffer = location.buffer.read(cx);
16520                        (location.buffer, location.range.to_point(buffer))
16521                    })
16522                    .into_group_map()
16523            })?;
16524            let mut num_locations = 0;
16525            for ranges in locations.values_mut() {
16526                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16527                ranges.dedup();
16528                num_locations += ranges.len();
16529            }
16530
16531            if num_locations > 1 {
16532                let Some(workspace) = workspace else {
16533                    return Ok(Navigated::No);
16534                };
16535
16536                let tab_kind = match kind {
16537                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16538                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16539                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16540                    Some(GotoDefinitionKind::Type) => "Types",
16541                };
16542                let title = editor
16543                    .update_in(cx, |_, _, cx| {
16544                        let target = locations
16545                            .iter()
16546                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16547                            .map(|(buffer, location)| {
16548                                buffer
16549                                    .read(cx)
16550                                    .text_for_range(location.clone())
16551                                    .collect::<String>()
16552                            })
16553                            .filter(|text| !text.contains('\n'))
16554                            .unique()
16555                            .take(3)
16556                            .join(", ");
16557                        if target.is_empty() {
16558                            tab_kind.to_owned()
16559                        } else {
16560                            format!("{tab_kind} for {target}")
16561                        }
16562                    })
16563                    .context("buffer title")?;
16564
16565                let opened = workspace
16566                    .update_in(cx, |workspace, window, cx| {
16567                        Self::open_locations_in_multibuffer(
16568                            workspace,
16569                            locations,
16570                            title,
16571                            split,
16572                            MultibufferSelectionMode::First,
16573                            window,
16574                            cx,
16575                        )
16576                    })
16577                    .is_ok();
16578
16579                anyhow::Ok(Navigated::from_bool(opened))
16580            } else if num_locations == 0 {
16581                // If there is one url or file, open it directly
16582                match first_url_or_file {
16583                    Some(Either::Left(url)) => {
16584                        cx.update(|_, cx| cx.open_url(&url))?;
16585                        Ok(Navigated::Yes)
16586                    }
16587                    Some(Either::Right(path)) => {
16588                        let Some(workspace) = workspace else {
16589                            return Ok(Navigated::No);
16590                        };
16591
16592                        workspace
16593                            .update_in(cx, |workspace, window, cx| {
16594                                workspace.open_resolved_path(path, window, cx)
16595                            })?
16596                            .await?;
16597                        Ok(Navigated::Yes)
16598                    }
16599                    None => Ok(Navigated::No),
16600                }
16601            } else {
16602                let Some(workspace) = workspace else {
16603                    return Ok(Navigated::No);
16604                };
16605
16606                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16607                let target_range = target_ranges.first().unwrap().clone();
16608
16609                editor.update_in(cx, |editor, window, cx| {
16610                    let range = target_range.to_point(target_buffer.read(cx));
16611                    let range = editor.range_for_match(&range);
16612                    let range = collapse_multiline_range(range);
16613
16614                    if !split
16615                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16616                    {
16617                        editor.go_to_singleton_buffer_range(range, window, cx);
16618                    } else {
16619                        let pane = workspace.read(cx).active_pane().clone();
16620                        window.defer(cx, move |window, cx| {
16621                            let target_editor: Entity<Self> =
16622                                workspace.update(cx, |workspace, cx| {
16623                                    let pane = if split {
16624                                        workspace.adjacent_pane(window, cx)
16625                                    } else {
16626                                        workspace.active_pane().clone()
16627                                    };
16628
16629                                    workspace.open_project_item(
16630                                        pane,
16631                                        target_buffer.clone(),
16632                                        true,
16633                                        true,
16634                                        window,
16635                                        cx,
16636                                    )
16637                                });
16638                            target_editor.update(cx, |target_editor, cx| {
16639                                // When selecting a definition in a different buffer, disable the nav history
16640                                // to avoid creating a history entry at the previous cursor location.
16641                                pane.update(cx, |pane, _| pane.disable_history());
16642                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16643                                pane.update(cx, |pane, _| pane.enable_history());
16644                            });
16645                        });
16646                    }
16647                    Navigated::Yes
16648                })
16649            }
16650        })
16651    }
16652
16653    fn compute_target_location(
16654        &self,
16655        lsp_location: lsp::Location,
16656        server_id: LanguageServerId,
16657        window: &mut Window,
16658        cx: &mut Context<Self>,
16659    ) -> Task<anyhow::Result<Option<Location>>> {
16660        let Some(project) = self.project.clone() else {
16661            return Task::ready(Ok(None));
16662        };
16663
16664        cx.spawn_in(window, async move |editor, cx| {
16665            let location_task = editor.update(cx, |_, cx| {
16666                project.update(cx, |project, cx| {
16667                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16668                })
16669            })?;
16670            let location = Some({
16671                let target_buffer_handle = location_task.await.context("open local buffer")?;
16672                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16673                    let target_start = target_buffer
16674                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16675                    let target_end = target_buffer
16676                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16677                    target_buffer.anchor_after(target_start)
16678                        ..target_buffer.anchor_before(target_end)
16679                })?;
16680                Location {
16681                    buffer: target_buffer_handle,
16682                    range,
16683                }
16684            });
16685            Ok(location)
16686        })
16687    }
16688
16689    pub fn find_all_references(
16690        &mut self,
16691        _: &FindAllReferences,
16692        window: &mut Window,
16693        cx: &mut Context<Self>,
16694    ) -> Option<Task<Result<Navigated>>> {
16695        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16696        let multi_buffer = self.buffer.read(cx);
16697        let head = selection.head();
16698
16699        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16700        let head_anchor = multi_buffer_snapshot.anchor_at(
16701            head,
16702            if head < selection.tail() {
16703                Bias::Right
16704            } else {
16705                Bias::Left
16706            },
16707        );
16708
16709        match self
16710            .find_all_references_task_sources
16711            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16712        {
16713            Ok(_) => {
16714                log::info!(
16715                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16716                );
16717                return None;
16718            }
16719            Err(i) => {
16720                self.find_all_references_task_sources.insert(i, head_anchor);
16721            }
16722        }
16723
16724        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16725        let workspace = self.workspace()?;
16726        let project = workspace.read(cx).project().clone();
16727        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16728        Some(cx.spawn_in(window, async move |editor, cx| {
16729            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16730                if let Ok(i) = editor
16731                    .find_all_references_task_sources
16732                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16733                {
16734                    editor.find_all_references_task_sources.remove(i);
16735                }
16736            });
16737
16738            let Some(locations) = references.await? else {
16739                return anyhow::Ok(Navigated::No);
16740            };
16741            let mut locations = cx.update(|_, cx| {
16742                locations
16743                    .into_iter()
16744                    .map(|location| {
16745                        let buffer = location.buffer.read(cx);
16746                        (location.buffer, location.range.to_point(buffer))
16747                    })
16748                    .into_group_map()
16749            })?;
16750            if locations.is_empty() {
16751                return anyhow::Ok(Navigated::No);
16752            }
16753            for ranges in locations.values_mut() {
16754                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16755                ranges.dedup();
16756            }
16757
16758            workspace.update_in(cx, |workspace, window, cx| {
16759                let target = locations
16760                    .iter()
16761                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16762                    .map(|(buffer, location)| {
16763                        buffer
16764                            .read(cx)
16765                            .text_for_range(location.clone())
16766                            .collect::<String>()
16767                    })
16768                    .filter(|text| !text.contains('\n'))
16769                    .unique()
16770                    .take(3)
16771                    .join(", ");
16772                let title = if target.is_empty() {
16773                    "References".to_owned()
16774                } else {
16775                    format!("References to {target}")
16776                };
16777                Self::open_locations_in_multibuffer(
16778                    workspace,
16779                    locations,
16780                    title,
16781                    false,
16782                    MultibufferSelectionMode::First,
16783                    window,
16784                    cx,
16785                );
16786                Navigated::Yes
16787            })
16788        }))
16789    }
16790
16791    /// Opens a multibuffer with the given project locations in it
16792    pub fn open_locations_in_multibuffer(
16793        workspace: &mut Workspace,
16794        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16795        title: String,
16796        split: bool,
16797        multibuffer_selection_mode: MultibufferSelectionMode,
16798        window: &mut Window,
16799        cx: &mut Context<Workspace>,
16800    ) {
16801        if locations.is_empty() {
16802            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16803            return;
16804        }
16805
16806        let capability = workspace.project().read(cx).capability();
16807        let mut ranges = <Vec<Range<Anchor>>>::new();
16808
16809        // a key to find existing multibuffer editors with the same set of locations
16810        // to prevent us from opening more and more multibuffer tabs for searches and the like
16811        let mut key = (title.clone(), vec![]);
16812        let excerpt_buffer = cx.new(|cx| {
16813            let key = &mut key.1;
16814            let mut multibuffer = MultiBuffer::new(capability);
16815            for (buffer, mut ranges_for_buffer) in locations {
16816                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16817                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16818                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16819                    PathKey::for_buffer(&buffer, cx),
16820                    buffer.clone(),
16821                    ranges_for_buffer,
16822                    multibuffer_context_lines(cx),
16823                    cx,
16824                );
16825                ranges.extend(new_ranges)
16826            }
16827
16828            multibuffer.with_title(title)
16829        });
16830        let existing = workspace.active_pane().update(cx, |pane, cx| {
16831            pane.items()
16832                .filter_map(|item| item.downcast::<Editor>())
16833                .find(|editor| {
16834                    editor
16835                        .read(cx)
16836                        .lookup_key
16837                        .as_ref()
16838                        .and_then(|it| {
16839                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16840                        })
16841                        .is_some_and(|it| *it == key)
16842                })
16843        });
16844        let editor = existing.unwrap_or_else(|| {
16845            cx.new(|cx| {
16846                let mut editor = Editor::for_multibuffer(
16847                    excerpt_buffer,
16848                    Some(workspace.project().clone()),
16849                    window,
16850                    cx,
16851                );
16852                editor.lookup_key = Some(Box::new(key));
16853                editor
16854            })
16855        });
16856        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
16857            MultibufferSelectionMode::First => {
16858                if let Some(first_range) = ranges.first() {
16859                    editor.change_selections(
16860                        SelectionEffects::no_scroll(),
16861                        window,
16862                        cx,
16863                        |selections| {
16864                            selections.clear_disjoint();
16865                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
16866                        },
16867                    );
16868                }
16869                editor.highlight_background::<Self>(
16870                    &ranges,
16871                    |theme| theme.colors().editor_highlighted_line_background,
16872                    cx,
16873                );
16874            }
16875            MultibufferSelectionMode::All => {
16876                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
16877                    selections.clear_disjoint();
16878                    selections.select_anchor_ranges(ranges);
16879                });
16880            }
16881        });
16882
16883        let item = Box::new(editor);
16884        let item_id = item.item_id();
16885
16886        if split {
16887            let pane = workspace.adjacent_pane(window, cx);
16888            workspace.add_item(pane, item, None, true, true, window, cx);
16889        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16890            let (preview_item_id, preview_item_idx) =
16891                workspace.active_pane().read_with(cx, |pane, _| {
16892                    (pane.preview_item_id(), pane.preview_item_idx())
16893                });
16894
16895            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16896
16897            if let Some(preview_item_id) = preview_item_id {
16898                workspace.active_pane().update(cx, |pane, cx| {
16899                    pane.remove_item(preview_item_id, false, false, window, cx);
16900                });
16901            }
16902        } else {
16903            workspace.add_item_to_active_pane(item, None, true, window, cx);
16904        }
16905        workspace.active_pane().update(cx, |pane, cx| {
16906            pane.set_preview_item_id(Some(item_id), cx);
16907        });
16908    }
16909
16910    pub fn rename(
16911        &mut self,
16912        _: &Rename,
16913        window: &mut Window,
16914        cx: &mut Context<Self>,
16915    ) -> Option<Task<Result<()>>> {
16916        use language::ToOffset as _;
16917
16918        let provider = self.semantics_provider.clone()?;
16919        let selection = self.selections.newest_anchor().clone();
16920        let (cursor_buffer, cursor_buffer_position) = self
16921            .buffer
16922            .read(cx)
16923            .text_anchor_for_position(selection.head(), cx)?;
16924        let (tail_buffer, cursor_buffer_position_end) = self
16925            .buffer
16926            .read(cx)
16927            .text_anchor_for_position(selection.tail(), cx)?;
16928        if tail_buffer != cursor_buffer {
16929            return None;
16930        }
16931
16932        let snapshot = cursor_buffer.read(cx).snapshot();
16933        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16934        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16935        let prepare_rename = provider
16936            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16937            .unwrap_or_else(|| Task::ready(Ok(None)));
16938        drop(snapshot);
16939
16940        Some(cx.spawn_in(window, async move |this, cx| {
16941            let rename_range = if let Some(range) = prepare_rename.await? {
16942                Some(range)
16943            } else {
16944                this.update(cx, |this, cx| {
16945                    let buffer = this.buffer.read(cx).snapshot(cx);
16946                    let mut buffer_highlights = this
16947                        .document_highlights_for_position(selection.head(), &buffer)
16948                        .filter(|highlight| {
16949                            highlight.start.excerpt_id == selection.head().excerpt_id
16950                                && highlight.end.excerpt_id == selection.head().excerpt_id
16951                        });
16952                    buffer_highlights
16953                        .next()
16954                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16955                })?
16956            };
16957            if let Some(rename_range) = rename_range {
16958                this.update_in(cx, |this, window, cx| {
16959                    let snapshot = cursor_buffer.read(cx).snapshot();
16960                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16961                    let cursor_offset_in_rename_range =
16962                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16963                    let cursor_offset_in_rename_range_end =
16964                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16965
16966                    this.take_rename(false, window, cx);
16967                    let buffer = this.buffer.read(cx).read(cx);
16968                    let cursor_offset = selection.head().to_offset(&buffer);
16969                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16970                    let rename_end = rename_start + rename_buffer_range.len();
16971                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16972                    let mut old_highlight_id = None;
16973                    let old_name: Arc<str> = buffer
16974                        .chunks(rename_start..rename_end, true)
16975                        .map(|chunk| {
16976                            if old_highlight_id.is_none() {
16977                                old_highlight_id = chunk.syntax_highlight_id;
16978                            }
16979                            chunk.text
16980                        })
16981                        .collect::<String>()
16982                        .into();
16983
16984                    drop(buffer);
16985
16986                    // Position the selection in the rename editor so that it matches the current selection.
16987                    this.show_local_selections = false;
16988                    let rename_editor = cx.new(|cx| {
16989                        let mut editor = Editor::single_line(window, cx);
16990                        editor.buffer.update(cx, |buffer, cx| {
16991                            buffer.edit([(0..0, old_name.clone())], None, cx)
16992                        });
16993                        let rename_selection_range = match cursor_offset_in_rename_range
16994                            .cmp(&cursor_offset_in_rename_range_end)
16995                        {
16996                            Ordering::Equal => {
16997                                editor.select_all(&SelectAll, window, cx);
16998                                return editor;
16999                            }
17000                            Ordering::Less => {
17001                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17002                            }
17003                            Ordering::Greater => {
17004                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17005                            }
17006                        };
17007                        if rename_selection_range.end > old_name.len() {
17008                            editor.select_all(&SelectAll, window, cx);
17009                        } else {
17010                            editor.change_selections(Default::default(), window, cx, |s| {
17011                                s.select_ranges([rename_selection_range]);
17012                            });
17013                        }
17014                        editor
17015                    });
17016                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17017                        if e == &EditorEvent::Focused {
17018                            cx.emit(EditorEvent::FocusedIn)
17019                        }
17020                    })
17021                    .detach();
17022
17023                    let write_highlights =
17024                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17025                    let read_highlights =
17026                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17027                    let ranges = write_highlights
17028                        .iter()
17029                        .flat_map(|(_, ranges)| ranges.iter())
17030                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17031                        .cloned()
17032                        .collect();
17033
17034                    this.highlight_text::<Rename>(
17035                        ranges,
17036                        HighlightStyle {
17037                            fade_out: Some(0.6),
17038                            ..Default::default()
17039                        },
17040                        cx,
17041                    );
17042                    let rename_focus_handle = rename_editor.focus_handle(cx);
17043                    window.focus(&rename_focus_handle);
17044                    let block_id = this.insert_blocks(
17045                        [BlockProperties {
17046                            style: BlockStyle::Flex,
17047                            placement: BlockPlacement::Below(range.start),
17048                            height: Some(1),
17049                            render: Arc::new({
17050                                let rename_editor = rename_editor.clone();
17051                                move |cx: &mut BlockContext| {
17052                                    let mut text_style = cx.editor_style.text.clone();
17053                                    if let Some(highlight_style) = old_highlight_id
17054                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17055                                    {
17056                                        text_style = text_style.highlight(highlight_style);
17057                                    }
17058                                    div()
17059                                        .block_mouse_except_scroll()
17060                                        .pl(cx.anchor_x)
17061                                        .child(EditorElement::new(
17062                                            &rename_editor,
17063                                            EditorStyle {
17064                                                background: cx.theme().system().transparent,
17065                                                local_player: cx.editor_style.local_player,
17066                                                text: text_style,
17067                                                scrollbar_width: cx.editor_style.scrollbar_width,
17068                                                syntax: cx.editor_style.syntax.clone(),
17069                                                status: cx.editor_style.status.clone(),
17070                                                inlay_hints_style: HighlightStyle {
17071                                                    font_weight: Some(FontWeight::BOLD),
17072                                                    ..make_inlay_hints_style(cx.app)
17073                                                },
17074                                                edit_prediction_styles: make_suggestion_styles(
17075                                                    cx.app,
17076                                                ),
17077                                                ..EditorStyle::default()
17078                                            },
17079                                        ))
17080                                        .into_any_element()
17081                                }
17082                            }),
17083                            priority: 0,
17084                        }],
17085                        Some(Autoscroll::fit()),
17086                        cx,
17087                    )[0];
17088                    this.pending_rename = Some(RenameState {
17089                        range,
17090                        old_name,
17091                        editor: rename_editor,
17092                        block_id,
17093                    });
17094                })?;
17095            }
17096
17097            Ok(())
17098        }))
17099    }
17100
17101    pub fn confirm_rename(
17102        &mut self,
17103        _: &ConfirmRename,
17104        window: &mut Window,
17105        cx: &mut Context<Self>,
17106    ) -> Option<Task<Result<()>>> {
17107        let rename = self.take_rename(false, window, cx)?;
17108        let workspace = self.workspace()?.downgrade();
17109        let (buffer, start) = self
17110            .buffer
17111            .read(cx)
17112            .text_anchor_for_position(rename.range.start, cx)?;
17113        let (end_buffer, _) = self
17114            .buffer
17115            .read(cx)
17116            .text_anchor_for_position(rename.range.end, cx)?;
17117        if buffer != end_buffer {
17118            return None;
17119        }
17120
17121        let old_name = rename.old_name;
17122        let new_name = rename.editor.read(cx).text(cx);
17123
17124        let rename = self.semantics_provider.as_ref()?.perform_rename(
17125            &buffer,
17126            start,
17127            new_name.clone(),
17128            cx,
17129        )?;
17130
17131        Some(cx.spawn_in(window, async move |editor, cx| {
17132            let project_transaction = rename.await?;
17133            Self::open_project_transaction(
17134                &editor,
17135                workspace,
17136                project_transaction,
17137                format!("Rename: {}{}", old_name, new_name),
17138                cx,
17139            )
17140            .await?;
17141
17142            editor.update(cx, |editor, cx| {
17143                editor.refresh_document_highlights(cx);
17144            })?;
17145            Ok(())
17146        }))
17147    }
17148
17149    fn take_rename(
17150        &mut self,
17151        moving_cursor: bool,
17152        window: &mut Window,
17153        cx: &mut Context<Self>,
17154    ) -> Option<RenameState> {
17155        let rename = self.pending_rename.take()?;
17156        if rename.editor.focus_handle(cx).is_focused(window) {
17157            window.focus(&self.focus_handle);
17158        }
17159
17160        self.remove_blocks(
17161            [rename.block_id].into_iter().collect(),
17162            Some(Autoscroll::fit()),
17163            cx,
17164        );
17165        self.clear_highlights::<Rename>(cx);
17166        self.show_local_selections = true;
17167
17168        if moving_cursor {
17169            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17170                editor
17171                    .selections
17172                    .newest::<usize>(&editor.display_snapshot(cx))
17173                    .head()
17174            });
17175
17176            // Update the selection to match the position of the selection inside
17177            // the rename editor.
17178            let snapshot = self.buffer.read(cx).read(cx);
17179            let rename_range = rename.range.to_offset(&snapshot);
17180            let cursor_in_editor = snapshot
17181                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17182                .min(rename_range.end);
17183            drop(snapshot);
17184
17185            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17186                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17187            });
17188        } else {
17189            self.refresh_document_highlights(cx);
17190        }
17191
17192        Some(rename)
17193    }
17194
17195    pub fn pending_rename(&self) -> Option<&RenameState> {
17196        self.pending_rename.as_ref()
17197    }
17198
17199    fn format(
17200        &mut self,
17201        _: &Format,
17202        window: &mut Window,
17203        cx: &mut Context<Self>,
17204    ) -> Option<Task<Result<()>>> {
17205        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17206
17207        let project = match &self.project {
17208            Some(project) => project.clone(),
17209            None => return None,
17210        };
17211
17212        Some(self.perform_format(
17213            project,
17214            FormatTrigger::Manual,
17215            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17216            window,
17217            cx,
17218        ))
17219    }
17220
17221    fn format_selections(
17222        &mut self,
17223        _: &FormatSelections,
17224        window: &mut Window,
17225        cx: &mut Context<Self>,
17226    ) -> Option<Task<Result<()>>> {
17227        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17228
17229        let project = match &self.project {
17230            Some(project) => project.clone(),
17231            None => return None,
17232        };
17233
17234        let ranges = self
17235            .selections
17236            .all_adjusted(&self.display_snapshot(cx))
17237            .into_iter()
17238            .map(|selection| selection.range())
17239            .collect_vec();
17240
17241        Some(self.perform_format(
17242            project,
17243            FormatTrigger::Manual,
17244            FormatTarget::Ranges(ranges),
17245            window,
17246            cx,
17247        ))
17248    }
17249
17250    fn perform_format(
17251        &mut self,
17252        project: Entity<Project>,
17253        trigger: FormatTrigger,
17254        target: FormatTarget,
17255        window: &mut Window,
17256        cx: &mut Context<Self>,
17257    ) -> Task<Result<()>> {
17258        let buffer = self.buffer.clone();
17259        let (buffers, target) = match target {
17260            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17261            FormatTarget::Ranges(selection_ranges) => {
17262                let multi_buffer = buffer.read(cx);
17263                let snapshot = multi_buffer.read(cx);
17264                let mut buffers = HashSet::default();
17265                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17266                    BTreeMap::new();
17267                for selection_range in selection_ranges {
17268                    for (buffer, buffer_range, _) in
17269                        snapshot.range_to_buffer_ranges(selection_range)
17270                    {
17271                        let buffer_id = buffer.remote_id();
17272                        let start = buffer.anchor_before(buffer_range.start);
17273                        let end = buffer.anchor_after(buffer_range.end);
17274                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17275                        buffer_id_to_ranges
17276                            .entry(buffer_id)
17277                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17278                            .or_insert_with(|| vec![start..end]);
17279                    }
17280                }
17281                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17282            }
17283        };
17284
17285        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17286        let selections_prev = transaction_id_prev
17287            .and_then(|transaction_id_prev| {
17288                // default to selections as they were after the last edit, if we have them,
17289                // instead of how they are now.
17290                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17291                // will take you back to where you made the last edit, instead of staying where you scrolled
17292                self.selection_history
17293                    .transaction(transaction_id_prev)
17294                    .map(|t| t.0.clone())
17295            })
17296            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17297
17298        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17299        let format = project.update(cx, |project, cx| {
17300            project.format(buffers, target, true, trigger, cx)
17301        });
17302
17303        cx.spawn_in(window, async move |editor, cx| {
17304            let transaction = futures::select_biased! {
17305                transaction = format.log_err().fuse() => transaction,
17306                () = timeout => {
17307                    log::warn!("timed out waiting for formatting");
17308                    None
17309                }
17310            };
17311
17312            buffer
17313                .update(cx, |buffer, cx| {
17314                    if let Some(transaction) = transaction
17315                        && !buffer.is_singleton()
17316                    {
17317                        buffer.push_transaction(&transaction.0, cx);
17318                    }
17319                    cx.notify();
17320                })
17321                .ok();
17322
17323            if let Some(transaction_id_now) =
17324                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17325            {
17326                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17327                if has_new_transaction {
17328                    _ = editor.update(cx, |editor, _| {
17329                        editor
17330                            .selection_history
17331                            .insert_transaction(transaction_id_now, selections_prev);
17332                    });
17333                }
17334            }
17335
17336            Ok(())
17337        })
17338    }
17339
17340    fn organize_imports(
17341        &mut self,
17342        _: &OrganizeImports,
17343        window: &mut Window,
17344        cx: &mut Context<Self>,
17345    ) -> Option<Task<Result<()>>> {
17346        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17347        let project = match &self.project {
17348            Some(project) => project.clone(),
17349            None => return None,
17350        };
17351        Some(self.perform_code_action_kind(
17352            project,
17353            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17354            window,
17355            cx,
17356        ))
17357    }
17358
17359    fn perform_code_action_kind(
17360        &mut self,
17361        project: Entity<Project>,
17362        kind: CodeActionKind,
17363        window: &mut Window,
17364        cx: &mut Context<Self>,
17365    ) -> Task<Result<()>> {
17366        let buffer = self.buffer.clone();
17367        let buffers = buffer.read(cx).all_buffers();
17368        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17369        let apply_action = project.update(cx, |project, cx| {
17370            project.apply_code_action_kind(buffers, kind, true, cx)
17371        });
17372        cx.spawn_in(window, async move |_, cx| {
17373            let transaction = futures::select_biased! {
17374                () = timeout => {
17375                    log::warn!("timed out waiting for executing code action");
17376                    None
17377                }
17378                transaction = apply_action.log_err().fuse() => transaction,
17379            };
17380            buffer
17381                .update(cx, |buffer, cx| {
17382                    // check if we need this
17383                    if let Some(transaction) = transaction
17384                        && !buffer.is_singleton()
17385                    {
17386                        buffer.push_transaction(&transaction.0, cx);
17387                    }
17388                    cx.notify();
17389                })
17390                .ok();
17391            Ok(())
17392        })
17393    }
17394
17395    pub fn restart_language_server(
17396        &mut self,
17397        _: &RestartLanguageServer,
17398        _: &mut Window,
17399        cx: &mut Context<Self>,
17400    ) {
17401        if let Some(project) = self.project.clone() {
17402            self.buffer.update(cx, |multi_buffer, cx| {
17403                project.update(cx, |project, cx| {
17404                    project.restart_language_servers_for_buffers(
17405                        multi_buffer.all_buffers().into_iter().collect(),
17406                        HashSet::default(),
17407                        cx,
17408                    );
17409                });
17410            })
17411        }
17412    }
17413
17414    pub fn stop_language_server(
17415        &mut self,
17416        _: &StopLanguageServer,
17417        _: &mut Window,
17418        cx: &mut Context<Self>,
17419    ) {
17420        if let Some(project) = self.project.clone() {
17421            self.buffer.update(cx, |multi_buffer, cx| {
17422                project.update(cx, |project, cx| {
17423                    project.stop_language_servers_for_buffers(
17424                        multi_buffer.all_buffers().into_iter().collect(),
17425                        HashSet::default(),
17426                        cx,
17427                    );
17428                });
17429            });
17430            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17431        }
17432    }
17433
17434    fn cancel_language_server_work(
17435        workspace: &mut Workspace,
17436        _: &actions::CancelLanguageServerWork,
17437        _: &mut Window,
17438        cx: &mut Context<Workspace>,
17439    ) {
17440        let project = workspace.project();
17441        let buffers = workspace
17442            .active_item(cx)
17443            .and_then(|item| item.act_as::<Editor>(cx))
17444            .map_or(HashSet::default(), |editor| {
17445                editor.read(cx).buffer.read(cx).all_buffers()
17446            });
17447        project.update(cx, |project, cx| {
17448            project.cancel_language_server_work_for_buffers(buffers, cx);
17449        });
17450    }
17451
17452    fn show_character_palette(
17453        &mut self,
17454        _: &ShowCharacterPalette,
17455        window: &mut Window,
17456        _: &mut Context<Self>,
17457    ) {
17458        window.show_character_palette();
17459    }
17460
17461    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17462        if !self.diagnostics_enabled() {
17463            return;
17464        }
17465
17466        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17467            let buffer = self.buffer.read(cx).snapshot(cx);
17468            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17469            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17470            let is_valid = buffer
17471                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17472                .any(|entry| {
17473                    entry.diagnostic.is_primary
17474                        && !entry.range.is_empty()
17475                        && entry.range.start == primary_range_start
17476                        && entry.diagnostic.message == active_diagnostics.active_message
17477                });
17478
17479            if !is_valid {
17480                self.dismiss_diagnostics(cx);
17481            }
17482        }
17483    }
17484
17485    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17486        match &self.active_diagnostics {
17487            ActiveDiagnostic::Group(group) => Some(group),
17488            _ => None,
17489        }
17490    }
17491
17492    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17493        if !self.diagnostics_enabled() {
17494            return;
17495        }
17496        self.dismiss_diagnostics(cx);
17497        self.active_diagnostics = ActiveDiagnostic::All;
17498    }
17499
17500    fn activate_diagnostics(
17501        &mut self,
17502        buffer_id: BufferId,
17503        diagnostic: DiagnosticEntryRef<'_, usize>,
17504        window: &mut Window,
17505        cx: &mut Context<Self>,
17506    ) {
17507        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17508            return;
17509        }
17510        self.dismiss_diagnostics(cx);
17511        let snapshot = self.snapshot(window, cx);
17512        let buffer = self.buffer.read(cx).snapshot(cx);
17513        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17514            return;
17515        };
17516
17517        let diagnostic_group = buffer
17518            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17519            .collect::<Vec<_>>();
17520
17521        let blocks =
17522            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17523
17524        let blocks = self.display_map.update(cx, |display_map, cx| {
17525            display_map.insert_blocks(blocks, cx).into_iter().collect()
17526        });
17527        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17528            active_range: buffer.anchor_before(diagnostic.range.start)
17529                ..buffer.anchor_after(diagnostic.range.end),
17530            active_message: diagnostic.diagnostic.message.clone(),
17531            group_id: diagnostic.diagnostic.group_id,
17532            blocks,
17533        });
17534        cx.notify();
17535    }
17536
17537    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17538        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17539            return;
17540        };
17541
17542        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17543        if let ActiveDiagnostic::Group(group) = prev {
17544            self.display_map.update(cx, |display_map, cx| {
17545                display_map.remove_blocks(group.blocks, cx);
17546            });
17547            cx.notify();
17548        }
17549    }
17550
17551    /// Disable inline diagnostics rendering for this editor.
17552    pub fn disable_inline_diagnostics(&mut self) {
17553        self.inline_diagnostics_enabled = false;
17554        self.inline_diagnostics_update = Task::ready(());
17555        self.inline_diagnostics.clear();
17556    }
17557
17558    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17559        self.diagnostics_enabled = false;
17560        self.dismiss_diagnostics(cx);
17561        self.inline_diagnostics_update = Task::ready(());
17562        self.inline_diagnostics.clear();
17563    }
17564
17565    pub fn disable_word_completions(&mut self) {
17566        self.word_completions_enabled = false;
17567    }
17568
17569    pub fn diagnostics_enabled(&self) -> bool {
17570        self.diagnostics_enabled && self.mode.is_full()
17571    }
17572
17573    pub fn inline_diagnostics_enabled(&self) -> bool {
17574        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17575    }
17576
17577    pub fn show_inline_diagnostics(&self) -> bool {
17578        self.show_inline_diagnostics
17579    }
17580
17581    pub fn toggle_inline_diagnostics(
17582        &mut self,
17583        _: &ToggleInlineDiagnostics,
17584        window: &mut Window,
17585        cx: &mut Context<Editor>,
17586    ) {
17587        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17588        self.refresh_inline_diagnostics(false, window, cx);
17589    }
17590
17591    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17592        self.diagnostics_max_severity = severity;
17593        self.display_map.update(cx, |display_map, _| {
17594            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17595        });
17596    }
17597
17598    pub fn toggle_diagnostics(
17599        &mut self,
17600        _: &ToggleDiagnostics,
17601        window: &mut Window,
17602        cx: &mut Context<Editor>,
17603    ) {
17604        if !self.diagnostics_enabled() {
17605            return;
17606        }
17607
17608        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17609            EditorSettings::get_global(cx)
17610                .diagnostics_max_severity
17611                .filter(|severity| severity != &DiagnosticSeverity::Off)
17612                .unwrap_or(DiagnosticSeverity::Hint)
17613        } else {
17614            DiagnosticSeverity::Off
17615        };
17616        self.set_max_diagnostics_severity(new_severity, cx);
17617        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17618            self.active_diagnostics = ActiveDiagnostic::None;
17619            self.inline_diagnostics_update = Task::ready(());
17620            self.inline_diagnostics.clear();
17621        } else {
17622            self.refresh_inline_diagnostics(false, window, cx);
17623        }
17624
17625        cx.notify();
17626    }
17627
17628    pub fn toggle_minimap(
17629        &mut self,
17630        _: &ToggleMinimap,
17631        window: &mut Window,
17632        cx: &mut Context<Editor>,
17633    ) {
17634        if self.supports_minimap(cx) {
17635            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17636        }
17637    }
17638
17639    fn refresh_inline_diagnostics(
17640        &mut self,
17641        debounce: bool,
17642        window: &mut Window,
17643        cx: &mut Context<Self>,
17644    ) {
17645        let max_severity = ProjectSettings::get_global(cx)
17646            .diagnostics
17647            .inline
17648            .max_severity
17649            .unwrap_or(self.diagnostics_max_severity);
17650
17651        if !self.inline_diagnostics_enabled()
17652            || !self.show_inline_diagnostics
17653            || max_severity == DiagnosticSeverity::Off
17654        {
17655            self.inline_diagnostics_update = Task::ready(());
17656            self.inline_diagnostics.clear();
17657            return;
17658        }
17659
17660        let debounce_ms = ProjectSettings::get_global(cx)
17661            .diagnostics
17662            .inline
17663            .update_debounce_ms;
17664        let debounce = if debounce && debounce_ms > 0 {
17665            Some(Duration::from_millis(debounce_ms))
17666        } else {
17667            None
17668        };
17669        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17670            if let Some(debounce) = debounce {
17671                cx.background_executor().timer(debounce).await;
17672            }
17673            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17674                editor
17675                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17676                    .ok()
17677            }) else {
17678                return;
17679            };
17680
17681            let new_inline_diagnostics = cx
17682                .background_spawn(async move {
17683                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17684                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17685                        let message = diagnostic_entry
17686                            .diagnostic
17687                            .message
17688                            .split_once('\n')
17689                            .map(|(line, _)| line)
17690                            .map(SharedString::new)
17691                            .unwrap_or_else(|| {
17692                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17693                            });
17694                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17695                        let (Ok(i) | Err(i)) = inline_diagnostics
17696                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17697                        inline_diagnostics.insert(
17698                            i,
17699                            (
17700                                start_anchor,
17701                                InlineDiagnostic {
17702                                    message,
17703                                    group_id: diagnostic_entry.diagnostic.group_id,
17704                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17705                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17706                                    severity: diagnostic_entry.diagnostic.severity,
17707                                },
17708                            ),
17709                        );
17710                    }
17711                    inline_diagnostics
17712                })
17713                .await;
17714
17715            editor
17716                .update(cx, |editor, cx| {
17717                    editor.inline_diagnostics = new_inline_diagnostics;
17718                    cx.notify();
17719                })
17720                .ok();
17721        });
17722    }
17723
17724    fn pull_diagnostics(
17725        &mut self,
17726        buffer_id: Option<BufferId>,
17727        window: &Window,
17728        cx: &mut Context<Self>,
17729    ) -> Option<()> {
17730        if self.ignore_lsp_data() {
17731            return None;
17732        }
17733        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17734            .diagnostics
17735            .lsp_pull_diagnostics;
17736        if !pull_diagnostics_settings.enabled {
17737            return None;
17738        }
17739        let project = self.project()?.downgrade();
17740        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17741        let mut buffers = self.buffer.read(cx).all_buffers();
17742        buffers.retain(|buffer| {
17743            let buffer_id_to_retain = buffer.read(cx).remote_id();
17744            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17745                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17746        });
17747        if buffers.is_empty() {
17748            self.pull_diagnostics_task = Task::ready(());
17749            return None;
17750        }
17751
17752        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17753            cx.background_executor().timer(debounce).await;
17754
17755            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17756                buffers
17757                    .into_iter()
17758                    .filter_map(|buffer| {
17759                        project
17760                            .update(cx, |project, cx| {
17761                                project.lsp_store().update(cx, |lsp_store, cx| {
17762                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17763                                })
17764                            })
17765                            .ok()
17766                    })
17767                    .collect::<FuturesUnordered<_>>()
17768            }) else {
17769                return;
17770            };
17771
17772            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17773                match pull_task {
17774                    Ok(()) => {
17775                        if editor
17776                            .update_in(cx, |editor, window, cx| {
17777                                editor.update_diagnostics_state(window, cx);
17778                            })
17779                            .is_err()
17780                        {
17781                            return;
17782                        }
17783                    }
17784                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17785                }
17786            }
17787        });
17788
17789        Some(())
17790    }
17791
17792    pub fn set_selections_from_remote(
17793        &mut self,
17794        selections: Vec<Selection<Anchor>>,
17795        pending_selection: Option<Selection<Anchor>>,
17796        window: &mut Window,
17797        cx: &mut Context<Self>,
17798    ) {
17799        let old_cursor_position = self.selections.newest_anchor().head();
17800        self.selections.change_with(cx, |s| {
17801            s.select_anchors(selections);
17802            if let Some(pending_selection) = pending_selection {
17803                s.set_pending(pending_selection, SelectMode::Character);
17804            } else {
17805                s.clear_pending();
17806            }
17807        });
17808        self.selections_did_change(
17809            false,
17810            &old_cursor_position,
17811            SelectionEffects::default(),
17812            window,
17813            cx,
17814        );
17815    }
17816
17817    pub fn transact(
17818        &mut self,
17819        window: &mut Window,
17820        cx: &mut Context<Self>,
17821        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17822    ) -> Option<TransactionId> {
17823        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17824            this.start_transaction_at(Instant::now(), window, cx);
17825            update(this, window, cx);
17826            this.end_transaction_at(Instant::now(), cx)
17827        })
17828    }
17829
17830    pub fn start_transaction_at(
17831        &mut self,
17832        now: Instant,
17833        window: &mut Window,
17834        cx: &mut Context<Self>,
17835    ) -> Option<TransactionId> {
17836        self.end_selection(window, cx);
17837        if let Some(tx_id) = self
17838            .buffer
17839            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17840        {
17841            self.selection_history
17842                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17843            cx.emit(EditorEvent::TransactionBegun {
17844                transaction_id: tx_id,
17845            });
17846            Some(tx_id)
17847        } else {
17848            None
17849        }
17850    }
17851
17852    pub fn end_transaction_at(
17853        &mut self,
17854        now: Instant,
17855        cx: &mut Context<Self>,
17856    ) -> Option<TransactionId> {
17857        if let Some(transaction_id) = self
17858            .buffer
17859            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17860        {
17861            if let Some((_, end_selections)) =
17862                self.selection_history.transaction_mut(transaction_id)
17863            {
17864                *end_selections = Some(self.selections.disjoint_anchors_arc());
17865            } else {
17866                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17867            }
17868
17869            cx.emit(EditorEvent::Edited { transaction_id });
17870            Some(transaction_id)
17871        } else {
17872            None
17873        }
17874    }
17875
17876    pub fn modify_transaction_selection_history(
17877        &mut self,
17878        transaction_id: TransactionId,
17879        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17880    ) -> bool {
17881        self.selection_history
17882            .transaction_mut(transaction_id)
17883            .map(modify)
17884            .is_some()
17885    }
17886
17887    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17888        if self.selection_mark_mode {
17889            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17890                s.move_with(|_, sel| {
17891                    sel.collapse_to(sel.head(), SelectionGoal::None);
17892                });
17893            })
17894        }
17895        self.selection_mark_mode = true;
17896        cx.notify();
17897    }
17898
17899    pub fn swap_selection_ends(
17900        &mut self,
17901        _: &actions::SwapSelectionEnds,
17902        window: &mut Window,
17903        cx: &mut Context<Self>,
17904    ) {
17905        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17906            s.move_with(|_, sel| {
17907                if sel.start != sel.end {
17908                    sel.reversed = !sel.reversed
17909                }
17910            });
17911        });
17912        self.request_autoscroll(Autoscroll::newest(), cx);
17913        cx.notify();
17914    }
17915
17916    pub fn toggle_focus(
17917        workspace: &mut Workspace,
17918        _: &actions::ToggleFocus,
17919        window: &mut Window,
17920        cx: &mut Context<Workspace>,
17921    ) {
17922        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17923            return;
17924        };
17925        workspace.activate_item(&item, true, true, window, cx);
17926    }
17927
17928    pub fn toggle_fold(
17929        &mut self,
17930        _: &actions::ToggleFold,
17931        window: &mut Window,
17932        cx: &mut Context<Self>,
17933    ) {
17934        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
17935            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17936            let selection = self.selections.newest::<Point>(&display_map);
17937
17938            let range = if selection.is_empty() {
17939                let point = selection.head().to_display_point(&display_map);
17940                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17941                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17942                    .to_point(&display_map);
17943                start..end
17944            } else {
17945                selection.range()
17946            };
17947            if display_map.folds_in_range(range).next().is_some() {
17948                self.unfold_lines(&Default::default(), window, cx)
17949            } else {
17950                self.fold(&Default::default(), window, cx)
17951            }
17952        } else {
17953            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17954            let buffer_ids: HashSet<_> = self
17955                .selections
17956                .disjoint_anchor_ranges()
17957                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17958                .collect();
17959
17960            let should_unfold = buffer_ids
17961                .iter()
17962                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17963
17964            for buffer_id in buffer_ids {
17965                if should_unfold {
17966                    self.unfold_buffer(buffer_id, cx);
17967                } else {
17968                    self.fold_buffer(buffer_id, cx);
17969                }
17970            }
17971        }
17972    }
17973
17974    pub fn toggle_fold_recursive(
17975        &mut self,
17976        _: &actions::ToggleFoldRecursive,
17977        window: &mut Window,
17978        cx: &mut Context<Self>,
17979    ) {
17980        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
17981
17982        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17983        let range = if selection.is_empty() {
17984            let point = selection.head().to_display_point(&display_map);
17985            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17986            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17987                .to_point(&display_map);
17988            start..end
17989        } else {
17990            selection.range()
17991        };
17992        if display_map.folds_in_range(range).next().is_some() {
17993            self.unfold_recursive(&Default::default(), window, cx)
17994        } else {
17995            self.fold_recursive(&Default::default(), window, cx)
17996        }
17997    }
17998
17999    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18000        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18001            let mut to_fold = Vec::new();
18002            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18003            let selections = self.selections.all_adjusted(&display_map);
18004
18005            for selection in selections {
18006                let range = selection.range().sorted();
18007                let buffer_start_row = range.start.row;
18008
18009                if range.start.row != range.end.row {
18010                    let mut found = false;
18011                    let mut row = range.start.row;
18012                    while row <= range.end.row {
18013                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18014                        {
18015                            found = true;
18016                            row = crease.range().end.row + 1;
18017                            to_fold.push(crease);
18018                        } else {
18019                            row += 1
18020                        }
18021                    }
18022                    if found {
18023                        continue;
18024                    }
18025                }
18026
18027                for row in (0..=range.start.row).rev() {
18028                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18029                        && crease.range().end.row >= buffer_start_row
18030                    {
18031                        to_fold.push(crease);
18032                        if row <= range.start.row {
18033                            break;
18034                        }
18035                    }
18036                }
18037            }
18038
18039            self.fold_creases(to_fold, true, window, cx);
18040        } else {
18041            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18042            let buffer_ids = self
18043                .selections
18044                .disjoint_anchor_ranges()
18045                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18046                .collect::<HashSet<_>>();
18047            for buffer_id in buffer_ids {
18048                self.fold_buffer(buffer_id, cx);
18049            }
18050        }
18051    }
18052
18053    pub fn toggle_fold_all(
18054        &mut self,
18055        _: &actions::ToggleFoldAll,
18056        window: &mut Window,
18057        cx: &mut Context<Self>,
18058    ) {
18059        if self.buffer.read(cx).is_singleton() {
18060            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18061            let has_folds = display_map
18062                .folds_in_range(0..display_map.buffer_snapshot().len())
18063                .next()
18064                .is_some();
18065
18066            if has_folds {
18067                self.unfold_all(&actions::UnfoldAll, window, cx);
18068            } else {
18069                self.fold_all(&actions::FoldAll, window, cx);
18070            }
18071        } else {
18072            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18073            let should_unfold = buffer_ids
18074                .iter()
18075                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18076
18077            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18078                editor
18079                    .update_in(cx, |editor, _, cx| {
18080                        for buffer_id in buffer_ids {
18081                            if should_unfold {
18082                                editor.unfold_buffer(buffer_id, cx);
18083                            } else {
18084                                editor.fold_buffer(buffer_id, cx);
18085                            }
18086                        }
18087                    })
18088                    .ok();
18089            });
18090        }
18091    }
18092
18093    fn fold_at_level(
18094        &mut self,
18095        fold_at: &FoldAtLevel,
18096        window: &mut Window,
18097        cx: &mut Context<Self>,
18098    ) {
18099        if !self.buffer.read(cx).is_singleton() {
18100            return;
18101        }
18102
18103        let fold_at_level = fold_at.0;
18104        let snapshot = self.buffer.read(cx).snapshot(cx);
18105        let mut to_fold = Vec::new();
18106        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18107
18108        let row_ranges_to_keep: Vec<Range<u32>> = self
18109            .selections
18110            .all::<Point>(&self.display_snapshot(cx))
18111            .into_iter()
18112            .map(|sel| sel.start.row..sel.end.row)
18113            .collect();
18114
18115        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18116            while start_row < end_row {
18117                match self
18118                    .snapshot(window, cx)
18119                    .crease_for_buffer_row(MultiBufferRow(start_row))
18120                {
18121                    Some(crease) => {
18122                        let nested_start_row = crease.range().start.row + 1;
18123                        let nested_end_row = crease.range().end.row;
18124
18125                        if current_level < fold_at_level {
18126                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18127                        } else if current_level == fold_at_level {
18128                            // Fold iff there is no selection completely contained within the fold region
18129                            if !row_ranges_to_keep.iter().any(|selection| {
18130                                selection.end >= nested_start_row
18131                                    && selection.start <= nested_end_row
18132                            }) {
18133                                to_fold.push(crease);
18134                            }
18135                        }
18136
18137                        start_row = nested_end_row + 1;
18138                    }
18139                    None => start_row += 1,
18140                }
18141            }
18142        }
18143
18144        self.fold_creases(to_fold, true, window, cx);
18145    }
18146
18147    pub fn fold_at_level_1(
18148        &mut self,
18149        _: &actions::FoldAtLevel1,
18150        window: &mut Window,
18151        cx: &mut Context<Self>,
18152    ) {
18153        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18154    }
18155
18156    pub fn fold_at_level_2(
18157        &mut self,
18158        _: &actions::FoldAtLevel2,
18159        window: &mut Window,
18160        cx: &mut Context<Self>,
18161    ) {
18162        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18163    }
18164
18165    pub fn fold_at_level_3(
18166        &mut self,
18167        _: &actions::FoldAtLevel3,
18168        window: &mut Window,
18169        cx: &mut Context<Self>,
18170    ) {
18171        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18172    }
18173
18174    pub fn fold_at_level_4(
18175        &mut self,
18176        _: &actions::FoldAtLevel4,
18177        window: &mut Window,
18178        cx: &mut Context<Self>,
18179    ) {
18180        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18181    }
18182
18183    pub fn fold_at_level_5(
18184        &mut self,
18185        _: &actions::FoldAtLevel5,
18186        window: &mut Window,
18187        cx: &mut Context<Self>,
18188    ) {
18189        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18190    }
18191
18192    pub fn fold_at_level_6(
18193        &mut self,
18194        _: &actions::FoldAtLevel6,
18195        window: &mut Window,
18196        cx: &mut Context<Self>,
18197    ) {
18198        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18199    }
18200
18201    pub fn fold_at_level_7(
18202        &mut self,
18203        _: &actions::FoldAtLevel7,
18204        window: &mut Window,
18205        cx: &mut Context<Self>,
18206    ) {
18207        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18208    }
18209
18210    pub fn fold_at_level_8(
18211        &mut self,
18212        _: &actions::FoldAtLevel8,
18213        window: &mut Window,
18214        cx: &mut Context<Self>,
18215    ) {
18216        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18217    }
18218
18219    pub fn fold_at_level_9(
18220        &mut self,
18221        _: &actions::FoldAtLevel9,
18222        window: &mut Window,
18223        cx: &mut Context<Self>,
18224    ) {
18225        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18226    }
18227
18228    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18229        if self.buffer.read(cx).is_singleton() {
18230            let mut fold_ranges = Vec::new();
18231            let snapshot = self.buffer.read(cx).snapshot(cx);
18232
18233            for row in 0..snapshot.max_row().0 {
18234                if let Some(foldable_range) = self
18235                    .snapshot(window, cx)
18236                    .crease_for_buffer_row(MultiBufferRow(row))
18237                {
18238                    fold_ranges.push(foldable_range);
18239                }
18240            }
18241
18242            self.fold_creases(fold_ranges, true, window, cx);
18243        } else {
18244            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18245                editor
18246                    .update_in(cx, |editor, _, cx| {
18247                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18248                            editor.fold_buffer(buffer_id, cx);
18249                        }
18250                    })
18251                    .ok();
18252            });
18253        }
18254    }
18255
18256    pub fn fold_function_bodies(
18257        &mut self,
18258        _: &actions::FoldFunctionBodies,
18259        window: &mut Window,
18260        cx: &mut Context<Self>,
18261    ) {
18262        let snapshot = self.buffer.read(cx).snapshot(cx);
18263
18264        let ranges = snapshot
18265            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18266            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18267            .collect::<Vec<_>>();
18268
18269        let creases = ranges
18270            .into_iter()
18271            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18272            .collect();
18273
18274        self.fold_creases(creases, true, window, cx);
18275    }
18276
18277    pub fn fold_recursive(
18278        &mut self,
18279        _: &actions::FoldRecursive,
18280        window: &mut Window,
18281        cx: &mut Context<Self>,
18282    ) {
18283        let mut to_fold = Vec::new();
18284        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18285        let selections = self.selections.all_adjusted(&display_map);
18286
18287        for selection in selections {
18288            let range = selection.range().sorted();
18289            let buffer_start_row = range.start.row;
18290
18291            if range.start.row != range.end.row {
18292                let mut found = false;
18293                for row in range.start.row..=range.end.row {
18294                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18295                        found = true;
18296                        to_fold.push(crease);
18297                    }
18298                }
18299                if found {
18300                    continue;
18301                }
18302            }
18303
18304            for row in (0..=range.start.row).rev() {
18305                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18306                    if crease.range().end.row >= buffer_start_row {
18307                        to_fold.push(crease);
18308                    } else {
18309                        break;
18310                    }
18311                }
18312            }
18313        }
18314
18315        self.fold_creases(to_fold, true, window, cx);
18316    }
18317
18318    pub fn fold_at(
18319        &mut self,
18320        buffer_row: MultiBufferRow,
18321        window: &mut Window,
18322        cx: &mut Context<Self>,
18323    ) {
18324        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18325
18326        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18327            let autoscroll = self
18328                .selections
18329                .all::<Point>(&display_map)
18330                .iter()
18331                .any(|selection| crease.range().overlaps(&selection.range()));
18332
18333            self.fold_creases(vec![crease], autoscroll, window, cx);
18334        }
18335    }
18336
18337    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18338        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18339            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18340            let buffer = display_map.buffer_snapshot();
18341            let selections = self.selections.all::<Point>(&display_map);
18342            let ranges = selections
18343                .iter()
18344                .map(|s| {
18345                    let range = s.display_range(&display_map).sorted();
18346                    let mut start = range.start.to_point(&display_map);
18347                    let mut end = range.end.to_point(&display_map);
18348                    start.column = 0;
18349                    end.column = buffer.line_len(MultiBufferRow(end.row));
18350                    start..end
18351                })
18352                .collect::<Vec<_>>();
18353
18354            self.unfold_ranges(&ranges, true, true, cx);
18355        } else {
18356            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18357            let buffer_ids = self
18358                .selections
18359                .disjoint_anchor_ranges()
18360                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18361                .collect::<HashSet<_>>();
18362            for buffer_id in buffer_ids {
18363                self.unfold_buffer(buffer_id, cx);
18364            }
18365        }
18366    }
18367
18368    pub fn unfold_recursive(
18369        &mut self,
18370        _: &UnfoldRecursive,
18371        _window: &mut Window,
18372        cx: &mut Context<Self>,
18373    ) {
18374        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18375        let selections = self.selections.all::<Point>(&display_map);
18376        let ranges = selections
18377            .iter()
18378            .map(|s| {
18379                let mut range = s.display_range(&display_map).sorted();
18380                *range.start.column_mut() = 0;
18381                *range.end.column_mut() = display_map.line_len(range.end.row());
18382                let start = range.start.to_point(&display_map);
18383                let end = range.end.to_point(&display_map);
18384                start..end
18385            })
18386            .collect::<Vec<_>>();
18387
18388        self.unfold_ranges(&ranges, true, true, cx);
18389    }
18390
18391    pub fn unfold_at(
18392        &mut self,
18393        buffer_row: MultiBufferRow,
18394        _window: &mut Window,
18395        cx: &mut Context<Self>,
18396    ) {
18397        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18398
18399        let intersection_range = Point::new(buffer_row.0, 0)
18400            ..Point::new(
18401                buffer_row.0,
18402                display_map.buffer_snapshot().line_len(buffer_row),
18403            );
18404
18405        let autoscroll = self
18406            .selections
18407            .all::<Point>(&display_map)
18408            .iter()
18409            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18410
18411        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18412    }
18413
18414    pub fn unfold_all(
18415        &mut self,
18416        _: &actions::UnfoldAll,
18417        _window: &mut Window,
18418        cx: &mut Context<Self>,
18419    ) {
18420        if self.buffer.read(cx).is_singleton() {
18421            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18422            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18423        } else {
18424            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18425                editor
18426                    .update(cx, |editor, cx| {
18427                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18428                            editor.unfold_buffer(buffer_id, cx);
18429                        }
18430                    })
18431                    .ok();
18432            });
18433        }
18434    }
18435
18436    pub fn fold_selected_ranges(
18437        &mut self,
18438        _: &FoldSelectedRanges,
18439        window: &mut Window,
18440        cx: &mut Context<Self>,
18441    ) {
18442        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18443        let selections = self.selections.all_adjusted(&display_map);
18444        let ranges = selections
18445            .into_iter()
18446            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18447            .collect::<Vec<_>>();
18448        self.fold_creases(ranges, true, window, cx);
18449    }
18450
18451    pub fn fold_ranges<T: ToOffset + Clone>(
18452        &mut self,
18453        ranges: Vec<Range<T>>,
18454        auto_scroll: bool,
18455        window: &mut Window,
18456        cx: &mut Context<Self>,
18457    ) {
18458        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18459        let ranges = ranges
18460            .into_iter()
18461            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18462            .collect::<Vec<_>>();
18463        self.fold_creases(ranges, auto_scroll, window, cx);
18464    }
18465
18466    pub fn fold_creases<T: ToOffset + Clone>(
18467        &mut self,
18468        creases: Vec<Crease<T>>,
18469        auto_scroll: bool,
18470        _window: &mut Window,
18471        cx: &mut Context<Self>,
18472    ) {
18473        if creases.is_empty() {
18474            return;
18475        }
18476
18477        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18478
18479        if auto_scroll {
18480            self.request_autoscroll(Autoscroll::fit(), cx);
18481        }
18482
18483        cx.notify();
18484
18485        self.scrollbar_marker_state.dirty = true;
18486        self.folds_did_change(cx);
18487    }
18488
18489    /// Removes any folds whose ranges intersect any of the given ranges.
18490    pub fn unfold_ranges<T: ToOffset + Clone>(
18491        &mut self,
18492        ranges: &[Range<T>],
18493        inclusive: bool,
18494        auto_scroll: bool,
18495        cx: &mut Context<Self>,
18496    ) {
18497        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18498            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18499        });
18500        self.folds_did_change(cx);
18501    }
18502
18503    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18504        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18505            return;
18506        }
18507        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18508        self.display_map.update(cx, |display_map, cx| {
18509            display_map.fold_buffers([buffer_id], cx)
18510        });
18511        cx.emit(EditorEvent::BufferFoldToggled {
18512            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18513            folded: true,
18514        });
18515        cx.notify();
18516    }
18517
18518    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18519        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18520            return;
18521        }
18522        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18523        self.display_map.update(cx, |display_map, cx| {
18524            display_map.unfold_buffers([buffer_id], cx);
18525        });
18526        cx.emit(EditorEvent::BufferFoldToggled {
18527            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18528            folded: false,
18529        });
18530        cx.notify();
18531    }
18532
18533    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18534        self.display_map.read(cx).is_buffer_folded(buffer)
18535    }
18536
18537    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18538        self.display_map.read(cx).folded_buffers()
18539    }
18540
18541    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18542        self.display_map.update(cx, |display_map, cx| {
18543            display_map.disable_header_for_buffer(buffer_id, cx);
18544        });
18545        cx.notify();
18546    }
18547
18548    /// Removes any folds with the given ranges.
18549    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18550        &mut self,
18551        ranges: &[Range<T>],
18552        type_id: TypeId,
18553        auto_scroll: bool,
18554        cx: &mut Context<Self>,
18555    ) {
18556        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18557            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18558        });
18559        self.folds_did_change(cx);
18560    }
18561
18562    fn remove_folds_with<T: ToOffset + Clone>(
18563        &mut self,
18564        ranges: &[Range<T>],
18565        auto_scroll: bool,
18566        cx: &mut Context<Self>,
18567        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18568    ) {
18569        if ranges.is_empty() {
18570            return;
18571        }
18572
18573        let mut buffers_affected = HashSet::default();
18574        let multi_buffer = self.buffer().read(cx);
18575        for range in ranges {
18576            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18577                buffers_affected.insert(buffer.read(cx).remote_id());
18578            };
18579        }
18580
18581        self.display_map.update(cx, update);
18582
18583        if auto_scroll {
18584            self.request_autoscroll(Autoscroll::fit(), cx);
18585        }
18586
18587        cx.notify();
18588        self.scrollbar_marker_state.dirty = true;
18589        self.active_indent_guides_state.dirty = true;
18590    }
18591
18592    pub fn update_renderer_widths(
18593        &mut self,
18594        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18595        cx: &mut Context<Self>,
18596    ) -> bool {
18597        self.display_map
18598            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18599    }
18600
18601    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18602        self.display_map.read(cx).fold_placeholder.clone()
18603    }
18604
18605    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18606        self.buffer.update(cx, |buffer, cx| {
18607            buffer.set_all_diff_hunks_expanded(cx);
18608        });
18609    }
18610
18611    pub fn expand_all_diff_hunks(
18612        &mut self,
18613        _: &ExpandAllDiffHunks,
18614        _window: &mut Window,
18615        cx: &mut Context<Self>,
18616    ) {
18617        self.buffer.update(cx, |buffer, cx| {
18618            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18619        });
18620    }
18621
18622    pub fn collapse_all_diff_hunks(
18623        &mut self,
18624        _: &CollapseAllDiffHunks,
18625        _window: &mut Window,
18626        cx: &mut Context<Self>,
18627    ) {
18628        self.buffer.update(cx, |buffer, cx| {
18629            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18630        });
18631    }
18632
18633    pub fn toggle_selected_diff_hunks(
18634        &mut self,
18635        _: &ToggleSelectedDiffHunks,
18636        _window: &mut Window,
18637        cx: &mut Context<Self>,
18638    ) {
18639        let ranges: Vec<_> = self
18640            .selections
18641            .disjoint_anchors()
18642            .iter()
18643            .map(|s| s.range())
18644            .collect();
18645        self.toggle_diff_hunks_in_ranges(ranges, cx);
18646    }
18647
18648    pub fn diff_hunks_in_ranges<'a>(
18649        &'a self,
18650        ranges: &'a [Range<Anchor>],
18651        buffer: &'a MultiBufferSnapshot,
18652    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18653        ranges.iter().flat_map(move |range| {
18654            let end_excerpt_id = range.end.excerpt_id;
18655            let range = range.to_point(buffer);
18656            let mut peek_end = range.end;
18657            if range.end.row < buffer.max_row().0 {
18658                peek_end = Point::new(range.end.row + 1, 0);
18659            }
18660            buffer
18661                .diff_hunks_in_range(range.start..peek_end)
18662                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18663        })
18664    }
18665
18666    pub fn has_stageable_diff_hunks_in_ranges(
18667        &self,
18668        ranges: &[Range<Anchor>],
18669        snapshot: &MultiBufferSnapshot,
18670    ) -> bool {
18671        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18672        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18673    }
18674
18675    pub fn toggle_staged_selected_diff_hunks(
18676        &mut self,
18677        _: &::git::ToggleStaged,
18678        _: &mut Window,
18679        cx: &mut Context<Self>,
18680    ) {
18681        let snapshot = self.buffer.read(cx).snapshot(cx);
18682        let ranges: Vec<_> = self
18683            .selections
18684            .disjoint_anchors()
18685            .iter()
18686            .map(|s| s.range())
18687            .collect();
18688        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18689        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18690    }
18691
18692    pub fn set_render_diff_hunk_controls(
18693        &mut self,
18694        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18695        cx: &mut Context<Self>,
18696    ) {
18697        self.render_diff_hunk_controls = render_diff_hunk_controls;
18698        cx.notify();
18699    }
18700
18701    pub fn stage_and_next(
18702        &mut self,
18703        _: &::git::StageAndNext,
18704        window: &mut Window,
18705        cx: &mut Context<Self>,
18706    ) {
18707        self.do_stage_or_unstage_and_next(true, window, cx);
18708    }
18709
18710    pub fn unstage_and_next(
18711        &mut self,
18712        _: &::git::UnstageAndNext,
18713        window: &mut Window,
18714        cx: &mut Context<Self>,
18715    ) {
18716        self.do_stage_or_unstage_and_next(false, window, cx);
18717    }
18718
18719    pub fn stage_or_unstage_diff_hunks(
18720        &mut self,
18721        stage: bool,
18722        ranges: Vec<Range<Anchor>>,
18723        cx: &mut Context<Self>,
18724    ) {
18725        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18726        cx.spawn(async move |this, cx| {
18727            task.await?;
18728            this.update(cx, |this, cx| {
18729                let snapshot = this.buffer.read(cx).snapshot(cx);
18730                let chunk_by = this
18731                    .diff_hunks_in_ranges(&ranges, &snapshot)
18732                    .chunk_by(|hunk| hunk.buffer_id);
18733                for (buffer_id, hunks) in &chunk_by {
18734                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18735                }
18736            })
18737        })
18738        .detach_and_log_err(cx);
18739    }
18740
18741    fn save_buffers_for_ranges_if_needed(
18742        &mut self,
18743        ranges: &[Range<Anchor>],
18744        cx: &mut Context<Editor>,
18745    ) -> Task<Result<()>> {
18746        let multibuffer = self.buffer.read(cx);
18747        let snapshot = multibuffer.read(cx);
18748        let buffer_ids: HashSet<_> = ranges
18749            .iter()
18750            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18751            .collect();
18752        drop(snapshot);
18753
18754        let mut buffers = HashSet::default();
18755        for buffer_id in buffer_ids {
18756            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18757                let buffer = buffer_entity.read(cx);
18758                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18759                {
18760                    buffers.insert(buffer_entity);
18761                }
18762            }
18763        }
18764
18765        if let Some(project) = &self.project {
18766            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18767        } else {
18768            Task::ready(Ok(()))
18769        }
18770    }
18771
18772    fn do_stage_or_unstage_and_next(
18773        &mut self,
18774        stage: bool,
18775        window: &mut Window,
18776        cx: &mut Context<Self>,
18777    ) {
18778        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18779
18780        if ranges.iter().any(|range| range.start != range.end) {
18781            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18782            return;
18783        }
18784
18785        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18786        let snapshot = self.snapshot(window, cx);
18787        let position = self
18788            .selections
18789            .newest::<Point>(&snapshot.display_snapshot)
18790            .head();
18791        let mut row = snapshot
18792            .buffer_snapshot()
18793            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18794            .find(|hunk| hunk.row_range.start.0 > position.row)
18795            .map(|hunk| hunk.row_range.start);
18796
18797        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18798        // Outside of the project diff editor, wrap around to the beginning.
18799        if !all_diff_hunks_expanded {
18800            row = row.or_else(|| {
18801                snapshot
18802                    .buffer_snapshot()
18803                    .diff_hunks_in_range(Point::zero()..position)
18804                    .find(|hunk| hunk.row_range.end.0 < position.row)
18805                    .map(|hunk| hunk.row_range.start)
18806            });
18807        }
18808
18809        if let Some(row) = row {
18810            let destination = Point::new(row.0, 0);
18811            let autoscroll = Autoscroll::center();
18812
18813            self.unfold_ranges(&[destination..destination], false, false, cx);
18814            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18815                s.select_ranges([destination..destination]);
18816            });
18817        }
18818    }
18819
18820    fn do_stage_or_unstage(
18821        &self,
18822        stage: bool,
18823        buffer_id: BufferId,
18824        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18825        cx: &mut App,
18826    ) -> Option<()> {
18827        let project = self.project()?;
18828        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18829        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18830        let buffer_snapshot = buffer.read(cx).snapshot();
18831        let file_exists = buffer_snapshot
18832            .file()
18833            .is_some_and(|file| file.disk_state().exists());
18834        diff.update(cx, |diff, cx| {
18835            diff.stage_or_unstage_hunks(
18836                stage,
18837                &hunks
18838                    .map(|hunk| buffer_diff::DiffHunk {
18839                        buffer_range: hunk.buffer_range,
18840                        diff_base_byte_range: hunk.diff_base_byte_range,
18841                        secondary_status: hunk.secondary_status,
18842                        range: Point::zero()..Point::zero(), // unused
18843                    })
18844                    .collect::<Vec<_>>(),
18845                &buffer_snapshot,
18846                file_exists,
18847                cx,
18848            )
18849        });
18850        None
18851    }
18852
18853    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18854        let ranges: Vec<_> = self
18855            .selections
18856            .disjoint_anchors()
18857            .iter()
18858            .map(|s| s.range())
18859            .collect();
18860        self.buffer
18861            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18862    }
18863
18864    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18865        self.buffer.update(cx, |buffer, cx| {
18866            let ranges = vec![Anchor::min()..Anchor::max()];
18867            if !buffer.all_diff_hunks_expanded()
18868                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18869            {
18870                buffer.collapse_diff_hunks(ranges, cx);
18871                true
18872            } else {
18873                false
18874            }
18875        })
18876    }
18877
18878    fn toggle_diff_hunks_in_ranges(
18879        &mut self,
18880        ranges: Vec<Range<Anchor>>,
18881        cx: &mut Context<Editor>,
18882    ) {
18883        self.buffer.update(cx, |buffer, cx| {
18884            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18885            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18886        })
18887    }
18888
18889    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18890        self.buffer.update(cx, |buffer, cx| {
18891            let snapshot = buffer.snapshot(cx);
18892            let excerpt_id = range.end.excerpt_id;
18893            let point_range = range.to_point(&snapshot);
18894            let expand = !buffer.single_hunk_is_expanded(range, cx);
18895            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18896        })
18897    }
18898
18899    pub(crate) fn apply_all_diff_hunks(
18900        &mut self,
18901        _: &ApplyAllDiffHunks,
18902        window: &mut Window,
18903        cx: &mut Context<Self>,
18904    ) {
18905        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18906
18907        let buffers = self.buffer.read(cx).all_buffers();
18908        for branch_buffer in buffers {
18909            branch_buffer.update(cx, |branch_buffer, cx| {
18910                branch_buffer.merge_into_base(Vec::new(), cx);
18911            });
18912        }
18913
18914        if let Some(project) = self.project.clone() {
18915            self.save(
18916                SaveOptions {
18917                    format: true,
18918                    autosave: false,
18919                },
18920                project,
18921                window,
18922                cx,
18923            )
18924            .detach_and_log_err(cx);
18925        }
18926    }
18927
18928    pub(crate) fn apply_selected_diff_hunks(
18929        &mut self,
18930        _: &ApplyDiffHunk,
18931        window: &mut Window,
18932        cx: &mut Context<Self>,
18933    ) {
18934        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18935        let snapshot = self.snapshot(window, cx);
18936        let hunks = snapshot.hunks_for_ranges(
18937            self.selections
18938                .all(&snapshot.display_snapshot)
18939                .into_iter()
18940                .map(|selection| selection.range()),
18941        );
18942        let mut ranges_by_buffer = HashMap::default();
18943        self.transact(window, cx, |editor, _window, cx| {
18944            for hunk in hunks {
18945                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18946                    ranges_by_buffer
18947                        .entry(buffer.clone())
18948                        .or_insert_with(Vec::new)
18949                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18950                }
18951            }
18952
18953            for (buffer, ranges) in ranges_by_buffer {
18954                buffer.update(cx, |buffer, cx| {
18955                    buffer.merge_into_base(ranges, cx);
18956                });
18957            }
18958        });
18959
18960        if let Some(project) = self.project.clone() {
18961            self.save(
18962                SaveOptions {
18963                    format: true,
18964                    autosave: false,
18965                },
18966                project,
18967                window,
18968                cx,
18969            )
18970            .detach_and_log_err(cx);
18971        }
18972    }
18973
18974    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18975        if hovered != self.gutter_hovered {
18976            self.gutter_hovered = hovered;
18977            cx.notify();
18978        }
18979    }
18980
18981    pub fn insert_blocks(
18982        &mut self,
18983        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18984        autoscroll: Option<Autoscroll>,
18985        cx: &mut Context<Self>,
18986    ) -> Vec<CustomBlockId> {
18987        let blocks = self
18988            .display_map
18989            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18990        if let Some(autoscroll) = autoscroll {
18991            self.request_autoscroll(autoscroll, cx);
18992        }
18993        cx.notify();
18994        blocks
18995    }
18996
18997    pub fn resize_blocks(
18998        &mut self,
18999        heights: HashMap<CustomBlockId, u32>,
19000        autoscroll: Option<Autoscroll>,
19001        cx: &mut Context<Self>,
19002    ) {
19003        self.display_map
19004            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19005        if let Some(autoscroll) = autoscroll {
19006            self.request_autoscroll(autoscroll, cx);
19007        }
19008        cx.notify();
19009    }
19010
19011    pub fn replace_blocks(
19012        &mut self,
19013        renderers: HashMap<CustomBlockId, RenderBlock>,
19014        autoscroll: Option<Autoscroll>,
19015        cx: &mut Context<Self>,
19016    ) {
19017        self.display_map
19018            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19019        if let Some(autoscroll) = autoscroll {
19020            self.request_autoscroll(autoscroll, cx);
19021        }
19022        cx.notify();
19023    }
19024
19025    pub fn remove_blocks(
19026        &mut self,
19027        block_ids: HashSet<CustomBlockId>,
19028        autoscroll: Option<Autoscroll>,
19029        cx: &mut Context<Self>,
19030    ) {
19031        self.display_map.update(cx, |display_map, cx| {
19032            display_map.remove_blocks(block_ids, cx)
19033        });
19034        if let Some(autoscroll) = autoscroll {
19035            self.request_autoscroll(autoscroll, cx);
19036        }
19037        cx.notify();
19038    }
19039
19040    pub fn row_for_block(
19041        &self,
19042        block_id: CustomBlockId,
19043        cx: &mut Context<Self>,
19044    ) -> Option<DisplayRow> {
19045        self.display_map
19046            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19047    }
19048
19049    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19050        self.focused_block = Some(focused_block);
19051    }
19052
19053    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19054        self.focused_block.take()
19055    }
19056
19057    pub fn insert_creases(
19058        &mut self,
19059        creases: impl IntoIterator<Item = Crease<Anchor>>,
19060        cx: &mut Context<Self>,
19061    ) -> Vec<CreaseId> {
19062        self.display_map
19063            .update(cx, |map, cx| map.insert_creases(creases, cx))
19064    }
19065
19066    pub fn remove_creases(
19067        &mut self,
19068        ids: impl IntoIterator<Item = CreaseId>,
19069        cx: &mut Context<Self>,
19070    ) -> Vec<(CreaseId, Range<Anchor>)> {
19071        self.display_map
19072            .update(cx, |map, cx| map.remove_creases(ids, cx))
19073    }
19074
19075    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19076        self.display_map
19077            .update(cx, |map, cx| map.snapshot(cx))
19078            .longest_row()
19079    }
19080
19081    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19082        self.display_map
19083            .update(cx, |map, cx| map.snapshot(cx))
19084            .max_point()
19085    }
19086
19087    pub fn text(&self, cx: &App) -> String {
19088        self.buffer.read(cx).read(cx).text()
19089    }
19090
19091    pub fn is_empty(&self, cx: &App) -> bool {
19092        self.buffer.read(cx).read(cx).is_empty()
19093    }
19094
19095    pub fn text_option(&self, cx: &App) -> Option<String> {
19096        let text = self.text(cx);
19097        let text = text.trim();
19098
19099        if text.is_empty() {
19100            return None;
19101        }
19102
19103        Some(text.to_string())
19104    }
19105
19106    pub fn set_text(
19107        &mut self,
19108        text: impl Into<Arc<str>>,
19109        window: &mut Window,
19110        cx: &mut Context<Self>,
19111    ) {
19112        self.transact(window, cx, |this, _, cx| {
19113            this.buffer
19114                .read(cx)
19115                .as_singleton()
19116                .expect("you can only call set_text on editors for singleton buffers")
19117                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19118        });
19119    }
19120
19121    pub fn display_text(&self, cx: &mut App) -> String {
19122        self.display_map
19123            .update(cx, |map, cx| map.snapshot(cx))
19124            .text()
19125    }
19126
19127    fn create_minimap(
19128        &self,
19129        minimap_settings: MinimapSettings,
19130        window: &mut Window,
19131        cx: &mut Context<Self>,
19132    ) -> Option<Entity<Self>> {
19133        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19134            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19135    }
19136
19137    fn initialize_new_minimap(
19138        &self,
19139        minimap_settings: MinimapSettings,
19140        window: &mut Window,
19141        cx: &mut Context<Self>,
19142    ) -> Entity<Self> {
19143        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19144
19145        let mut minimap = Editor::new_internal(
19146            EditorMode::Minimap {
19147                parent: cx.weak_entity(),
19148            },
19149            self.buffer.clone(),
19150            None,
19151            Some(self.display_map.clone()),
19152            window,
19153            cx,
19154        );
19155        minimap.scroll_manager.clone_state(&self.scroll_manager);
19156        minimap.set_text_style_refinement(TextStyleRefinement {
19157            font_size: Some(MINIMAP_FONT_SIZE),
19158            font_weight: Some(MINIMAP_FONT_WEIGHT),
19159            ..Default::default()
19160        });
19161        minimap.update_minimap_configuration(minimap_settings, cx);
19162        cx.new(|_| minimap)
19163    }
19164
19165    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19166        let current_line_highlight = minimap_settings
19167            .current_line_highlight
19168            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19169        self.set_current_line_highlight(Some(current_line_highlight));
19170    }
19171
19172    pub fn minimap(&self) -> Option<&Entity<Self>> {
19173        self.minimap
19174            .as_ref()
19175            .filter(|_| self.minimap_visibility.visible())
19176    }
19177
19178    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19179        let mut wrap_guides = smallvec![];
19180
19181        if self.show_wrap_guides == Some(false) {
19182            return wrap_guides;
19183        }
19184
19185        let settings = self.buffer.read(cx).language_settings(cx);
19186        if settings.show_wrap_guides {
19187            match self.soft_wrap_mode(cx) {
19188                SoftWrap::Column(soft_wrap) => {
19189                    wrap_guides.push((soft_wrap as usize, true));
19190                }
19191                SoftWrap::Bounded(soft_wrap) => {
19192                    wrap_guides.push((soft_wrap as usize, true));
19193                }
19194                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19195            }
19196            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19197        }
19198
19199        wrap_guides
19200    }
19201
19202    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19203        let settings = self.buffer.read(cx).language_settings(cx);
19204        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19205        match mode {
19206            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19207                SoftWrap::None
19208            }
19209            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19210            language_settings::SoftWrap::PreferredLineLength => {
19211                SoftWrap::Column(settings.preferred_line_length)
19212            }
19213            language_settings::SoftWrap::Bounded => {
19214                SoftWrap::Bounded(settings.preferred_line_length)
19215            }
19216        }
19217    }
19218
19219    pub fn set_soft_wrap_mode(
19220        &mut self,
19221        mode: language_settings::SoftWrap,
19222
19223        cx: &mut Context<Self>,
19224    ) {
19225        self.soft_wrap_mode_override = Some(mode);
19226        cx.notify();
19227    }
19228
19229    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19230        self.hard_wrap = hard_wrap;
19231        cx.notify();
19232    }
19233
19234    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19235        self.text_style_refinement = Some(style);
19236    }
19237
19238    /// called by the Element so we know what style we were most recently rendered with.
19239    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19240        // We intentionally do not inform the display map about the minimap style
19241        // so that wrapping is not recalculated and stays consistent for the editor
19242        // and its linked minimap.
19243        if !self.mode.is_minimap() {
19244            let font = style.text.font();
19245            let font_size = style.text.font_size.to_pixels(window.rem_size());
19246            let display_map = self
19247                .placeholder_display_map
19248                .as_ref()
19249                .filter(|_| self.is_empty(cx))
19250                .unwrap_or(&self.display_map);
19251
19252            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19253        }
19254        self.style = Some(style);
19255    }
19256
19257    pub fn style(&self) -> Option<&EditorStyle> {
19258        self.style.as_ref()
19259    }
19260
19261    // Called by the element. This method is not designed to be called outside of the editor
19262    // element's layout code because it does not notify when rewrapping is computed synchronously.
19263    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19264        if self.is_empty(cx) {
19265            self.placeholder_display_map
19266                .as_ref()
19267                .map_or(false, |display_map| {
19268                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19269                })
19270        } else {
19271            self.display_map
19272                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19273        }
19274    }
19275
19276    pub fn set_soft_wrap(&mut self) {
19277        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19278    }
19279
19280    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19281        if self.soft_wrap_mode_override.is_some() {
19282            self.soft_wrap_mode_override.take();
19283        } else {
19284            let soft_wrap = match self.soft_wrap_mode(cx) {
19285                SoftWrap::GitDiff => return,
19286                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19287                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19288                    language_settings::SoftWrap::None
19289                }
19290            };
19291            self.soft_wrap_mode_override = Some(soft_wrap);
19292        }
19293        cx.notify();
19294    }
19295
19296    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19297        let Some(workspace) = self.workspace() else {
19298            return;
19299        };
19300        let fs = workspace.read(cx).app_state().fs.clone();
19301        let current_show = TabBarSettings::get_global(cx).show;
19302        update_settings_file(fs, cx, move |setting, _| {
19303            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19304        });
19305    }
19306
19307    pub fn toggle_indent_guides(
19308        &mut self,
19309        _: &ToggleIndentGuides,
19310        _: &mut Window,
19311        cx: &mut Context<Self>,
19312    ) {
19313        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19314            self.buffer
19315                .read(cx)
19316                .language_settings(cx)
19317                .indent_guides
19318                .enabled
19319        });
19320        self.show_indent_guides = Some(!currently_enabled);
19321        cx.notify();
19322    }
19323
19324    fn should_show_indent_guides(&self) -> Option<bool> {
19325        self.show_indent_guides
19326    }
19327
19328    pub fn toggle_line_numbers(
19329        &mut self,
19330        _: &ToggleLineNumbers,
19331        _: &mut Window,
19332        cx: &mut Context<Self>,
19333    ) {
19334        let mut editor_settings = EditorSettings::get_global(cx).clone();
19335        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19336        EditorSettings::override_global(editor_settings, cx);
19337    }
19338
19339    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19340        if let Some(show_line_numbers) = self.show_line_numbers {
19341            return show_line_numbers;
19342        }
19343        EditorSettings::get_global(cx).gutter.line_numbers
19344    }
19345
19346    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19347        match (
19348            self.use_relative_line_numbers,
19349            EditorSettings::get_global(cx).relative_line_numbers,
19350        ) {
19351            (None, setting) => setting,
19352            (Some(false), _) => RelativeLineNumbers::Disabled,
19353            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19354            (Some(true), _) => RelativeLineNumbers::Enabled,
19355        }
19356    }
19357
19358    pub fn toggle_relative_line_numbers(
19359        &mut self,
19360        _: &ToggleRelativeLineNumbers,
19361        _: &mut Window,
19362        cx: &mut Context<Self>,
19363    ) {
19364        let is_relative = self.relative_line_numbers(cx);
19365        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19366    }
19367
19368    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19369        self.use_relative_line_numbers = is_relative;
19370        cx.notify();
19371    }
19372
19373    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19374        self.show_gutter = show_gutter;
19375        cx.notify();
19376    }
19377
19378    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19379        self.show_scrollbars = ScrollbarAxes {
19380            horizontal: show,
19381            vertical: show,
19382        };
19383        cx.notify();
19384    }
19385
19386    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19387        self.show_scrollbars.vertical = show;
19388        cx.notify();
19389    }
19390
19391    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19392        self.show_scrollbars.horizontal = show;
19393        cx.notify();
19394    }
19395
19396    pub fn set_minimap_visibility(
19397        &mut self,
19398        minimap_visibility: MinimapVisibility,
19399        window: &mut Window,
19400        cx: &mut Context<Self>,
19401    ) {
19402        if self.minimap_visibility != minimap_visibility {
19403            if minimap_visibility.visible() && self.minimap.is_none() {
19404                let minimap_settings = EditorSettings::get_global(cx).minimap;
19405                self.minimap =
19406                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19407            }
19408            self.minimap_visibility = minimap_visibility;
19409            cx.notify();
19410        }
19411    }
19412
19413    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19414        self.set_show_scrollbars(false, cx);
19415        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19416    }
19417
19418    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19419        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19420    }
19421
19422    /// Normally the text in full mode and auto height editors is padded on the
19423    /// left side by roughly half a character width for improved hit testing.
19424    ///
19425    /// Use this method to disable this for cases where this is not wanted (e.g.
19426    /// if you want to align the editor text with some other text above or below)
19427    /// or if you want to add this padding to single-line editors.
19428    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19429        self.offset_content = offset_content;
19430        cx.notify();
19431    }
19432
19433    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19434        self.show_line_numbers = Some(show_line_numbers);
19435        cx.notify();
19436    }
19437
19438    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19439        self.disable_expand_excerpt_buttons = true;
19440        cx.notify();
19441    }
19442
19443    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19444        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19445        cx.notify();
19446    }
19447
19448    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19449        self.show_code_actions = Some(show_code_actions);
19450        cx.notify();
19451    }
19452
19453    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19454        self.show_runnables = Some(show_runnables);
19455        cx.notify();
19456    }
19457
19458    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19459        self.show_breakpoints = Some(show_breakpoints);
19460        cx.notify();
19461    }
19462
19463    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19464        if self.display_map.read(cx).masked != masked {
19465            self.display_map.update(cx, |map, _| map.masked = masked);
19466        }
19467        cx.notify()
19468    }
19469
19470    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19471        self.show_wrap_guides = Some(show_wrap_guides);
19472        cx.notify();
19473    }
19474
19475    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19476        self.show_indent_guides = Some(show_indent_guides);
19477        cx.notify();
19478    }
19479
19480    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19481        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19482            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19483                && let Some(dir) = file.abs_path(cx).parent()
19484            {
19485                return Some(dir.to_owned());
19486            }
19487        }
19488
19489        None
19490    }
19491
19492    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19493        self.active_excerpt(cx)?
19494            .1
19495            .read(cx)
19496            .file()
19497            .and_then(|f| f.as_local())
19498    }
19499
19500    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19501        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19502            let buffer = buffer.read(cx);
19503            if let Some(project_path) = buffer.project_path(cx) {
19504                let project = self.project()?.read(cx);
19505                project.absolute_path(&project_path, cx)
19506            } else {
19507                buffer
19508                    .file()
19509                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19510            }
19511        })
19512    }
19513
19514    pub fn reveal_in_finder(
19515        &mut self,
19516        _: &RevealInFileManager,
19517        _window: &mut Window,
19518        cx: &mut Context<Self>,
19519    ) {
19520        if let Some(target) = self.target_file(cx) {
19521            cx.reveal_path(&target.abs_path(cx));
19522        }
19523    }
19524
19525    pub fn copy_path(
19526        &mut self,
19527        _: &zed_actions::workspace::CopyPath,
19528        _window: &mut Window,
19529        cx: &mut Context<Self>,
19530    ) {
19531        if let Some(path) = self.target_file_abs_path(cx)
19532            && let Some(path) = path.to_str()
19533        {
19534            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19535        } else {
19536            cx.propagate();
19537        }
19538    }
19539
19540    pub fn copy_relative_path(
19541        &mut self,
19542        _: &zed_actions::workspace::CopyRelativePath,
19543        _window: &mut Window,
19544        cx: &mut Context<Self>,
19545    ) {
19546        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19547            let project = self.project()?.read(cx);
19548            let path = buffer.read(cx).file()?.path();
19549            let path = path.display(project.path_style(cx));
19550            Some(path)
19551        }) {
19552            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19553        } else {
19554            cx.propagate();
19555        }
19556    }
19557
19558    /// Returns the project path for the editor's buffer, if any buffer is
19559    /// opened in the editor.
19560    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19561        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19562            buffer.read(cx).project_path(cx)
19563        } else {
19564            None
19565        }
19566    }
19567
19568    // Returns true if the editor handled a go-to-line request
19569    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19570        maybe!({
19571            let breakpoint_store = self.breakpoint_store.as_ref()?;
19572
19573            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19574            else {
19575                self.clear_row_highlights::<ActiveDebugLine>();
19576                return None;
19577            };
19578
19579            let position = active_stack_frame.position;
19580            let buffer_id = position.buffer_id?;
19581            let snapshot = self
19582                .project
19583                .as_ref()?
19584                .read(cx)
19585                .buffer_for_id(buffer_id, cx)?
19586                .read(cx)
19587                .snapshot();
19588
19589            let mut handled = false;
19590            for (id, ExcerptRange { context, .. }) in
19591                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19592            {
19593                if context.start.cmp(&position, &snapshot).is_ge()
19594                    || context.end.cmp(&position, &snapshot).is_lt()
19595                {
19596                    continue;
19597                }
19598                let snapshot = self.buffer.read(cx).snapshot(cx);
19599                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19600
19601                handled = true;
19602                self.clear_row_highlights::<ActiveDebugLine>();
19603
19604                self.go_to_line::<ActiveDebugLine>(
19605                    multibuffer_anchor,
19606                    Some(cx.theme().colors().editor_debugger_active_line_background),
19607                    window,
19608                    cx,
19609                );
19610
19611                cx.notify();
19612            }
19613
19614            handled.then_some(())
19615        })
19616        .is_some()
19617    }
19618
19619    pub fn copy_file_name_without_extension(
19620        &mut self,
19621        _: &CopyFileNameWithoutExtension,
19622        _: &mut Window,
19623        cx: &mut Context<Self>,
19624    ) {
19625        if let Some(file) = self.target_file(cx)
19626            && let Some(file_stem) = file.path().file_stem()
19627        {
19628            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19629        }
19630    }
19631
19632    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19633        if let Some(file) = self.target_file(cx)
19634            && let Some(name) = file.path().file_name()
19635        {
19636            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19637        }
19638    }
19639
19640    pub fn toggle_git_blame(
19641        &mut self,
19642        _: &::git::Blame,
19643        window: &mut Window,
19644        cx: &mut Context<Self>,
19645    ) {
19646        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19647
19648        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19649            self.start_git_blame(true, window, cx);
19650        }
19651
19652        cx.notify();
19653    }
19654
19655    pub fn toggle_git_blame_inline(
19656        &mut self,
19657        _: &ToggleGitBlameInline,
19658        window: &mut Window,
19659        cx: &mut Context<Self>,
19660    ) {
19661        self.toggle_git_blame_inline_internal(true, window, cx);
19662        cx.notify();
19663    }
19664
19665    pub fn open_git_blame_commit(
19666        &mut self,
19667        _: &OpenGitBlameCommit,
19668        window: &mut Window,
19669        cx: &mut Context<Self>,
19670    ) {
19671        self.open_git_blame_commit_internal(window, cx);
19672    }
19673
19674    fn open_git_blame_commit_internal(
19675        &mut self,
19676        window: &mut Window,
19677        cx: &mut Context<Self>,
19678    ) -> Option<()> {
19679        let blame = self.blame.as_ref()?;
19680        let snapshot = self.snapshot(window, cx);
19681        let cursor = self
19682            .selections
19683            .newest::<Point>(&snapshot.display_snapshot)
19684            .head();
19685        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19686        let (_, blame_entry) = blame
19687            .update(cx, |blame, cx| {
19688                blame
19689                    .blame_for_rows(
19690                        &[RowInfo {
19691                            buffer_id: Some(buffer.remote_id()),
19692                            buffer_row: Some(point.row),
19693                            ..Default::default()
19694                        }],
19695                        cx,
19696                    )
19697                    .next()
19698            })
19699            .flatten()?;
19700        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19701        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19702        let workspace = self.workspace()?.downgrade();
19703        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19704        None
19705    }
19706
19707    pub fn git_blame_inline_enabled(&self) -> bool {
19708        self.git_blame_inline_enabled
19709    }
19710
19711    pub fn toggle_selection_menu(
19712        &mut self,
19713        _: &ToggleSelectionMenu,
19714        _: &mut Window,
19715        cx: &mut Context<Self>,
19716    ) {
19717        self.show_selection_menu = self
19718            .show_selection_menu
19719            .map(|show_selections_menu| !show_selections_menu)
19720            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19721
19722        cx.notify();
19723    }
19724
19725    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19726        self.show_selection_menu
19727            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19728    }
19729
19730    fn start_git_blame(
19731        &mut self,
19732        user_triggered: bool,
19733        window: &mut Window,
19734        cx: &mut Context<Self>,
19735    ) {
19736        if let Some(project) = self.project() {
19737            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19738                && buffer.read(cx).file().is_none()
19739            {
19740                return;
19741            }
19742
19743            let focused = self.focus_handle(cx).contains_focused(window, cx);
19744
19745            let project = project.clone();
19746            let blame = cx
19747                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19748            self.blame_subscription =
19749                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19750            self.blame = Some(blame);
19751        }
19752    }
19753
19754    fn toggle_git_blame_inline_internal(
19755        &mut self,
19756        user_triggered: bool,
19757        window: &mut Window,
19758        cx: &mut Context<Self>,
19759    ) {
19760        if self.git_blame_inline_enabled {
19761            self.git_blame_inline_enabled = false;
19762            self.show_git_blame_inline = false;
19763            self.show_git_blame_inline_delay_task.take();
19764        } else {
19765            self.git_blame_inline_enabled = true;
19766            self.start_git_blame_inline(user_triggered, window, cx);
19767        }
19768
19769        cx.notify();
19770    }
19771
19772    fn start_git_blame_inline(
19773        &mut self,
19774        user_triggered: bool,
19775        window: &mut Window,
19776        cx: &mut Context<Self>,
19777    ) {
19778        self.start_git_blame(user_triggered, window, cx);
19779
19780        if ProjectSettings::get_global(cx)
19781            .git
19782            .inline_blame_delay()
19783            .is_some()
19784        {
19785            self.start_inline_blame_timer(window, cx);
19786        } else {
19787            self.show_git_blame_inline = true
19788        }
19789    }
19790
19791    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19792        self.blame.as_ref()
19793    }
19794
19795    pub fn show_git_blame_gutter(&self) -> bool {
19796        self.show_git_blame_gutter
19797    }
19798
19799    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19800        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19801    }
19802
19803    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19804        self.show_git_blame_inline
19805            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19806            && !self.newest_selection_head_on_empty_line(cx)
19807            && self.has_blame_entries(cx)
19808    }
19809
19810    fn has_blame_entries(&self, cx: &App) -> bool {
19811        self.blame()
19812            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19813    }
19814
19815    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19816        let cursor_anchor = self.selections.newest_anchor().head();
19817
19818        let snapshot = self.buffer.read(cx).snapshot(cx);
19819        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19820
19821        snapshot.line_len(buffer_row) == 0
19822    }
19823
19824    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19825        let buffer_and_selection = maybe!({
19826            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19827            let selection_range = selection.range();
19828
19829            let multi_buffer = self.buffer().read(cx);
19830            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19831            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19832
19833            let (buffer, range, _) = if selection.reversed {
19834                buffer_ranges.first()
19835            } else {
19836                buffer_ranges.last()
19837            }?;
19838
19839            let selection = text::ToPoint::to_point(&range.start, buffer).row
19840                ..text::ToPoint::to_point(&range.end, buffer).row;
19841            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19842        });
19843
19844        let Some((buffer, selection)) = buffer_and_selection else {
19845            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19846        };
19847
19848        let Some(project) = self.project() else {
19849            return Task::ready(Err(anyhow!("editor does not have project")));
19850        };
19851
19852        project.update(cx, |project, cx| {
19853            project.get_permalink_to_line(&buffer, selection, cx)
19854        })
19855    }
19856
19857    pub fn copy_permalink_to_line(
19858        &mut self,
19859        _: &CopyPermalinkToLine,
19860        window: &mut Window,
19861        cx: &mut Context<Self>,
19862    ) {
19863        let permalink_task = self.get_permalink_to_line(cx);
19864        let workspace = self.workspace();
19865
19866        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19867            Ok(permalink) => {
19868                cx.update(|_, cx| {
19869                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19870                })
19871                .ok();
19872            }
19873            Err(err) => {
19874                let message = format!("Failed to copy permalink: {err}");
19875
19876                anyhow::Result::<()>::Err(err).log_err();
19877
19878                if let Some(workspace) = workspace {
19879                    workspace
19880                        .update_in(cx, |workspace, _, cx| {
19881                            struct CopyPermalinkToLine;
19882
19883                            workspace.show_toast(
19884                                Toast::new(
19885                                    NotificationId::unique::<CopyPermalinkToLine>(),
19886                                    message,
19887                                ),
19888                                cx,
19889                            )
19890                        })
19891                        .ok();
19892                }
19893            }
19894        })
19895        .detach();
19896    }
19897
19898    pub fn copy_file_location(
19899        &mut self,
19900        _: &CopyFileLocation,
19901        _: &mut Window,
19902        cx: &mut Context<Self>,
19903    ) {
19904        let selection = self
19905            .selections
19906            .newest::<Point>(&self.display_snapshot(cx))
19907            .start
19908            .row
19909            + 1;
19910        if let Some(file) = self.target_file(cx) {
19911            let path = file.path().display(file.path_style(cx));
19912            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19913        }
19914    }
19915
19916    pub fn open_permalink_to_line(
19917        &mut self,
19918        _: &OpenPermalinkToLine,
19919        window: &mut Window,
19920        cx: &mut Context<Self>,
19921    ) {
19922        let permalink_task = self.get_permalink_to_line(cx);
19923        let workspace = self.workspace();
19924
19925        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19926            Ok(permalink) => {
19927                cx.update(|_, cx| {
19928                    cx.open_url(permalink.as_ref());
19929                })
19930                .ok();
19931            }
19932            Err(err) => {
19933                let message = format!("Failed to open permalink: {err}");
19934
19935                anyhow::Result::<()>::Err(err).log_err();
19936
19937                if let Some(workspace) = workspace {
19938                    workspace
19939                        .update(cx, |workspace, cx| {
19940                            struct OpenPermalinkToLine;
19941
19942                            workspace.show_toast(
19943                                Toast::new(
19944                                    NotificationId::unique::<OpenPermalinkToLine>(),
19945                                    message,
19946                                ),
19947                                cx,
19948                            )
19949                        })
19950                        .ok();
19951                }
19952            }
19953        })
19954        .detach();
19955    }
19956
19957    pub fn insert_uuid_v4(
19958        &mut self,
19959        _: &InsertUuidV4,
19960        window: &mut Window,
19961        cx: &mut Context<Self>,
19962    ) {
19963        self.insert_uuid(UuidVersion::V4, window, cx);
19964    }
19965
19966    pub fn insert_uuid_v7(
19967        &mut self,
19968        _: &InsertUuidV7,
19969        window: &mut Window,
19970        cx: &mut Context<Self>,
19971    ) {
19972        self.insert_uuid(UuidVersion::V7, window, cx);
19973    }
19974
19975    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19976        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19977        self.transact(window, cx, |this, window, cx| {
19978            let edits = this
19979                .selections
19980                .all::<Point>(&this.display_snapshot(cx))
19981                .into_iter()
19982                .map(|selection| {
19983                    let uuid = match version {
19984                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19985                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19986                    };
19987
19988                    (selection.range(), uuid.to_string())
19989                });
19990            this.edit(edits, cx);
19991            this.refresh_edit_prediction(true, false, window, cx);
19992        });
19993    }
19994
19995    pub fn open_selections_in_multibuffer(
19996        &mut self,
19997        _: &OpenSelectionsInMultibuffer,
19998        window: &mut Window,
19999        cx: &mut Context<Self>,
20000    ) {
20001        let multibuffer = self.buffer.read(cx);
20002
20003        let Some(buffer) = multibuffer.as_singleton() else {
20004            return;
20005        };
20006
20007        let Some(workspace) = self.workspace() else {
20008            return;
20009        };
20010
20011        let title = multibuffer.title(cx).to_string();
20012
20013        let locations = self
20014            .selections
20015            .all_anchors(cx)
20016            .iter()
20017            .map(|selection| {
20018                (
20019                    buffer.clone(),
20020                    (selection.start.text_anchor..selection.end.text_anchor)
20021                        .to_point(buffer.read(cx)),
20022                )
20023            })
20024            .into_group_map();
20025
20026        cx.spawn_in(window, async move |_, cx| {
20027            workspace.update_in(cx, |workspace, window, cx| {
20028                Self::open_locations_in_multibuffer(
20029                    workspace,
20030                    locations,
20031                    format!("Selections for '{title}'"),
20032                    false,
20033                    MultibufferSelectionMode::All,
20034                    window,
20035                    cx,
20036                );
20037            })
20038        })
20039        .detach();
20040    }
20041
20042    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20043    /// last highlight added will be used.
20044    ///
20045    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20046    pub fn highlight_rows<T: 'static>(
20047        &mut self,
20048        range: Range<Anchor>,
20049        color: Hsla,
20050        options: RowHighlightOptions,
20051        cx: &mut Context<Self>,
20052    ) {
20053        let snapshot = self.buffer().read(cx).snapshot(cx);
20054        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20055        let ix = row_highlights.binary_search_by(|highlight| {
20056            Ordering::Equal
20057                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20058                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20059        });
20060
20061        if let Err(mut ix) = ix {
20062            let index = post_inc(&mut self.highlight_order);
20063
20064            // If this range intersects with the preceding highlight, then merge it with
20065            // the preceding highlight. Otherwise insert a new highlight.
20066            let mut merged = false;
20067            if ix > 0 {
20068                let prev_highlight = &mut row_highlights[ix - 1];
20069                if prev_highlight
20070                    .range
20071                    .end
20072                    .cmp(&range.start, &snapshot)
20073                    .is_ge()
20074                {
20075                    ix -= 1;
20076                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20077                        prev_highlight.range.end = range.end;
20078                    }
20079                    merged = true;
20080                    prev_highlight.index = index;
20081                    prev_highlight.color = color;
20082                    prev_highlight.options = options;
20083                }
20084            }
20085
20086            if !merged {
20087                row_highlights.insert(
20088                    ix,
20089                    RowHighlight {
20090                        range,
20091                        index,
20092                        color,
20093                        options,
20094                        type_id: TypeId::of::<T>(),
20095                    },
20096                );
20097            }
20098
20099            // If any of the following highlights intersect with this one, merge them.
20100            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20101                let highlight = &row_highlights[ix];
20102                if next_highlight
20103                    .range
20104                    .start
20105                    .cmp(&highlight.range.end, &snapshot)
20106                    .is_le()
20107                {
20108                    if next_highlight
20109                        .range
20110                        .end
20111                        .cmp(&highlight.range.end, &snapshot)
20112                        .is_gt()
20113                    {
20114                        row_highlights[ix].range.end = next_highlight.range.end;
20115                    }
20116                    row_highlights.remove(ix + 1);
20117                } else {
20118                    break;
20119                }
20120            }
20121        }
20122    }
20123
20124    /// Remove any highlighted row ranges of the given type that intersect the
20125    /// given ranges.
20126    pub fn remove_highlighted_rows<T: 'static>(
20127        &mut self,
20128        ranges_to_remove: Vec<Range<Anchor>>,
20129        cx: &mut Context<Self>,
20130    ) {
20131        let snapshot = self.buffer().read(cx).snapshot(cx);
20132        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20133        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20134        row_highlights.retain(|highlight| {
20135            while let Some(range_to_remove) = ranges_to_remove.peek() {
20136                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20137                    Ordering::Less | Ordering::Equal => {
20138                        ranges_to_remove.next();
20139                    }
20140                    Ordering::Greater => {
20141                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20142                            Ordering::Less | Ordering::Equal => {
20143                                return false;
20144                            }
20145                            Ordering::Greater => break,
20146                        }
20147                    }
20148                }
20149            }
20150
20151            true
20152        })
20153    }
20154
20155    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20156    pub fn clear_row_highlights<T: 'static>(&mut self) {
20157        self.highlighted_rows.remove(&TypeId::of::<T>());
20158    }
20159
20160    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20161    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20162        self.highlighted_rows
20163            .get(&TypeId::of::<T>())
20164            .map_or(&[] as &[_], |vec| vec.as_slice())
20165            .iter()
20166            .map(|highlight| (highlight.range.clone(), highlight.color))
20167    }
20168
20169    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20170    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20171    /// Allows to ignore certain kinds of highlights.
20172    pub fn highlighted_display_rows(
20173        &self,
20174        window: &mut Window,
20175        cx: &mut App,
20176    ) -> BTreeMap<DisplayRow, LineHighlight> {
20177        let snapshot = self.snapshot(window, cx);
20178        let mut used_highlight_orders = HashMap::default();
20179        self.highlighted_rows
20180            .iter()
20181            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20182            .fold(
20183                BTreeMap::<DisplayRow, LineHighlight>::new(),
20184                |mut unique_rows, highlight| {
20185                    let start = highlight.range.start.to_display_point(&snapshot);
20186                    let end = highlight.range.end.to_display_point(&snapshot);
20187                    let start_row = start.row().0;
20188                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20189                        && end.column() == 0
20190                    {
20191                        end.row().0.saturating_sub(1)
20192                    } else {
20193                        end.row().0
20194                    };
20195                    for row in start_row..=end_row {
20196                        let used_index =
20197                            used_highlight_orders.entry(row).or_insert(highlight.index);
20198                        if highlight.index >= *used_index {
20199                            *used_index = highlight.index;
20200                            unique_rows.insert(
20201                                DisplayRow(row),
20202                                LineHighlight {
20203                                    include_gutter: highlight.options.include_gutter,
20204                                    border: None,
20205                                    background: highlight.color.into(),
20206                                    type_id: Some(highlight.type_id),
20207                                },
20208                            );
20209                        }
20210                    }
20211                    unique_rows
20212                },
20213            )
20214    }
20215
20216    pub fn highlighted_display_row_for_autoscroll(
20217        &self,
20218        snapshot: &DisplaySnapshot,
20219    ) -> Option<DisplayRow> {
20220        self.highlighted_rows
20221            .values()
20222            .flat_map(|highlighted_rows| highlighted_rows.iter())
20223            .filter_map(|highlight| {
20224                if highlight.options.autoscroll {
20225                    Some(highlight.range.start.to_display_point(snapshot).row())
20226                } else {
20227                    None
20228                }
20229            })
20230            .min()
20231    }
20232
20233    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20234        self.highlight_background::<SearchWithinRange>(
20235            ranges,
20236            |colors| colors.colors().editor_document_highlight_read_background,
20237            cx,
20238        )
20239    }
20240
20241    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20242        self.breadcrumb_header = Some(new_header);
20243    }
20244
20245    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20246        self.clear_background_highlights::<SearchWithinRange>(cx);
20247    }
20248
20249    pub fn highlight_background<T: 'static>(
20250        &mut self,
20251        ranges: &[Range<Anchor>],
20252        color_fetcher: fn(&Theme) -> Hsla,
20253        cx: &mut Context<Self>,
20254    ) {
20255        self.background_highlights.insert(
20256            HighlightKey::Type(TypeId::of::<T>()),
20257            (color_fetcher, Arc::from(ranges)),
20258        );
20259        self.scrollbar_marker_state.dirty = true;
20260        cx.notify();
20261    }
20262
20263    pub fn highlight_background_key<T: 'static>(
20264        &mut self,
20265        key: usize,
20266        ranges: &[Range<Anchor>],
20267        color_fetcher: fn(&Theme) -> Hsla,
20268        cx: &mut Context<Self>,
20269    ) {
20270        self.background_highlights.insert(
20271            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20272            (color_fetcher, Arc::from(ranges)),
20273        );
20274        self.scrollbar_marker_state.dirty = true;
20275        cx.notify();
20276    }
20277
20278    pub fn clear_background_highlights<T: 'static>(
20279        &mut self,
20280        cx: &mut Context<Self>,
20281    ) -> Option<BackgroundHighlight> {
20282        let text_highlights = self
20283            .background_highlights
20284            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20285        if !text_highlights.1.is_empty() {
20286            self.scrollbar_marker_state.dirty = true;
20287            cx.notify();
20288        }
20289        Some(text_highlights)
20290    }
20291
20292    pub fn highlight_gutter<T: 'static>(
20293        &mut self,
20294        ranges: impl Into<Vec<Range<Anchor>>>,
20295        color_fetcher: fn(&App) -> Hsla,
20296        cx: &mut Context<Self>,
20297    ) {
20298        self.gutter_highlights
20299            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20300        cx.notify();
20301    }
20302
20303    pub fn clear_gutter_highlights<T: 'static>(
20304        &mut self,
20305        cx: &mut Context<Self>,
20306    ) -> Option<GutterHighlight> {
20307        cx.notify();
20308        self.gutter_highlights.remove(&TypeId::of::<T>())
20309    }
20310
20311    pub fn insert_gutter_highlight<T: 'static>(
20312        &mut self,
20313        range: Range<Anchor>,
20314        color_fetcher: fn(&App) -> Hsla,
20315        cx: &mut Context<Self>,
20316    ) {
20317        let snapshot = self.buffer().read(cx).snapshot(cx);
20318        let mut highlights = self
20319            .gutter_highlights
20320            .remove(&TypeId::of::<T>())
20321            .map(|(_, highlights)| highlights)
20322            .unwrap_or_default();
20323        let ix = highlights.binary_search_by(|highlight| {
20324            Ordering::Equal
20325                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20326                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20327        });
20328        if let Err(ix) = ix {
20329            highlights.insert(ix, range);
20330        }
20331        self.gutter_highlights
20332            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20333    }
20334
20335    pub fn remove_gutter_highlights<T: 'static>(
20336        &mut self,
20337        ranges_to_remove: Vec<Range<Anchor>>,
20338        cx: &mut Context<Self>,
20339    ) {
20340        let snapshot = self.buffer().read(cx).snapshot(cx);
20341        let Some((color_fetcher, mut gutter_highlights)) =
20342            self.gutter_highlights.remove(&TypeId::of::<T>())
20343        else {
20344            return;
20345        };
20346        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20347        gutter_highlights.retain(|highlight| {
20348            while let Some(range_to_remove) = ranges_to_remove.peek() {
20349                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20350                    Ordering::Less | Ordering::Equal => {
20351                        ranges_to_remove.next();
20352                    }
20353                    Ordering::Greater => {
20354                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20355                            Ordering::Less | Ordering::Equal => {
20356                                return false;
20357                            }
20358                            Ordering::Greater => break,
20359                        }
20360                    }
20361                }
20362            }
20363
20364            true
20365        });
20366        self.gutter_highlights
20367            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20368    }
20369
20370    #[cfg(feature = "test-support")]
20371    pub fn all_text_highlights(
20372        &self,
20373        window: &mut Window,
20374        cx: &mut Context<Self>,
20375    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20376        let snapshot = self.snapshot(window, cx);
20377        self.display_map.update(cx, |display_map, _| {
20378            display_map
20379                .all_text_highlights()
20380                .map(|highlight| {
20381                    let (style, ranges) = highlight.as_ref();
20382                    (
20383                        *style,
20384                        ranges
20385                            .iter()
20386                            .map(|range| range.clone().to_display_points(&snapshot))
20387                            .collect(),
20388                    )
20389                })
20390                .collect()
20391        })
20392    }
20393
20394    #[cfg(feature = "test-support")]
20395    pub fn all_text_background_highlights(
20396        &self,
20397        window: &mut Window,
20398        cx: &mut Context<Self>,
20399    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20400        let snapshot = self.snapshot(window, cx);
20401        let buffer = &snapshot.buffer_snapshot();
20402        let start = buffer.anchor_before(0);
20403        let end = buffer.anchor_after(buffer.len());
20404        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20405    }
20406
20407    #[cfg(any(test, feature = "test-support"))]
20408    pub fn sorted_background_highlights_in_range(
20409        &self,
20410        search_range: Range<Anchor>,
20411        display_snapshot: &DisplaySnapshot,
20412        theme: &Theme,
20413    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20414        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20415        res.sort_by(|a, b| {
20416            a.0.start
20417                .cmp(&b.0.start)
20418                .then_with(|| a.0.end.cmp(&b.0.end))
20419                .then_with(|| a.1.cmp(&b.1))
20420        });
20421        res
20422    }
20423
20424    #[cfg(feature = "test-support")]
20425    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20426        let snapshot = self.buffer().read(cx).snapshot(cx);
20427
20428        let highlights = self
20429            .background_highlights
20430            .get(&HighlightKey::Type(TypeId::of::<
20431                items::BufferSearchHighlights,
20432            >()));
20433
20434        if let Some((_color, ranges)) = highlights {
20435            ranges
20436                .iter()
20437                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20438                .collect_vec()
20439        } else {
20440            vec![]
20441        }
20442    }
20443
20444    fn document_highlights_for_position<'a>(
20445        &'a self,
20446        position: Anchor,
20447        buffer: &'a MultiBufferSnapshot,
20448    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20449        let read_highlights = self
20450            .background_highlights
20451            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20452            .map(|h| &h.1);
20453        let write_highlights = self
20454            .background_highlights
20455            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20456            .map(|h| &h.1);
20457        let left_position = position.bias_left(buffer);
20458        let right_position = position.bias_right(buffer);
20459        read_highlights
20460            .into_iter()
20461            .chain(write_highlights)
20462            .flat_map(move |ranges| {
20463                let start_ix = match ranges.binary_search_by(|probe| {
20464                    let cmp = probe.end.cmp(&left_position, buffer);
20465                    if cmp.is_ge() {
20466                        Ordering::Greater
20467                    } else {
20468                        Ordering::Less
20469                    }
20470                }) {
20471                    Ok(i) | Err(i) => i,
20472                };
20473
20474                ranges[start_ix..]
20475                    .iter()
20476                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20477            })
20478    }
20479
20480    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20481        self.background_highlights
20482            .get(&HighlightKey::Type(TypeId::of::<T>()))
20483            .is_some_and(|(_, highlights)| !highlights.is_empty())
20484    }
20485
20486    /// Returns all background highlights for a given range.
20487    ///
20488    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20489    pub fn background_highlights_in_range(
20490        &self,
20491        search_range: Range<Anchor>,
20492        display_snapshot: &DisplaySnapshot,
20493        theme: &Theme,
20494    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20495        let mut results = Vec::new();
20496        for (color_fetcher, ranges) in self.background_highlights.values() {
20497            let color = color_fetcher(theme);
20498            let start_ix = match ranges.binary_search_by(|probe| {
20499                let cmp = probe
20500                    .end
20501                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20502                if cmp.is_gt() {
20503                    Ordering::Greater
20504                } else {
20505                    Ordering::Less
20506                }
20507            }) {
20508                Ok(i) | Err(i) => i,
20509            };
20510            for range in &ranges[start_ix..] {
20511                if range
20512                    .start
20513                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20514                    .is_ge()
20515                {
20516                    break;
20517                }
20518
20519                let start = range.start.to_display_point(display_snapshot);
20520                let end = range.end.to_display_point(display_snapshot);
20521                results.push((start..end, color))
20522            }
20523        }
20524        results
20525    }
20526
20527    pub fn gutter_highlights_in_range(
20528        &self,
20529        search_range: Range<Anchor>,
20530        display_snapshot: &DisplaySnapshot,
20531        cx: &App,
20532    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20533        let mut results = Vec::new();
20534        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20535            let color = color_fetcher(cx);
20536            let start_ix = match ranges.binary_search_by(|probe| {
20537                let cmp = probe
20538                    .end
20539                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20540                if cmp.is_gt() {
20541                    Ordering::Greater
20542                } else {
20543                    Ordering::Less
20544                }
20545            }) {
20546                Ok(i) | Err(i) => i,
20547            };
20548            for range in &ranges[start_ix..] {
20549                if range
20550                    .start
20551                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20552                    .is_ge()
20553                {
20554                    break;
20555                }
20556
20557                let start = range.start.to_display_point(display_snapshot);
20558                let end = range.end.to_display_point(display_snapshot);
20559                results.push((start..end, color))
20560            }
20561        }
20562        results
20563    }
20564
20565    /// Get the text ranges corresponding to the redaction query
20566    pub fn redacted_ranges(
20567        &self,
20568        search_range: Range<Anchor>,
20569        display_snapshot: &DisplaySnapshot,
20570        cx: &App,
20571    ) -> Vec<Range<DisplayPoint>> {
20572        display_snapshot
20573            .buffer_snapshot()
20574            .redacted_ranges(search_range, |file| {
20575                if let Some(file) = file {
20576                    file.is_private()
20577                        && EditorSettings::get(
20578                            Some(SettingsLocation {
20579                                worktree_id: file.worktree_id(cx),
20580                                path: file.path().as_ref(),
20581                            }),
20582                            cx,
20583                        )
20584                        .redact_private_values
20585                } else {
20586                    false
20587                }
20588            })
20589            .map(|range| {
20590                range.start.to_display_point(display_snapshot)
20591                    ..range.end.to_display_point(display_snapshot)
20592            })
20593            .collect()
20594    }
20595
20596    pub fn highlight_text_key<T: 'static>(
20597        &mut self,
20598        key: usize,
20599        ranges: Vec<Range<Anchor>>,
20600        style: HighlightStyle,
20601        cx: &mut Context<Self>,
20602    ) {
20603        self.display_map.update(cx, |map, _| {
20604            map.highlight_text(
20605                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20606                ranges,
20607                style,
20608            );
20609        });
20610        cx.notify();
20611    }
20612
20613    pub fn highlight_text<T: 'static>(
20614        &mut self,
20615        ranges: Vec<Range<Anchor>>,
20616        style: HighlightStyle,
20617        cx: &mut Context<Self>,
20618    ) {
20619        self.display_map.update(cx, |map, _| {
20620            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20621        });
20622        cx.notify();
20623    }
20624
20625    pub fn text_highlights<'a, T: 'static>(
20626        &'a self,
20627        cx: &'a App,
20628    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20629        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20630    }
20631
20632    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20633        let cleared = self
20634            .display_map
20635            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20636        if cleared {
20637            cx.notify();
20638        }
20639    }
20640
20641    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20642        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20643            && self.focus_handle.is_focused(window)
20644    }
20645
20646    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20647        self.show_cursor_when_unfocused = is_enabled;
20648        cx.notify();
20649    }
20650
20651    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20652        cx.notify();
20653    }
20654
20655    fn on_debug_session_event(
20656        &mut self,
20657        _session: Entity<Session>,
20658        event: &SessionEvent,
20659        cx: &mut Context<Self>,
20660    ) {
20661        if let SessionEvent::InvalidateInlineValue = event {
20662            self.refresh_inline_values(cx);
20663        }
20664    }
20665
20666    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20667        let Some(project) = self.project.clone() else {
20668            return;
20669        };
20670
20671        if !self.inline_value_cache.enabled {
20672            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20673            self.splice_inlays(&inlays, Vec::new(), cx);
20674            return;
20675        }
20676
20677        let current_execution_position = self
20678            .highlighted_rows
20679            .get(&TypeId::of::<ActiveDebugLine>())
20680            .and_then(|lines| lines.last().map(|line| line.range.end));
20681
20682        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20683            let inline_values = editor
20684                .update(cx, |editor, cx| {
20685                    let Some(current_execution_position) = current_execution_position else {
20686                        return Some(Task::ready(Ok(Vec::new())));
20687                    };
20688
20689                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20690                        let snapshot = buffer.snapshot(cx);
20691
20692                        let excerpt = snapshot.excerpt_containing(
20693                            current_execution_position..current_execution_position,
20694                        )?;
20695
20696                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20697                    })?;
20698
20699                    let range =
20700                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20701
20702                    project.inline_values(buffer, range, cx)
20703                })
20704                .ok()
20705                .flatten()?
20706                .await
20707                .context("refreshing debugger inlays")
20708                .log_err()?;
20709
20710            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20711
20712            for (buffer_id, inline_value) in inline_values
20713                .into_iter()
20714                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20715            {
20716                buffer_inline_values
20717                    .entry(buffer_id)
20718                    .or_default()
20719                    .push(inline_value);
20720            }
20721
20722            editor
20723                .update(cx, |editor, cx| {
20724                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20725                    let mut new_inlays = Vec::default();
20726
20727                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20728                        let buffer_id = buffer_snapshot.remote_id();
20729                        buffer_inline_values
20730                            .get(&buffer_id)
20731                            .into_iter()
20732                            .flatten()
20733                            .for_each(|hint| {
20734                                let inlay = Inlay::debugger(
20735                                    post_inc(&mut editor.next_inlay_id),
20736                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20737                                    hint.text(),
20738                                );
20739                                if !inlay.text().chars().contains(&'\n') {
20740                                    new_inlays.push(inlay);
20741                                }
20742                            });
20743                    }
20744
20745                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20746                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20747
20748                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20749                })
20750                .ok()?;
20751            Some(())
20752        });
20753    }
20754
20755    fn on_buffer_event(
20756        &mut self,
20757        multibuffer: &Entity<MultiBuffer>,
20758        event: &multi_buffer::Event,
20759        window: &mut Window,
20760        cx: &mut Context<Self>,
20761    ) {
20762        match event {
20763            multi_buffer::Event::Edited { edited_buffer } => {
20764                self.scrollbar_marker_state.dirty = true;
20765                self.active_indent_guides_state.dirty = true;
20766                self.refresh_active_diagnostics(cx);
20767                self.refresh_code_actions(window, cx);
20768                self.refresh_selected_text_highlights(true, window, cx);
20769                self.refresh_single_line_folds(window, cx);
20770                self.refresh_matching_bracket_highlights(window, cx);
20771                if self.has_active_edit_prediction() {
20772                    self.update_visible_edit_prediction(window, cx);
20773                }
20774
20775                if let Some(buffer) = edited_buffer {
20776                    if buffer.read(cx).file().is_none() {
20777                        cx.emit(EditorEvent::TitleChanged);
20778                    }
20779
20780                    if self.project.is_some() {
20781                        let buffer_id = buffer.read(cx).remote_id();
20782                        self.register_buffer(buffer_id, cx);
20783                        self.update_lsp_data(Some(buffer_id), window, cx);
20784                        self.refresh_inlay_hints(
20785                            InlayHintRefreshReason::BufferEdited(buffer_id),
20786                            cx,
20787                        );
20788                    }
20789                }
20790
20791                cx.emit(EditorEvent::BufferEdited);
20792                cx.emit(SearchEvent::MatchesInvalidated);
20793
20794                let Some(project) = &self.project else { return };
20795                let (telemetry, is_via_ssh) = {
20796                    let project = project.read(cx);
20797                    let telemetry = project.client().telemetry().clone();
20798                    let is_via_ssh = project.is_via_remote_server();
20799                    (telemetry, is_via_ssh)
20800                };
20801                telemetry.log_edit_event("editor", is_via_ssh);
20802            }
20803            multi_buffer::Event::ExcerptsAdded {
20804                buffer,
20805                predecessor,
20806                excerpts,
20807            } => {
20808                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20809                let buffer_id = buffer.read(cx).remote_id();
20810                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20811                    && let Some(project) = &self.project
20812                {
20813                    update_uncommitted_diff_for_buffer(
20814                        cx.entity(),
20815                        project,
20816                        [buffer.clone()],
20817                        self.buffer.clone(),
20818                        cx,
20819                    )
20820                    .detach();
20821                }
20822                self.update_lsp_data(Some(buffer_id), window, cx);
20823                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20824                cx.emit(EditorEvent::ExcerptsAdded {
20825                    buffer: buffer.clone(),
20826                    predecessor: *predecessor,
20827                    excerpts: excerpts.clone(),
20828                });
20829            }
20830            multi_buffer::Event::ExcerptsRemoved {
20831                ids,
20832                removed_buffer_ids,
20833            } => {
20834                if let Some(inlay_hints) = &mut self.inlay_hints {
20835                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
20836                }
20837                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20838                for buffer_id in removed_buffer_ids {
20839                    self.registered_buffers.remove(buffer_id);
20840                }
20841                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20842                cx.emit(EditorEvent::ExcerptsRemoved {
20843                    ids: ids.clone(),
20844                    removed_buffer_ids: removed_buffer_ids.clone(),
20845                });
20846            }
20847            multi_buffer::Event::ExcerptsEdited {
20848                excerpt_ids,
20849                buffer_ids,
20850            } => {
20851                self.display_map.update(cx, |map, cx| {
20852                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20853                });
20854                cx.emit(EditorEvent::ExcerptsEdited {
20855                    ids: excerpt_ids.clone(),
20856                });
20857            }
20858            multi_buffer::Event::ExcerptsExpanded { ids } => {
20859                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20860                self.refresh_document_highlights(cx);
20861                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20862            }
20863            multi_buffer::Event::Reparsed(buffer_id) => {
20864                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20865                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20866
20867                cx.emit(EditorEvent::Reparsed(*buffer_id));
20868            }
20869            multi_buffer::Event::DiffHunksToggled => {
20870                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20871            }
20872            multi_buffer::Event::LanguageChanged(buffer_id) => {
20873                self.registered_buffers.remove(&buffer_id);
20874                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20875                cx.emit(EditorEvent::Reparsed(*buffer_id));
20876                cx.notify();
20877            }
20878            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20879            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20880            multi_buffer::Event::FileHandleChanged
20881            | multi_buffer::Event::Reloaded
20882            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20883            multi_buffer::Event::DiagnosticsUpdated => {
20884                self.update_diagnostics_state(window, cx);
20885            }
20886            _ => {}
20887        };
20888    }
20889
20890    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20891        if !self.diagnostics_enabled() {
20892            return;
20893        }
20894        self.refresh_active_diagnostics(cx);
20895        self.refresh_inline_diagnostics(true, window, cx);
20896        self.scrollbar_marker_state.dirty = true;
20897        cx.notify();
20898    }
20899
20900    pub fn start_temporary_diff_override(&mut self) {
20901        self.load_diff_task.take();
20902        self.temporary_diff_override = true;
20903    }
20904
20905    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20906        self.temporary_diff_override = false;
20907        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20908        self.buffer.update(cx, |buffer, cx| {
20909            buffer.set_all_diff_hunks_collapsed(cx);
20910        });
20911
20912        if let Some(project) = self.project.clone() {
20913            self.load_diff_task = Some(
20914                update_uncommitted_diff_for_buffer(
20915                    cx.entity(),
20916                    &project,
20917                    self.buffer.read(cx).all_buffers(),
20918                    self.buffer.clone(),
20919                    cx,
20920                )
20921                .shared(),
20922            );
20923        }
20924    }
20925
20926    fn on_display_map_changed(
20927        &mut self,
20928        _: Entity<DisplayMap>,
20929        _: &mut Window,
20930        cx: &mut Context<Self>,
20931    ) {
20932        cx.notify();
20933    }
20934
20935    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20936        if self.diagnostics_enabled() {
20937            let new_severity = EditorSettings::get_global(cx)
20938                .diagnostics_max_severity
20939                .unwrap_or(DiagnosticSeverity::Hint);
20940            self.set_max_diagnostics_severity(new_severity, cx);
20941        }
20942        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20943        self.update_edit_prediction_settings(cx);
20944        self.refresh_edit_prediction(true, false, window, cx);
20945        self.refresh_inline_values(cx);
20946        self.refresh_inlay_hints(
20947            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20948                self.selections.newest_anchor().head(),
20949                &self.buffer.read(cx).snapshot(cx),
20950                cx,
20951            )),
20952            cx,
20953        );
20954
20955        let old_cursor_shape = self.cursor_shape;
20956        let old_show_breadcrumbs = self.show_breadcrumbs;
20957
20958        {
20959            let editor_settings = EditorSettings::get_global(cx);
20960            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20961            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20962            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20963            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20964        }
20965
20966        if old_cursor_shape != self.cursor_shape {
20967            cx.emit(EditorEvent::CursorShapeChanged);
20968        }
20969
20970        if old_show_breadcrumbs != self.show_breadcrumbs {
20971            cx.emit(EditorEvent::BreadcrumbsChanged);
20972        }
20973
20974        let project_settings = ProjectSettings::get_global(cx);
20975        self.serialize_dirty_buffers =
20976            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20977
20978        if self.mode.is_full() {
20979            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20980            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20981            if self.show_inline_diagnostics != show_inline_diagnostics {
20982                self.show_inline_diagnostics = show_inline_diagnostics;
20983                self.refresh_inline_diagnostics(false, window, cx);
20984            }
20985
20986            if self.git_blame_inline_enabled != inline_blame_enabled {
20987                self.toggle_git_blame_inline_internal(false, window, cx);
20988            }
20989
20990            let minimap_settings = EditorSettings::get_global(cx).minimap;
20991            if self.minimap_visibility != MinimapVisibility::Disabled {
20992                if self.minimap_visibility.settings_visibility()
20993                    != minimap_settings.minimap_enabled()
20994                {
20995                    self.set_minimap_visibility(
20996                        MinimapVisibility::for_mode(self.mode(), cx),
20997                        window,
20998                        cx,
20999                    );
21000                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21001                    minimap_entity.update(cx, |minimap_editor, cx| {
21002                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21003                    })
21004                }
21005            }
21006        }
21007
21008        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21009            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21010        }) {
21011            if !inlay_splice.is_empty() {
21012                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21013            }
21014            self.refresh_colors_for_visible_range(None, window, cx);
21015        }
21016
21017        cx.notify();
21018    }
21019
21020    pub fn set_searchable(&mut self, searchable: bool) {
21021        self.searchable = searchable;
21022    }
21023
21024    pub fn searchable(&self) -> bool {
21025        self.searchable
21026    }
21027
21028    pub fn open_excerpts_in_split(
21029        &mut self,
21030        _: &OpenExcerptsSplit,
21031        window: &mut Window,
21032        cx: &mut Context<Self>,
21033    ) {
21034        self.open_excerpts_common(None, true, window, cx)
21035    }
21036
21037    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21038        self.open_excerpts_common(None, false, window, cx)
21039    }
21040
21041    fn open_excerpts_common(
21042        &mut self,
21043        jump_data: Option<JumpData>,
21044        split: bool,
21045        window: &mut Window,
21046        cx: &mut Context<Self>,
21047    ) {
21048        let Some(workspace) = self.workspace() else {
21049            cx.propagate();
21050            return;
21051        };
21052
21053        if self.buffer.read(cx).is_singleton() {
21054            cx.propagate();
21055            return;
21056        }
21057
21058        let mut new_selections_by_buffer = HashMap::default();
21059        match &jump_data {
21060            Some(JumpData::MultiBufferPoint {
21061                excerpt_id,
21062                position,
21063                anchor,
21064                line_offset_from_top,
21065            }) => {
21066                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21067                if let Some(buffer) = multi_buffer_snapshot
21068                    .buffer_id_for_excerpt(*excerpt_id)
21069                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21070                {
21071                    let buffer_snapshot = buffer.read(cx).snapshot();
21072                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21073                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21074                    } else {
21075                        buffer_snapshot.clip_point(*position, Bias::Left)
21076                    };
21077                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21078                    new_selections_by_buffer.insert(
21079                        buffer,
21080                        (
21081                            vec![jump_to_offset..jump_to_offset],
21082                            Some(*line_offset_from_top),
21083                        ),
21084                    );
21085                }
21086            }
21087            Some(JumpData::MultiBufferRow {
21088                row,
21089                line_offset_from_top,
21090            }) => {
21091                let point = MultiBufferPoint::new(row.0, 0);
21092                if let Some((buffer, buffer_point, _)) =
21093                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21094                {
21095                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21096                    new_selections_by_buffer
21097                        .entry(buffer)
21098                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21099                        .0
21100                        .push(buffer_offset..buffer_offset)
21101                }
21102            }
21103            None => {
21104                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21105                let multi_buffer = self.buffer.read(cx);
21106                for selection in selections {
21107                    for (snapshot, range, _, anchor) in multi_buffer
21108                        .snapshot(cx)
21109                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21110                    {
21111                        if let Some(anchor) = anchor {
21112                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21113                            else {
21114                                continue;
21115                            };
21116                            let offset = text::ToOffset::to_offset(
21117                                &anchor.text_anchor,
21118                                &buffer_handle.read(cx).snapshot(),
21119                            );
21120                            let range = offset..offset;
21121                            new_selections_by_buffer
21122                                .entry(buffer_handle)
21123                                .or_insert((Vec::new(), None))
21124                                .0
21125                                .push(range)
21126                        } else {
21127                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21128                            else {
21129                                continue;
21130                            };
21131                            new_selections_by_buffer
21132                                .entry(buffer_handle)
21133                                .or_insert((Vec::new(), None))
21134                                .0
21135                                .push(range)
21136                        }
21137                    }
21138                }
21139            }
21140        }
21141
21142        new_selections_by_buffer
21143            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21144
21145        if new_selections_by_buffer.is_empty() {
21146            return;
21147        }
21148
21149        // We defer the pane interaction because we ourselves are a workspace item
21150        // and activating a new item causes the pane to call a method on us reentrantly,
21151        // which panics if we're on the stack.
21152        window.defer(cx, move |window, cx| {
21153            workspace.update(cx, |workspace, cx| {
21154                let pane = if split {
21155                    workspace.adjacent_pane(window, cx)
21156                } else {
21157                    workspace.active_pane().clone()
21158                };
21159
21160                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21161                    let editor = buffer
21162                        .read(cx)
21163                        .file()
21164                        .is_none()
21165                        .then(|| {
21166                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21167                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21168                            // Instead, we try to activate the existing editor in the pane first.
21169                            let (editor, pane_item_index) =
21170                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21171                                    let editor = item.downcast::<Editor>()?;
21172                                    let singleton_buffer =
21173                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21174                                    if singleton_buffer == buffer {
21175                                        Some((editor, i))
21176                                    } else {
21177                                        None
21178                                    }
21179                                })?;
21180                            pane.update(cx, |pane, cx| {
21181                                pane.activate_item(pane_item_index, true, true, window, cx)
21182                            });
21183                            Some(editor)
21184                        })
21185                        .flatten()
21186                        .unwrap_or_else(|| {
21187                            workspace.open_project_item::<Self>(
21188                                pane.clone(),
21189                                buffer,
21190                                true,
21191                                true,
21192                                window,
21193                                cx,
21194                            )
21195                        });
21196
21197                    editor.update(cx, |editor, cx| {
21198                        let autoscroll = match scroll_offset {
21199                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21200                            None => Autoscroll::newest(),
21201                        };
21202                        let nav_history = editor.nav_history.take();
21203                        editor.change_selections(
21204                            SelectionEffects::scroll(autoscroll),
21205                            window,
21206                            cx,
21207                            |s| {
21208                                s.select_ranges(ranges);
21209                            },
21210                        );
21211                        editor.nav_history = nav_history;
21212                    });
21213                }
21214            })
21215        });
21216    }
21217
21218    // For now, don't allow opening excerpts in buffers that aren't backed by
21219    // regular project files.
21220    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21221        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21222    }
21223
21224    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21225        let snapshot = self.buffer.read(cx).read(cx);
21226        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21227        Some(
21228            ranges
21229                .iter()
21230                .map(move |range| {
21231                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21232                })
21233                .collect(),
21234        )
21235    }
21236
21237    fn selection_replacement_ranges(
21238        &self,
21239        range: Range<OffsetUtf16>,
21240        cx: &mut App,
21241    ) -> Vec<Range<OffsetUtf16>> {
21242        let selections = self
21243            .selections
21244            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21245        let newest_selection = selections
21246            .iter()
21247            .max_by_key(|selection| selection.id)
21248            .unwrap();
21249        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21250        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21251        let snapshot = self.buffer.read(cx).read(cx);
21252        selections
21253            .into_iter()
21254            .map(|mut selection| {
21255                selection.start.0 =
21256                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21257                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21258                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21259                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21260            })
21261            .collect()
21262    }
21263
21264    fn report_editor_event(
21265        &self,
21266        reported_event: ReportEditorEvent,
21267        file_extension: Option<String>,
21268        cx: &App,
21269    ) {
21270        if cfg!(any(test, feature = "test-support")) {
21271            return;
21272        }
21273
21274        let Some(project) = &self.project else { return };
21275
21276        // If None, we are in a file without an extension
21277        let file = self
21278            .buffer
21279            .read(cx)
21280            .as_singleton()
21281            .and_then(|b| b.read(cx).file());
21282        let file_extension = file_extension.or(file
21283            .as_ref()
21284            .and_then(|file| Path::new(file.file_name(cx)).extension())
21285            .and_then(|e| e.to_str())
21286            .map(|a| a.to_string()));
21287
21288        let vim_mode = vim_enabled(cx);
21289
21290        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21291        let copilot_enabled = edit_predictions_provider
21292            == language::language_settings::EditPredictionProvider::Copilot;
21293        let copilot_enabled_for_language = self
21294            .buffer
21295            .read(cx)
21296            .language_settings(cx)
21297            .show_edit_predictions;
21298
21299        let project = project.read(cx);
21300        let event_type = reported_event.event_type();
21301
21302        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21303            telemetry::event!(
21304                event_type,
21305                type = if auto_saved {"autosave"} else {"manual"},
21306                file_extension,
21307                vim_mode,
21308                copilot_enabled,
21309                copilot_enabled_for_language,
21310                edit_predictions_provider,
21311                is_via_ssh = project.is_via_remote_server(),
21312            );
21313        } else {
21314            telemetry::event!(
21315                event_type,
21316                file_extension,
21317                vim_mode,
21318                copilot_enabled,
21319                copilot_enabled_for_language,
21320                edit_predictions_provider,
21321                is_via_ssh = project.is_via_remote_server(),
21322            );
21323        };
21324    }
21325
21326    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21327    /// with each line being an array of {text, highlight} objects.
21328    fn copy_highlight_json(
21329        &mut self,
21330        _: &CopyHighlightJson,
21331        window: &mut Window,
21332        cx: &mut Context<Self>,
21333    ) {
21334        #[derive(Serialize)]
21335        struct Chunk<'a> {
21336            text: String,
21337            highlight: Option<&'a str>,
21338        }
21339
21340        let snapshot = self.buffer.read(cx).snapshot(cx);
21341        let range = self
21342            .selected_text_range(false, window, cx)
21343            .and_then(|selection| {
21344                if selection.range.is_empty() {
21345                    None
21346                } else {
21347                    Some(
21348                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21349                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21350                    )
21351                }
21352            })
21353            .unwrap_or_else(|| 0..snapshot.len());
21354
21355        let chunks = snapshot.chunks(range, true);
21356        let mut lines = Vec::new();
21357        let mut line: VecDeque<Chunk> = VecDeque::new();
21358
21359        let Some(style) = self.style.as_ref() else {
21360            return;
21361        };
21362
21363        for chunk in chunks {
21364            let highlight = chunk
21365                .syntax_highlight_id
21366                .and_then(|id| id.name(&style.syntax));
21367            let mut chunk_lines = chunk.text.split('\n').peekable();
21368            while let Some(text) = chunk_lines.next() {
21369                let mut merged_with_last_token = false;
21370                if let Some(last_token) = line.back_mut()
21371                    && last_token.highlight == highlight
21372                {
21373                    last_token.text.push_str(text);
21374                    merged_with_last_token = true;
21375                }
21376
21377                if !merged_with_last_token {
21378                    line.push_back(Chunk {
21379                        text: text.into(),
21380                        highlight,
21381                    });
21382                }
21383
21384                if chunk_lines.peek().is_some() {
21385                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21386                        line.pop_front();
21387                    }
21388                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21389                        line.pop_back();
21390                    }
21391
21392                    lines.push(mem::take(&mut line));
21393                }
21394            }
21395        }
21396
21397        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21398            return;
21399        };
21400        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21401    }
21402
21403    pub fn open_context_menu(
21404        &mut self,
21405        _: &OpenContextMenu,
21406        window: &mut Window,
21407        cx: &mut Context<Self>,
21408    ) {
21409        self.request_autoscroll(Autoscroll::newest(), cx);
21410        let position = self
21411            .selections
21412            .newest_display(&self.display_snapshot(cx))
21413            .start;
21414        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21415    }
21416
21417    pub fn replay_insert_event(
21418        &mut self,
21419        text: &str,
21420        relative_utf16_range: Option<Range<isize>>,
21421        window: &mut Window,
21422        cx: &mut Context<Self>,
21423    ) {
21424        if !self.input_enabled {
21425            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21426            return;
21427        }
21428        if let Some(relative_utf16_range) = relative_utf16_range {
21429            let selections = self
21430                .selections
21431                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21432            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21433                let new_ranges = selections.into_iter().map(|range| {
21434                    let start = OffsetUtf16(
21435                        range
21436                            .head()
21437                            .0
21438                            .saturating_add_signed(relative_utf16_range.start),
21439                    );
21440                    let end = OffsetUtf16(
21441                        range
21442                            .head()
21443                            .0
21444                            .saturating_add_signed(relative_utf16_range.end),
21445                    );
21446                    start..end
21447                });
21448                s.select_ranges(new_ranges);
21449            });
21450        }
21451
21452        self.handle_input(text, window, cx);
21453    }
21454
21455    pub fn is_focused(&self, window: &Window) -> bool {
21456        self.focus_handle.is_focused(window)
21457    }
21458
21459    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21460        cx.emit(EditorEvent::Focused);
21461
21462        if let Some(descendant) = self
21463            .last_focused_descendant
21464            .take()
21465            .and_then(|descendant| descendant.upgrade())
21466        {
21467            window.focus(&descendant);
21468        } else {
21469            if let Some(blame) = self.blame.as_ref() {
21470                blame.update(cx, GitBlame::focus)
21471            }
21472
21473            self.blink_manager.update(cx, BlinkManager::enable);
21474            self.show_cursor_names(window, cx);
21475            self.buffer.update(cx, |buffer, cx| {
21476                buffer.finalize_last_transaction(cx);
21477                if self.leader_id.is_none() {
21478                    buffer.set_active_selections(
21479                        &self.selections.disjoint_anchors_arc(),
21480                        self.selections.line_mode(),
21481                        self.cursor_shape,
21482                        cx,
21483                    );
21484                }
21485            });
21486        }
21487    }
21488
21489    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21490        cx.emit(EditorEvent::FocusedIn)
21491    }
21492
21493    fn handle_focus_out(
21494        &mut self,
21495        event: FocusOutEvent,
21496        _window: &mut Window,
21497        cx: &mut Context<Self>,
21498    ) {
21499        if event.blurred != self.focus_handle {
21500            self.last_focused_descendant = Some(event.blurred);
21501        }
21502        self.selection_drag_state = SelectionDragState::None;
21503        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21504    }
21505
21506    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21507        self.blink_manager.update(cx, BlinkManager::disable);
21508        self.buffer
21509            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21510
21511        if let Some(blame) = self.blame.as_ref() {
21512            blame.update(cx, GitBlame::blur)
21513        }
21514        if !self.hover_state.focused(window, cx) {
21515            hide_hover(self, cx);
21516        }
21517        if !self
21518            .context_menu
21519            .borrow()
21520            .as_ref()
21521            .is_some_and(|context_menu| context_menu.focused(window, cx))
21522        {
21523            self.hide_context_menu(window, cx);
21524        }
21525        self.take_active_edit_prediction(cx);
21526        cx.emit(EditorEvent::Blurred);
21527        cx.notify();
21528    }
21529
21530    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21531        let mut pending: String = window
21532            .pending_input_keystrokes()
21533            .into_iter()
21534            .flatten()
21535            .filter_map(|keystroke| {
21536                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21537                    keystroke.key_char.clone()
21538                } else {
21539                    None
21540                }
21541            })
21542            .collect();
21543
21544        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21545            pending = "".to_string();
21546        }
21547
21548        let existing_pending = self
21549            .text_highlights::<PendingInput>(cx)
21550            .map(|(_, ranges)| ranges.to_vec());
21551        if existing_pending.is_none() && pending.is_empty() {
21552            return;
21553        }
21554        let transaction =
21555            self.transact(window, cx, |this, window, cx| {
21556                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21557                let edits = selections
21558                    .iter()
21559                    .map(|selection| (selection.end..selection.end, pending.clone()));
21560                this.edit(edits, cx);
21561                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21562                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21563                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21564                    }));
21565                });
21566                if let Some(existing_ranges) = existing_pending {
21567                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21568                    this.edit(edits, cx);
21569                }
21570            });
21571
21572        let snapshot = self.snapshot(window, cx);
21573        let ranges = self
21574            .selections
21575            .all::<usize>(&snapshot.display_snapshot)
21576            .into_iter()
21577            .map(|selection| {
21578                snapshot.buffer_snapshot().anchor_after(selection.end)
21579                    ..snapshot
21580                        .buffer_snapshot()
21581                        .anchor_before(selection.end + pending.len())
21582            })
21583            .collect();
21584
21585        if pending.is_empty() {
21586            self.clear_highlights::<PendingInput>(cx);
21587        } else {
21588            self.highlight_text::<PendingInput>(
21589                ranges,
21590                HighlightStyle {
21591                    underline: Some(UnderlineStyle {
21592                        thickness: px(1.),
21593                        color: None,
21594                        wavy: false,
21595                    }),
21596                    ..Default::default()
21597                },
21598                cx,
21599            );
21600        }
21601
21602        self.ime_transaction = self.ime_transaction.or(transaction);
21603        if let Some(transaction) = self.ime_transaction {
21604            self.buffer.update(cx, |buffer, cx| {
21605                buffer.group_until_transaction(transaction, cx);
21606            });
21607        }
21608
21609        if self.text_highlights::<PendingInput>(cx).is_none() {
21610            self.ime_transaction.take();
21611        }
21612    }
21613
21614    pub fn register_action_renderer(
21615        &mut self,
21616        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21617    ) -> Subscription {
21618        let id = self.next_editor_action_id.post_inc();
21619        self.editor_actions
21620            .borrow_mut()
21621            .insert(id, Box::new(listener));
21622
21623        let editor_actions = self.editor_actions.clone();
21624        Subscription::new(move || {
21625            editor_actions.borrow_mut().remove(&id);
21626        })
21627    }
21628
21629    pub fn register_action<A: Action>(
21630        &mut self,
21631        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21632    ) -> Subscription {
21633        let id = self.next_editor_action_id.post_inc();
21634        let listener = Arc::new(listener);
21635        self.editor_actions.borrow_mut().insert(
21636            id,
21637            Box::new(move |_, window, _| {
21638                let listener = listener.clone();
21639                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21640                    let action = action.downcast_ref().unwrap();
21641                    if phase == DispatchPhase::Bubble {
21642                        listener(action, window, cx)
21643                    }
21644                })
21645            }),
21646        );
21647
21648        let editor_actions = self.editor_actions.clone();
21649        Subscription::new(move || {
21650            editor_actions.borrow_mut().remove(&id);
21651        })
21652    }
21653
21654    pub fn file_header_size(&self) -> u32 {
21655        FILE_HEADER_HEIGHT
21656    }
21657
21658    pub fn restore(
21659        &mut self,
21660        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21661        window: &mut Window,
21662        cx: &mut Context<Self>,
21663    ) {
21664        let workspace = self.workspace();
21665        let project = self.project();
21666        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21667            let mut tasks = Vec::new();
21668            for (buffer_id, changes) in revert_changes {
21669                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21670                    buffer.update(cx, |buffer, cx| {
21671                        buffer.edit(
21672                            changes
21673                                .into_iter()
21674                                .map(|(range, text)| (range, text.to_string())),
21675                            None,
21676                            cx,
21677                        );
21678                    });
21679
21680                    if let Some(project) =
21681                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21682                    {
21683                        project.update(cx, |project, cx| {
21684                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21685                        })
21686                    }
21687                }
21688            }
21689            tasks
21690        });
21691        cx.spawn_in(window, async move |_, cx| {
21692            for (buffer, task) in save_tasks {
21693                let result = task.await;
21694                if result.is_err() {
21695                    let Some(path) = buffer
21696                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21697                        .ok()
21698                    else {
21699                        continue;
21700                    };
21701                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21702                        let Some(task) = cx
21703                            .update_window_entity(workspace, |workspace, window, cx| {
21704                                workspace
21705                                    .open_path_preview(path, None, false, false, false, window, cx)
21706                            })
21707                            .ok()
21708                        else {
21709                            continue;
21710                        };
21711                        task.await.log_err();
21712                    }
21713                }
21714            }
21715        })
21716        .detach();
21717        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21718            selections.refresh()
21719        });
21720    }
21721
21722    pub fn to_pixel_point(
21723        &self,
21724        source: multi_buffer::Anchor,
21725        editor_snapshot: &EditorSnapshot,
21726        window: &mut Window,
21727    ) -> Option<gpui::Point<Pixels>> {
21728        let source_point = source.to_display_point(editor_snapshot);
21729        self.display_to_pixel_point(source_point, editor_snapshot, window)
21730    }
21731
21732    pub fn display_to_pixel_point(
21733        &self,
21734        source: DisplayPoint,
21735        editor_snapshot: &EditorSnapshot,
21736        window: &mut Window,
21737    ) -> Option<gpui::Point<Pixels>> {
21738        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21739        let text_layout_details = self.text_layout_details(window);
21740        let scroll_top = text_layout_details
21741            .scroll_anchor
21742            .scroll_position(editor_snapshot)
21743            .y;
21744
21745        if source.row().as_f64() < scroll_top.floor() {
21746            return None;
21747        }
21748        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21749        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21750        Some(gpui::Point::new(source_x, source_y))
21751    }
21752
21753    pub fn has_visible_completions_menu(&self) -> bool {
21754        !self.edit_prediction_preview_is_active()
21755            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21756                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21757            })
21758    }
21759
21760    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21761        if self.mode.is_minimap() {
21762            return;
21763        }
21764        self.addons
21765            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21766    }
21767
21768    pub fn unregister_addon<T: Addon>(&mut self) {
21769        self.addons.remove(&std::any::TypeId::of::<T>());
21770    }
21771
21772    pub fn addon<T: Addon>(&self) -> Option<&T> {
21773        let type_id = std::any::TypeId::of::<T>();
21774        self.addons
21775            .get(&type_id)
21776            .and_then(|item| item.to_any().downcast_ref::<T>())
21777    }
21778
21779    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21780        let type_id = std::any::TypeId::of::<T>();
21781        self.addons
21782            .get_mut(&type_id)
21783            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21784    }
21785
21786    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21787        let text_layout_details = self.text_layout_details(window);
21788        let style = &text_layout_details.editor_style;
21789        let font_id = window.text_system().resolve_font(&style.text.font());
21790        let font_size = style.text.font_size.to_pixels(window.rem_size());
21791        let line_height = style.text.line_height_in_pixels(window.rem_size());
21792        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21793        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21794
21795        CharacterDimensions {
21796            em_width,
21797            em_advance,
21798            line_height,
21799        }
21800    }
21801
21802    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21803        self.load_diff_task.clone()
21804    }
21805
21806    fn read_metadata_from_db(
21807        &mut self,
21808        item_id: u64,
21809        workspace_id: WorkspaceId,
21810        window: &mut Window,
21811        cx: &mut Context<Editor>,
21812    ) {
21813        if self.buffer_kind(cx) == ItemBufferKind::Singleton
21814            && !self.mode.is_minimap()
21815            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21816        {
21817            let buffer_snapshot = OnceCell::new();
21818
21819            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21820                && !folds.is_empty()
21821            {
21822                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21823                self.fold_ranges(
21824                    folds
21825                        .into_iter()
21826                        .map(|(start, end)| {
21827                            snapshot.clip_offset(start, Bias::Left)
21828                                ..snapshot.clip_offset(end, Bias::Right)
21829                        })
21830                        .collect(),
21831                    false,
21832                    window,
21833                    cx,
21834                );
21835            }
21836
21837            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21838                && !selections.is_empty()
21839            {
21840                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21841                // skip adding the initial selection to selection history
21842                self.selection_history.mode = SelectionHistoryMode::Skipping;
21843                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21844                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21845                        snapshot.clip_offset(start, Bias::Left)
21846                            ..snapshot.clip_offset(end, Bias::Right)
21847                    }));
21848                });
21849                self.selection_history.mode = SelectionHistoryMode::Normal;
21850            };
21851        }
21852
21853        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21854    }
21855
21856    fn update_lsp_data(
21857        &mut self,
21858        for_buffer: Option<BufferId>,
21859        window: &mut Window,
21860        cx: &mut Context<'_, Self>,
21861    ) {
21862        self.pull_diagnostics(for_buffer, window, cx);
21863        self.refresh_colors_for_visible_range(for_buffer, window, cx);
21864    }
21865
21866    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
21867        if self.ignore_lsp_data() {
21868            return;
21869        }
21870        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
21871            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
21872        }
21873    }
21874
21875    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
21876        if !self.registered_buffers.contains_key(&buffer_id)
21877            && let Some(project) = self.project.as_ref()
21878        {
21879            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
21880                project.update(cx, |project, cx| {
21881                    self.registered_buffers.insert(
21882                        buffer_id,
21883                        project.register_buffer_with_language_servers(&buffer, cx),
21884                    );
21885                });
21886            } else {
21887                self.registered_buffers.remove(&buffer_id);
21888            }
21889        }
21890    }
21891
21892    fn ignore_lsp_data(&self) -> bool {
21893        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
21894        // skip any LSP updates for it.
21895        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
21896    }
21897}
21898
21899fn edit_for_markdown_paste<'a>(
21900    buffer: &MultiBufferSnapshot,
21901    range: Range<usize>,
21902    to_insert: &'a str,
21903    url: Option<url::Url>,
21904) -> (Range<usize>, Cow<'a, str>) {
21905    if url.is_none() {
21906        return (range, Cow::Borrowed(to_insert));
21907    };
21908
21909    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
21910
21911    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
21912        Cow::Borrowed(to_insert)
21913    } else {
21914        Cow::Owned(format!("[{old_text}]({to_insert})"))
21915    };
21916    (range, new_text)
21917}
21918
21919fn vim_enabled(cx: &App) -> bool {
21920    vim_mode_setting::VimModeSetting::try_get(cx)
21921        .map(|vim_mode| vim_mode.0)
21922        .unwrap_or(false)
21923}
21924
21925fn process_completion_for_edit(
21926    completion: &Completion,
21927    intent: CompletionIntent,
21928    buffer: &Entity<Buffer>,
21929    cursor_position: &text::Anchor,
21930    cx: &mut Context<Editor>,
21931) -> CompletionEdit {
21932    let buffer = buffer.read(cx);
21933    let buffer_snapshot = buffer.snapshot();
21934    let (snippet, new_text) = if completion.is_snippet() {
21935        let mut snippet_source = completion.new_text.clone();
21936        // Workaround for typescript language server issues so that methods don't expand within
21937        // strings and functions with type expressions. The previous point is used because the query
21938        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21939        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
21940        let previous_point = if previous_point.column > 0 {
21941            cursor_position.to_previous_offset(&buffer_snapshot)
21942        } else {
21943            cursor_position.to_offset(&buffer_snapshot)
21944        };
21945        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21946            && scope.prefers_label_for_snippet_in_completion()
21947            && let Some(label) = completion.label()
21948            && matches!(
21949                completion.kind(),
21950                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21951            )
21952        {
21953            snippet_source = label;
21954        }
21955        match Snippet::parse(&snippet_source).log_err() {
21956            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21957            None => (None, completion.new_text.clone()),
21958        }
21959    } else {
21960        (None, completion.new_text.clone())
21961    };
21962
21963    let mut range_to_replace = {
21964        let replace_range = &completion.replace_range;
21965        if let CompletionSource::Lsp {
21966            insert_range: Some(insert_range),
21967            ..
21968        } = &completion.source
21969        {
21970            debug_assert_eq!(
21971                insert_range.start, replace_range.start,
21972                "insert_range and replace_range should start at the same position"
21973            );
21974            debug_assert!(
21975                insert_range
21976                    .start
21977                    .cmp(cursor_position, &buffer_snapshot)
21978                    .is_le(),
21979                "insert_range should start before or at cursor position"
21980            );
21981            debug_assert!(
21982                replace_range
21983                    .start
21984                    .cmp(cursor_position, &buffer_snapshot)
21985                    .is_le(),
21986                "replace_range should start before or at cursor position"
21987            );
21988
21989            let should_replace = match intent {
21990                CompletionIntent::CompleteWithInsert => false,
21991                CompletionIntent::CompleteWithReplace => true,
21992                CompletionIntent::Complete | CompletionIntent::Compose => {
21993                    let insert_mode =
21994                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21995                            .completions
21996                            .lsp_insert_mode;
21997                    match insert_mode {
21998                        LspInsertMode::Insert => false,
21999                        LspInsertMode::Replace => true,
22000                        LspInsertMode::ReplaceSubsequence => {
22001                            let mut text_to_replace = buffer.chars_for_range(
22002                                buffer.anchor_before(replace_range.start)
22003                                    ..buffer.anchor_after(replace_range.end),
22004                            );
22005                            let mut current_needle = text_to_replace.next();
22006                            for haystack_ch in completion.label.text.chars() {
22007                                if let Some(needle_ch) = current_needle
22008                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22009                                {
22010                                    current_needle = text_to_replace.next();
22011                                }
22012                            }
22013                            current_needle.is_none()
22014                        }
22015                        LspInsertMode::ReplaceSuffix => {
22016                            if replace_range
22017                                .end
22018                                .cmp(cursor_position, &buffer_snapshot)
22019                                .is_gt()
22020                            {
22021                                let range_after_cursor = *cursor_position..replace_range.end;
22022                                let text_after_cursor = buffer
22023                                    .text_for_range(
22024                                        buffer.anchor_before(range_after_cursor.start)
22025                                            ..buffer.anchor_after(range_after_cursor.end),
22026                                    )
22027                                    .collect::<String>()
22028                                    .to_ascii_lowercase();
22029                                completion
22030                                    .label
22031                                    .text
22032                                    .to_ascii_lowercase()
22033                                    .ends_with(&text_after_cursor)
22034                            } else {
22035                                true
22036                            }
22037                        }
22038                    }
22039                }
22040            };
22041
22042            if should_replace {
22043                replace_range.clone()
22044            } else {
22045                insert_range.clone()
22046            }
22047        } else {
22048            replace_range.clone()
22049        }
22050    };
22051
22052    if range_to_replace
22053        .end
22054        .cmp(cursor_position, &buffer_snapshot)
22055        .is_lt()
22056    {
22057        range_to_replace.end = *cursor_position;
22058    }
22059
22060    CompletionEdit {
22061        new_text,
22062        replace_range: range_to_replace.to_offset(buffer),
22063        snippet,
22064    }
22065}
22066
22067struct CompletionEdit {
22068    new_text: String,
22069    replace_range: Range<usize>,
22070    snippet: Option<Snippet>,
22071}
22072
22073fn insert_extra_newline_brackets(
22074    buffer: &MultiBufferSnapshot,
22075    range: Range<usize>,
22076    language: &language::LanguageScope,
22077) -> bool {
22078    let leading_whitespace_len = buffer
22079        .reversed_chars_at(range.start)
22080        .take_while(|c| c.is_whitespace() && *c != '\n')
22081        .map(|c| c.len_utf8())
22082        .sum::<usize>();
22083    let trailing_whitespace_len = buffer
22084        .chars_at(range.end)
22085        .take_while(|c| c.is_whitespace() && *c != '\n')
22086        .map(|c| c.len_utf8())
22087        .sum::<usize>();
22088    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22089
22090    language.brackets().any(|(pair, enabled)| {
22091        let pair_start = pair.start.trim_end();
22092        let pair_end = pair.end.trim_start();
22093
22094        enabled
22095            && pair.newline
22096            && buffer.contains_str_at(range.end, pair_end)
22097            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22098    })
22099}
22100
22101fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22102    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22103        [(buffer, range, _)] => (*buffer, range.clone()),
22104        _ => return false,
22105    };
22106    let pair = {
22107        let mut result: Option<BracketMatch> = None;
22108
22109        for pair in buffer
22110            .all_bracket_ranges(range.clone())
22111            .filter(move |pair| {
22112                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22113            })
22114        {
22115            let len = pair.close_range.end - pair.open_range.start;
22116
22117            if let Some(existing) = &result {
22118                let existing_len = existing.close_range.end - existing.open_range.start;
22119                if len > existing_len {
22120                    continue;
22121                }
22122            }
22123
22124            result = Some(pair);
22125        }
22126
22127        result
22128    };
22129    let Some(pair) = pair else {
22130        return false;
22131    };
22132    pair.newline_only
22133        && buffer
22134            .chars_for_range(pair.open_range.end..range.start)
22135            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22136            .all(|c| c.is_whitespace() && c != '\n')
22137}
22138
22139fn update_uncommitted_diff_for_buffer(
22140    editor: Entity<Editor>,
22141    project: &Entity<Project>,
22142    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22143    buffer: Entity<MultiBuffer>,
22144    cx: &mut App,
22145) -> Task<()> {
22146    let mut tasks = Vec::new();
22147    project.update(cx, |project, cx| {
22148        for buffer in buffers {
22149            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22150                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22151            }
22152        }
22153    });
22154    cx.spawn(async move |cx| {
22155        let diffs = future::join_all(tasks).await;
22156        if editor
22157            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22158            .unwrap_or(false)
22159        {
22160            return;
22161        }
22162
22163        buffer
22164            .update(cx, |buffer, cx| {
22165                for diff in diffs.into_iter().flatten() {
22166                    buffer.add_diff(diff, cx);
22167                }
22168            })
22169            .ok();
22170    })
22171}
22172
22173fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22174    let tab_size = tab_size.get() as usize;
22175    let mut width = offset;
22176
22177    for ch in text.chars() {
22178        width += if ch == '\t' {
22179            tab_size - (width % tab_size)
22180        } else {
22181            1
22182        };
22183    }
22184
22185    width - offset
22186}
22187
22188#[cfg(test)]
22189mod tests {
22190    use super::*;
22191
22192    #[test]
22193    fn test_string_size_with_expanded_tabs() {
22194        let nz = |val| NonZeroU32::new(val).unwrap();
22195        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22196        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22197        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22198        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22199        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22200        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22201        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22202        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22203    }
22204}
22205
22206/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22207struct WordBreakingTokenizer<'a> {
22208    input: &'a str,
22209}
22210
22211impl<'a> WordBreakingTokenizer<'a> {
22212    fn new(input: &'a str) -> Self {
22213        Self { input }
22214    }
22215}
22216
22217fn is_char_ideographic(ch: char) -> bool {
22218    use unicode_script::Script::*;
22219    use unicode_script::UnicodeScript;
22220    matches!(ch.script(), Han | Tangut | Yi)
22221}
22222
22223fn is_grapheme_ideographic(text: &str) -> bool {
22224    text.chars().any(is_char_ideographic)
22225}
22226
22227fn is_grapheme_whitespace(text: &str) -> bool {
22228    text.chars().any(|x| x.is_whitespace())
22229}
22230
22231fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22232    text.chars()
22233        .next()
22234        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22235}
22236
22237#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22238enum WordBreakToken<'a> {
22239    Word { token: &'a str, grapheme_len: usize },
22240    InlineWhitespace { token: &'a str, grapheme_len: usize },
22241    Newline,
22242}
22243
22244impl<'a> Iterator for WordBreakingTokenizer<'a> {
22245    /// Yields a span, the count of graphemes in the token, and whether it was
22246    /// whitespace. Note that it also breaks at word boundaries.
22247    type Item = WordBreakToken<'a>;
22248
22249    fn next(&mut self) -> Option<Self::Item> {
22250        use unicode_segmentation::UnicodeSegmentation;
22251        if self.input.is_empty() {
22252            return None;
22253        }
22254
22255        let mut iter = self.input.graphemes(true).peekable();
22256        let mut offset = 0;
22257        let mut grapheme_len = 0;
22258        if let Some(first_grapheme) = iter.next() {
22259            let is_newline = first_grapheme == "\n";
22260            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22261            offset += first_grapheme.len();
22262            grapheme_len += 1;
22263            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22264                if let Some(grapheme) = iter.peek().copied()
22265                    && should_stay_with_preceding_ideograph(grapheme)
22266                {
22267                    offset += grapheme.len();
22268                    grapheme_len += 1;
22269                }
22270            } else {
22271                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22272                let mut next_word_bound = words.peek().copied();
22273                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22274                    next_word_bound = words.next();
22275                }
22276                while let Some(grapheme) = iter.peek().copied() {
22277                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22278                        break;
22279                    };
22280                    if is_grapheme_whitespace(grapheme) != is_whitespace
22281                        || (grapheme == "\n") != is_newline
22282                    {
22283                        break;
22284                    };
22285                    offset += grapheme.len();
22286                    grapheme_len += 1;
22287                    iter.next();
22288                }
22289            }
22290            let token = &self.input[..offset];
22291            self.input = &self.input[offset..];
22292            if token == "\n" {
22293                Some(WordBreakToken::Newline)
22294            } else if is_whitespace {
22295                Some(WordBreakToken::InlineWhitespace {
22296                    token,
22297                    grapheme_len,
22298                })
22299            } else {
22300                Some(WordBreakToken::Word {
22301                    token,
22302                    grapheme_len,
22303                })
22304            }
22305        } else {
22306            None
22307        }
22308    }
22309}
22310
22311#[test]
22312fn test_word_breaking_tokenizer() {
22313    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22314        ("", &[]),
22315        ("  ", &[whitespace("  ", 2)]),
22316        ("Ʒ", &[word("Ʒ", 1)]),
22317        ("Ǽ", &[word("Ǽ", 1)]),
22318        ("", &[word("", 1)]),
22319        ("⋑⋑", &[word("⋑⋑", 2)]),
22320        (
22321            "原理,进而",
22322            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22323        ),
22324        (
22325            "hello world",
22326            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22327        ),
22328        (
22329            "hello, world",
22330            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22331        ),
22332        (
22333            "  hello world",
22334            &[
22335                whitespace("  ", 2),
22336                word("hello", 5),
22337                whitespace(" ", 1),
22338                word("world", 5),
22339            ],
22340        ),
22341        (
22342            "这是什么 \n 钢笔",
22343            &[
22344                word("", 1),
22345                word("", 1),
22346                word("", 1),
22347                word("", 1),
22348                whitespace(" ", 1),
22349                newline(),
22350                whitespace(" ", 1),
22351                word("", 1),
22352                word("", 1),
22353            ],
22354        ),
22355        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22356    ];
22357
22358    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22359        WordBreakToken::Word {
22360            token,
22361            grapheme_len,
22362        }
22363    }
22364
22365    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22366        WordBreakToken::InlineWhitespace {
22367            token,
22368            grapheme_len,
22369        }
22370    }
22371
22372    fn newline() -> WordBreakToken<'static> {
22373        WordBreakToken::Newline
22374    }
22375
22376    for (input, result) in tests {
22377        assert_eq!(
22378            WordBreakingTokenizer::new(input)
22379                .collect::<Vec<_>>()
22380                .as_slice(),
22381            *result,
22382        );
22383    }
22384}
22385
22386fn wrap_with_prefix(
22387    first_line_prefix: String,
22388    subsequent_lines_prefix: String,
22389    unwrapped_text: String,
22390    wrap_column: usize,
22391    tab_size: NonZeroU32,
22392    preserve_existing_whitespace: bool,
22393) -> String {
22394    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22395    let subsequent_lines_prefix_len =
22396        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22397    let mut wrapped_text = String::new();
22398    let mut current_line = first_line_prefix;
22399    let mut is_first_line = true;
22400
22401    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22402    let mut current_line_len = first_line_prefix_len;
22403    let mut in_whitespace = false;
22404    for token in tokenizer {
22405        let have_preceding_whitespace = in_whitespace;
22406        match token {
22407            WordBreakToken::Word {
22408                token,
22409                grapheme_len,
22410            } => {
22411                in_whitespace = false;
22412                let current_prefix_len = if is_first_line {
22413                    first_line_prefix_len
22414                } else {
22415                    subsequent_lines_prefix_len
22416                };
22417                if current_line_len + grapheme_len > wrap_column
22418                    && current_line_len != current_prefix_len
22419                {
22420                    wrapped_text.push_str(current_line.trim_end());
22421                    wrapped_text.push('\n');
22422                    is_first_line = false;
22423                    current_line = subsequent_lines_prefix.clone();
22424                    current_line_len = subsequent_lines_prefix_len;
22425                }
22426                current_line.push_str(token);
22427                current_line_len += grapheme_len;
22428            }
22429            WordBreakToken::InlineWhitespace {
22430                mut token,
22431                mut grapheme_len,
22432            } => {
22433                in_whitespace = true;
22434                if have_preceding_whitespace && !preserve_existing_whitespace {
22435                    continue;
22436                }
22437                if !preserve_existing_whitespace {
22438                    // Keep a single whitespace grapheme as-is
22439                    if let Some(first) =
22440                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22441                    {
22442                        token = first;
22443                    } else {
22444                        token = " ";
22445                    }
22446                    grapheme_len = 1;
22447                }
22448                let current_prefix_len = if is_first_line {
22449                    first_line_prefix_len
22450                } else {
22451                    subsequent_lines_prefix_len
22452                };
22453                if current_line_len + grapheme_len > wrap_column {
22454                    wrapped_text.push_str(current_line.trim_end());
22455                    wrapped_text.push('\n');
22456                    is_first_line = false;
22457                    current_line = subsequent_lines_prefix.clone();
22458                    current_line_len = subsequent_lines_prefix_len;
22459                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22460                    current_line.push_str(token);
22461                    current_line_len += grapheme_len;
22462                }
22463            }
22464            WordBreakToken::Newline => {
22465                in_whitespace = true;
22466                let current_prefix_len = if is_first_line {
22467                    first_line_prefix_len
22468                } else {
22469                    subsequent_lines_prefix_len
22470                };
22471                if preserve_existing_whitespace {
22472                    wrapped_text.push_str(current_line.trim_end());
22473                    wrapped_text.push('\n');
22474                    is_first_line = false;
22475                    current_line = subsequent_lines_prefix.clone();
22476                    current_line_len = subsequent_lines_prefix_len;
22477                } else if have_preceding_whitespace {
22478                    continue;
22479                } else if current_line_len + 1 > wrap_column
22480                    && current_line_len != current_prefix_len
22481                {
22482                    wrapped_text.push_str(current_line.trim_end());
22483                    wrapped_text.push('\n');
22484                    is_first_line = false;
22485                    current_line = subsequent_lines_prefix.clone();
22486                    current_line_len = subsequent_lines_prefix_len;
22487                } else if current_line_len != current_prefix_len {
22488                    current_line.push(' ');
22489                    current_line_len += 1;
22490                }
22491            }
22492        }
22493    }
22494
22495    if !current_line.is_empty() {
22496        wrapped_text.push_str(&current_line);
22497    }
22498    wrapped_text
22499}
22500
22501#[test]
22502fn test_wrap_with_prefix() {
22503    assert_eq!(
22504        wrap_with_prefix(
22505            "# ".to_string(),
22506            "# ".to_string(),
22507            "abcdefg".to_string(),
22508            4,
22509            NonZeroU32::new(4).unwrap(),
22510            false,
22511        ),
22512        "# abcdefg"
22513    );
22514    assert_eq!(
22515        wrap_with_prefix(
22516            "".to_string(),
22517            "".to_string(),
22518            "\thello world".to_string(),
22519            8,
22520            NonZeroU32::new(4).unwrap(),
22521            false,
22522        ),
22523        "hello\nworld"
22524    );
22525    assert_eq!(
22526        wrap_with_prefix(
22527            "// ".to_string(),
22528            "// ".to_string(),
22529            "xx \nyy zz aa bb cc".to_string(),
22530            12,
22531            NonZeroU32::new(4).unwrap(),
22532            false,
22533        ),
22534        "// xx yy zz\n// aa bb cc"
22535    );
22536    assert_eq!(
22537        wrap_with_prefix(
22538            String::new(),
22539            String::new(),
22540            "这是什么 \n 钢笔".to_string(),
22541            3,
22542            NonZeroU32::new(4).unwrap(),
22543            false,
22544        ),
22545        "这是什\n么 钢\n"
22546    );
22547    assert_eq!(
22548        wrap_with_prefix(
22549            String::new(),
22550            String::new(),
22551            format!("foo{}bar", '\u{2009}'), // thin space
22552            80,
22553            NonZeroU32::new(4).unwrap(),
22554            false,
22555        ),
22556        format!("foo{}bar", '\u{2009}')
22557    );
22558}
22559
22560pub trait CollaborationHub {
22561    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22562    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22563    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22564}
22565
22566impl CollaborationHub for Entity<Project> {
22567    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22568        self.read(cx).collaborators()
22569    }
22570
22571    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22572        self.read(cx).user_store().read(cx).participant_indices()
22573    }
22574
22575    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22576        let this = self.read(cx);
22577        let user_ids = this.collaborators().values().map(|c| c.user_id);
22578        this.user_store().read(cx).participant_names(user_ids, cx)
22579    }
22580}
22581
22582pub trait SemanticsProvider {
22583    fn hover(
22584        &self,
22585        buffer: &Entity<Buffer>,
22586        position: text::Anchor,
22587        cx: &mut App,
22588    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22589
22590    fn inline_values(
22591        &self,
22592        buffer_handle: Entity<Buffer>,
22593        range: Range<text::Anchor>,
22594        cx: &mut App,
22595    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22596
22597    fn applicable_inlay_chunks(
22598        &self,
22599        buffer: &Entity<Buffer>,
22600        ranges: &[Range<text::Anchor>],
22601        cx: &mut App,
22602    ) -> Vec<Range<BufferRow>>;
22603
22604    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22605
22606    fn inlay_hints(
22607        &self,
22608        invalidate: InvalidationStrategy,
22609        buffer: Entity<Buffer>,
22610        ranges: Vec<Range<text::Anchor>>,
22611        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22612        cx: &mut App,
22613    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22614
22615    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22616
22617    fn document_highlights(
22618        &self,
22619        buffer: &Entity<Buffer>,
22620        position: text::Anchor,
22621        cx: &mut App,
22622    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22623
22624    fn definitions(
22625        &self,
22626        buffer: &Entity<Buffer>,
22627        position: text::Anchor,
22628        kind: GotoDefinitionKind,
22629        cx: &mut App,
22630    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22631
22632    fn range_for_rename(
22633        &self,
22634        buffer: &Entity<Buffer>,
22635        position: text::Anchor,
22636        cx: &mut App,
22637    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22638
22639    fn perform_rename(
22640        &self,
22641        buffer: &Entity<Buffer>,
22642        position: text::Anchor,
22643        new_name: String,
22644        cx: &mut App,
22645    ) -> Option<Task<Result<ProjectTransaction>>>;
22646}
22647
22648pub trait CompletionProvider {
22649    fn completions(
22650        &self,
22651        excerpt_id: ExcerptId,
22652        buffer: &Entity<Buffer>,
22653        buffer_position: text::Anchor,
22654        trigger: CompletionContext,
22655        window: &mut Window,
22656        cx: &mut Context<Editor>,
22657    ) -> Task<Result<Vec<CompletionResponse>>>;
22658
22659    fn resolve_completions(
22660        &self,
22661        _buffer: Entity<Buffer>,
22662        _completion_indices: Vec<usize>,
22663        _completions: Rc<RefCell<Box<[Completion]>>>,
22664        _cx: &mut Context<Editor>,
22665    ) -> Task<Result<bool>> {
22666        Task::ready(Ok(false))
22667    }
22668
22669    fn apply_additional_edits_for_completion(
22670        &self,
22671        _buffer: Entity<Buffer>,
22672        _completions: Rc<RefCell<Box<[Completion]>>>,
22673        _completion_index: usize,
22674        _push_to_history: bool,
22675        _cx: &mut Context<Editor>,
22676    ) -> Task<Result<Option<language::Transaction>>> {
22677        Task::ready(Ok(None))
22678    }
22679
22680    fn is_completion_trigger(
22681        &self,
22682        buffer: &Entity<Buffer>,
22683        position: language::Anchor,
22684        text: &str,
22685        trigger_in_words: bool,
22686        menu_is_open: bool,
22687        cx: &mut Context<Editor>,
22688    ) -> bool;
22689
22690    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22691
22692    fn sort_completions(&self) -> bool {
22693        true
22694    }
22695
22696    fn filter_completions(&self) -> bool {
22697        true
22698    }
22699}
22700
22701pub trait CodeActionProvider {
22702    fn id(&self) -> Arc<str>;
22703
22704    fn code_actions(
22705        &self,
22706        buffer: &Entity<Buffer>,
22707        range: Range<text::Anchor>,
22708        window: &mut Window,
22709        cx: &mut App,
22710    ) -> Task<Result<Vec<CodeAction>>>;
22711
22712    fn apply_code_action(
22713        &self,
22714        buffer_handle: Entity<Buffer>,
22715        action: CodeAction,
22716        excerpt_id: ExcerptId,
22717        push_to_history: bool,
22718        window: &mut Window,
22719        cx: &mut App,
22720    ) -> Task<Result<ProjectTransaction>>;
22721}
22722
22723impl CodeActionProvider for Entity<Project> {
22724    fn id(&self) -> Arc<str> {
22725        "project".into()
22726    }
22727
22728    fn code_actions(
22729        &self,
22730        buffer: &Entity<Buffer>,
22731        range: Range<text::Anchor>,
22732        _window: &mut Window,
22733        cx: &mut App,
22734    ) -> Task<Result<Vec<CodeAction>>> {
22735        self.update(cx, |project, cx| {
22736            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22737            let code_actions = project.code_actions(buffer, range, None, cx);
22738            cx.background_spawn(async move {
22739                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22740                Ok(code_lens_actions
22741                    .context("code lens fetch")?
22742                    .into_iter()
22743                    .flatten()
22744                    .chain(
22745                        code_actions
22746                            .context("code action fetch")?
22747                            .into_iter()
22748                            .flatten(),
22749                    )
22750                    .collect())
22751            })
22752        })
22753    }
22754
22755    fn apply_code_action(
22756        &self,
22757        buffer_handle: Entity<Buffer>,
22758        action: CodeAction,
22759        _excerpt_id: ExcerptId,
22760        push_to_history: bool,
22761        _window: &mut Window,
22762        cx: &mut App,
22763    ) -> Task<Result<ProjectTransaction>> {
22764        self.update(cx, |project, cx| {
22765            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22766        })
22767    }
22768}
22769
22770fn snippet_completions(
22771    project: &Project,
22772    buffer: &Entity<Buffer>,
22773    buffer_position: text::Anchor,
22774    cx: &mut App,
22775) -> Task<Result<CompletionResponse>> {
22776    let languages = buffer.read(cx).languages_at(buffer_position);
22777    let snippet_store = project.snippets().read(cx);
22778
22779    let scopes: Vec<_> = languages
22780        .iter()
22781        .filter_map(|language| {
22782            let language_name = language.lsp_id();
22783            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22784
22785            if snippets.is_empty() {
22786                None
22787            } else {
22788                Some((language.default_scope(), snippets))
22789            }
22790        })
22791        .collect();
22792
22793    if scopes.is_empty() {
22794        return Task::ready(Ok(CompletionResponse {
22795            completions: vec![],
22796            display_options: CompletionDisplayOptions::default(),
22797            is_incomplete: false,
22798        }));
22799    }
22800
22801    let snapshot = buffer.read(cx).text_snapshot();
22802    let executor = cx.background_executor().clone();
22803
22804    cx.background_spawn(async move {
22805        let mut is_incomplete = false;
22806        let mut completions: Vec<Completion> = Vec::new();
22807        for (scope, snippets) in scopes.into_iter() {
22808            let classifier =
22809                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22810
22811            const MAX_WORD_PREFIX_LEN: usize = 128;
22812            let last_word: String = snapshot
22813                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22814                .take(MAX_WORD_PREFIX_LEN)
22815                .take_while(|c| classifier.is_word(*c))
22816                .collect::<String>()
22817                .chars()
22818                .rev()
22819                .collect();
22820
22821            if last_word.is_empty() {
22822                return Ok(CompletionResponse {
22823                    completions: vec![],
22824                    display_options: CompletionDisplayOptions::default(),
22825                    is_incomplete: true,
22826                });
22827            }
22828
22829            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22830            let to_lsp = |point: &text::Anchor| {
22831                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22832                point_to_lsp(end)
22833            };
22834            let lsp_end = to_lsp(&buffer_position);
22835
22836            let candidates = snippets
22837                .iter()
22838                .enumerate()
22839                .flat_map(|(ix, snippet)| {
22840                    snippet
22841                        .prefix
22842                        .iter()
22843                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22844                })
22845                .collect::<Vec<StringMatchCandidate>>();
22846
22847            const MAX_RESULTS: usize = 100;
22848            let mut matches = fuzzy::match_strings(
22849                &candidates,
22850                &last_word,
22851                last_word.chars().any(|c| c.is_uppercase()),
22852                true,
22853                MAX_RESULTS,
22854                &Default::default(),
22855                executor.clone(),
22856            )
22857            .await;
22858
22859            if matches.len() >= MAX_RESULTS {
22860                is_incomplete = true;
22861            }
22862
22863            // Remove all candidates where the query's start does not match the start of any word in the candidate
22864            if let Some(query_start) = last_word.chars().next() {
22865                matches.retain(|string_match| {
22866                    split_words(&string_match.string).any(|word| {
22867                        // Check that the first codepoint of the word as lowercase matches the first
22868                        // codepoint of the query as lowercase
22869                        word.chars()
22870                            .flat_map(|codepoint| codepoint.to_lowercase())
22871                            .zip(query_start.to_lowercase())
22872                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22873                    })
22874                });
22875            }
22876
22877            let matched_strings = matches
22878                .into_iter()
22879                .map(|m| m.string)
22880                .collect::<HashSet<_>>();
22881
22882            completions.extend(snippets.iter().filter_map(|snippet| {
22883                let matching_prefix = snippet
22884                    .prefix
22885                    .iter()
22886                    .find(|prefix| matched_strings.contains(*prefix))?;
22887                let start = as_offset - last_word.len();
22888                let start = snapshot.anchor_before(start);
22889                let range = start..buffer_position;
22890                let lsp_start = to_lsp(&start);
22891                let lsp_range = lsp::Range {
22892                    start: lsp_start,
22893                    end: lsp_end,
22894                };
22895                Some(Completion {
22896                    replace_range: range,
22897                    new_text: snippet.body.clone(),
22898                    source: CompletionSource::Lsp {
22899                        insert_range: None,
22900                        server_id: LanguageServerId(usize::MAX),
22901                        resolved: true,
22902                        lsp_completion: Box::new(lsp::CompletionItem {
22903                            label: snippet.prefix.first().unwrap().clone(),
22904                            kind: Some(CompletionItemKind::SNIPPET),
22905                            label_details: snippet.description.as_ref().map(|description| {
22906                                lsp::CompletionItemLabelDetails {
22907                                    detail: Some(description.clone()),
22908                                    description: None,
22909                                }
22910                            }),
22911                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22912                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22913                                lsp::InsertReplaceEdit {
22914                                    new_text: snippet.body.clone(),
22915                                    insert: lsp_range,
22916                                    replace: lsp_range,
22917                                },
22918                            )),
22919                            filter_text: Some(snippet.body.clone()),
22920                            sort_text: Some(char::MAX.to_string()),
22921                            ..lsp::CompletionItem::default()
22922                        }),
22923                        lsp_defaults: None,
22924                    },
22925                    label: CodeLabel::plain(matching_prefix.clone(), None),
22926                    icon_path: None,
22927                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22928                        single_line: snippet.name.clone().into(),
22929                        plain_text: snippet
22930                            .description
22931                            .clone()
22932                            .map(|description| description.into()),
22933                    }),
22934                    insert_text_mode: None,
22935                    confirm: None,
22936                })
22937            }))
22938        }
22939
22940        Ok(CompletionResponse {
22941            completions,
22942            display_options: CompletionDisplayOptions::default(),
22943            is_incomplete,
22944        })
22945    })
22946}
22947
22948impl CompletionProvider for Entity<Project> {
22949    fn completions(
22950        &self,
22951        _excerpt_id: ExcerptId,
22952        buffer: &Entity<Buffer>,
22953        buffer_position: text::Anchor,
22954        options: CompletionContext,
22955        _window: &mut Window,
22956        cx: &mut Context<Editor>,
22957    ) -> Task<Result<Vec<CompletionResponse>>> {
22958        self.update(cx, |project, cx| {
22959            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22960            let project_completions = project.completions(buffer, buffer_position, options, cx);
22961            cx.background_spawn(async move {
22962                let mut responses = project_completions.await?;
22963                let snippets = snippets.await?;
22964                if !snippets.completions.is_empty() {
22965                    responses.push(snippets);
22966                }
22967                Ok(responses)
22968            })
22969        })
22970    }
22971
22972    fn resolve_completions(
22973        &self,
22974        buffer: Entity<Buffer>,
22975        completion_indices: Vec<usize>,
22976        completions: Rc<RefCell<Box<[Completion]>>>,
22977        cx: &mut Context<Editor>,
22978    ) -> Task<Result<bool>> {
22979        self.update(cx, |project, cx| {
22980            project.lsp_store().update(cx, |lsp_store, cx| {
22981                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22982            })
22983        })
22984    }
22985
22986    fn apply_additional_edits_for_completion(
22987        &self,
22988        buffer: Entity<Buffer>,
22989        completions: Rc<RefCell<Box<[Completion]>>>,
22990        completion_index: usize,
22991        push_to_history: bool,
22992        cx: &mut Context<Editor>,
22993    ) -> Task<Result<Option<language::Transaction>>> {
22994        self.update(cx, |project, cx| {
22995            project.lsp_store().update(cx, |lsp_store, cx| {
22996                lsp_store.apply_additional_edits_for_completion(
22997                    buffer,
22998                    completions,
22999                    completion_index,
23000                    push_to_history,
23001                    cx,
23002                )
23003            })
23004        })
23005    }
23006
23007    fn is_completion_trigger(
23008        &self,
23009        buffer: &Entity<Buffer>,
23010        position: language::Anchor,
23011        text: &str,
23012        trigger_in_words: bool,
23013        menu_is_open: bool,
23014        cx: &mut Context<Editor>,
23015    ) -> bool {
23016        let mut chars = text.chars();
23017        let char = if let Some(char) = chars.next() {
23018            char
23019        } else {
23020            return false;
23021        };
23022        if chars.next().is_some() {
23023            return false;
23024        }
23025
23026        let buffer = buffer.read(cx);
23027        let snapshot = buffer.snapshot();
23028        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23029            return false;
23030        }
23031        let classifier = snapshot
23032            .char_classifier_at(position)
23033            .scope_context(Some(CharScopeContext::Completion));
23034        if trigger_in_words && classifier.is_word(char) {
23035            return true;
23036        }
23037
23038        buffer.completion_triggers().contains(text)
23039    }
23040}
23041
23042impl SemanticsProvider for Entity<Project> {
23043    fn hover(
23044        &self,
23045        buffer: &Entity<Buffer>,
23046        position: text::Anchor,
23047        cx: &mut App,
23048    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23049        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23050    }
23051
23052    fn document_highlights(
23053        &self,
23054        buffer: &Entity<Buffer>,
23055        position: text::Anchor,
23056        cx: &mut App,
23057    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23058        Some(self.update(cx, |project, cx| {
23059            project.document_highlights(buffer, position, cx)
23060        }))
23061    }
23062
23063    fn definitions(
23064        &self,
23065        buffer: &Entity<Buffer>,
23066        position: text::Anchor,
23067        kind: GotoDefinitionKind,
23068        cx: &mut App,
23069    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23070        Some(self.update(cx, |project, cx| match kind {
23071            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23072            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23073            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23074            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23075        }))
23076    }
23077
23078    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23079        self.update(cx, |project, cx| {
23080            if project
23081                .active_debug_session(cx)
23082                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23083            {
23084                return true;
23085            }
23086
23087            buffer.update(cx, |buffer, cx| {
23088                project.any_language_server_supports_inlay_hints(buffer, cx)
23089            })
23090        })
23091    }
23092
23093    fn inline_values(
23094        &self,
23095        buffer_handle: Entity<Buffer>,
23096        range: Range<text::Anchor>,
23097        cx: &mut App,
23098    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23099        self.update(cx, |project, cx| {
23100            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23101
23102            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23103        })
23104    }
23105
23106    fn applicable_inlay_chunks(
23107        &self,
23108        buffer: &Entity<Buffer>,
23109        ranges: &[Range<text::Anchor>],
23110        cx: &mut App,
23111    ) -> Vec<Range<BufferRow>> {
23112        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23113            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23114        })
23115    }
23116
23117    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23118        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23119            lsp_store.invalidate_inlay_hints(for_buffers)
23120        });
23121    }
23122
23123    fn inlay_hints(
23124        &self,
23125        invalidate: InvalidationStrategy,
23126        buffer: Entity<Buffer>,
23127        ranges: Vec<Range<text::Anchor>>,
23128        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23129        cx: &mut App,
23130    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23131        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23132            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23133        }))
23134    }
23135
23136    fn range_for_rename(
23137        &self,
23138        buffer: &Entity<Buffer>,
23139        position: text::Anchor,
23140        cx: &mut App,
23141    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23142        Some(self.update(cx, |project, cx| {
23143            let buffer = buffer.clone();
23144            let task = project.prepare_rename(buffer.clone(), position, cx);
23145            cx.spawn(async move |_, cx| {
23146                Ok(match task.await? {
23147                    PrepareRenameResponse::Success(range) => Some(range),
23148                    PrepareRenameResponse::InvalidPosition => None,
23149                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23150                        // Fallback on using TreeSitter info to determine identifier range
23151                        buffer.read_with(cx, |buffer, _| {
23152                            let snapshot = buffer.snapshot();
23153                            let (range, kind) = snapshot.surrounding_word(position, None);
23154                            if kind != Some(CharKind::Word) {
23155                                return None;
23156                            }
23157                            Some(
23158                                snapshot.anchor_before(range.start)
23159                                    ..snapshot.anchor_after(range.end),
23160                            )
23161                        })?
23162                    }
23163                })
23164            })
23165        }))
23166    }
23167
23168    fn perform_rename(
23169        &self,
23170        buffer: &Entity<Buffer>,
23171        position: text::Anchor,
23172        new_name: String,
23173        cx: &mut App,
23174    ) -> Option<Task<Result<ProjectTransaction>>> {
23175        Some(self.update(cx, |project, cx| {
23176            project.perform_rename(buffer.clone(), position, new_name, cx)
23177        }))
23178    }
23179}
23180
23181fn consume_contiguous_rows(
23182    contiguous_row_selections: &mut Vec<Selection<Point>>,
23183    selection: &Selection<Point>,
23184    display_map: &DisplaySnapshot,
23185    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23186) -> (MultiBufferRow, MultiBufferRow) {
23187    contiguous_row_selections.push(selection.clone());
23188    let start_row = starting_row(selection, display_map);
23189    let mut end_row = ending_row(selection, display_map);
23190
23191    while let Some(next_selection) = selections.peek() {
23192        if next_selection.start.row <= end_row.0 {
23193            end_row = ending_row(next_selection, display_map);
23194            contiguous_row_selections.push(selections.next().unwrap().clone());
23195        } else {
23196            break;
23197        }
23198    }
23199    (start_row, end_row)
23200}
23201
23202fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23203    if selection.start.column > 0 {
23204        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23205    } else {
23206        MultiBufferRow(selection.start.row)
23207    }
23208}
23209
23210fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23211    if next_selection.end.column > 0 || next_selection.is_empty() {
23212        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23213    } else {
23214        MultiBufferRow(next_selection.end.row)
23215    }
23216}
23217
23218impl EditorSnapshot {
23219    pub fn remote_selections_in_range<'a>(
23220        &'a self,
23221        range: &'a Range<Anchor>,
23222        collaboration_hub: &dyn CollaborationHub,
23223        cx: &'a App,
23224    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23225        let participant_names = collaboration_hub.user_names(cx);
23226        let participant_indices = collaboration_hub.user_participant_indices(cx);
23227        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23228        let collaborators_by_replica_id = collaborators_by_peer_id
23229            .values()
23230            .map(|collaborator| (collaborator.replica_id, collaborator))
23231            .collect::<HashMap<_, _>>();
23232        self.buffer_snapshot()
23233            .selections_in_range(range, false)
23234            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23235                if replica_id == ReplicaId::AGENT {
23236                    Some(RemoteSelection {
23237                        replica_id,
23238                        selection,
23239                        cursor_shape,
23240                        line_mode,
23241                        collaborator_id: CollaboratorId::Agent,
23242                        user_name: Some("Agent".into()),
23243                        color: cx.theme().players().agent(),
23244                    })
23245                } else {
23246                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23247                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23248                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23249                    Some(RemoteSelection {
23250                        replica_id,
23251                        selection,
23252                        cursor_shape,
23253                        line_mode,
23254                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23255                        user_name,
23256                        color: if let Some(index) = participant_index {
23257                            cx.theme().players().color_for_participant(index.0)
23258                        } else {
23259                            cx.theme().players().absent()
23260                        },
23261                    })
23262                }
23263            })
23264    }
23265
23266    pub fn hunks_for_ranges(
23267        &self,
23268        ranges: impl IntoIterator<Item = Range<Point>>,
23269    ) -> Vec<MultiBufferDiffHunk> {
23270        let mut hunks = Vec::new();
23271        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23272            HashMap::default();
23273        for query_range in ranges {
23274            let query_rows =
23275                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23276            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23277                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23278            ) {
23279                // Include deleted hunks that are adjacent to the query range, because
23280                // otherwise they would be missed.
23281                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23282                if hunk.status().is_deleted() {
23283                    intersects_range |= hunk.row_range.start == query_rows.end;
23284                    intersects_range |= hunk.row_range.end == query_rows.start;
23285                }
23286                if intersects_range {
23287                    if !processed_buffer_rows
23288                        .entry(hunk.buffer_id)
23289                        .or_default()
23290                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23291                    {
23292                        continue;
23293                    }
23294                    hunks.push(hunk);
23295                }
23296            }
23297        }
23298
23299        hunks
23300    }
23301
23302    fn display_diff_hunks_for_rows<'a>(
23303        &'a self,
23304        display_rows: Range<DisplayRow>,
23305        folded_buffers: &'a HashSet<BufferId>,
23306    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23307        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23308        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23309
23310        self.buffer_snapshot()
23311            .diff_hunks_in_range(buffer_start..buffer_end)
23312            .filter_map(|hunk| {
23313                if folded_buffers.contains(&hunk.buffer_id) {
23314                    return None;
23315                }
23316
23317                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23318                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23319
23320                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23321                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23322
23323                let display_hunk = if hunk_display_start.column() != 0 {
23324                    DisplayDiffHunk::Folded {
23325                        display_row: hunk_display_start.row(),
23326                    }
23327                } else {
23328                    let mut end_row = hunk_display_end.row();
23329                    if hunk_display_end.column() > 0 {
23330                        end_row.0 += 1;
23331                    }
23332                    let is_created_file = hunk.is_created_file();
23333                    DisplayDiffHunk::Unfolded {
23334                        status: hunk.status(),
23335                        diff_base_byte_range: hunk.diff_base_byte_range,
23336                        display_row_range: hunk_display_start.row()..end_row,
23337                        multi_buffer_range: Anchor::range_in_buffer(
23338                            hunk.excerpt_id,
23339                            hunk.buffer_id,
23340                            hunk.buffer_range,
23341                        ),
23342                        is_created_file,
23343                    }
23344                };
23345
23346                Some(display_hunk)
23347            })
23348    }
23349
23350    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23351        self.display_snapshot
23352            .buffer_snapshot()
23353            .language_at(position)
23354    }
23355
23356    pub fn is_focused(&self) -> bool {
23357        self.is_focused
23358    }
23359
23360    pub fn placeholder_text(&self) -> Option<String> {
23361        self.placeholder_display_snapshot
23362            .as_ref()
23363            .map(|display_map| display_map.text())
23364    }
23365
23366    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23367        self.scroll_anchor.scroll_position(&self.display_snapshot)
23368    }
23369
23370    fn gutter_dimensions(
23371        &self,
23372        font_id: FontId,
23373        font_size: Pixels,
23374        max_line_number_width: Pixels,
23375        cx: &App,
23376    ) -> Option<GutterDimensions> {
23377        if !self.show_gutter {
23378            return None;
23379        }
23380
23381        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23382        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23383
23384        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23385            matches!(
23386                ProjectSettings::get_global(cx).git.git_gutter,
23387                GitGutterSetting::TrackedFiles
23388            )
23389        });
23390        let gutter_settings = EditorSettings::get_global(cx).gutter;
23391        let show_line_numbers = self
23392            .show_line_numbers
23393            .unwrap_or(gutter_settings.line_numbers);
23394        let line_gutter_width = if show_line_numbers {
23395            // Avoid flicker-like gutter resizes when the line number gains another digit by
23396            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23397            let min_width_for_number_on_gutter =
23398                ch_advance * gutter_settings.min_line_number_digits as f32;
23399            max_line_number_width.max(min_width_for_number_on_gutter)
23400        } else {
23401            0.0.into()
23402        };
23403
23404        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23405        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23406
23407        let git_blame_entries_width =
23408            self.git_blame_gutter_max_author_length
23409                .map(|max_author_length| {
23410                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23411                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23412
23413                    /// The number of characters to dedicate to gaps and margins.
23414                    const SPACING_WIDTH: usize = 4;
23415
23416                    let max_char_count = max_author_length.min(renderer.max_author_length())
23417                        + ::git::SHORT_SHA_LENGTH
23418                        + MAX_RELATIVE_TIMESTAMP.len()
23419                        + SPACING_WIDTH;
23420
23421                    ch_advance * max_char_count
23422                });
23423
23424        let is_singleton = self.buffer_snapshot().is_singleton();
23425
23426        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23427        left_padding += if !is_singleton {
23428            ch_width * 4.0
23429        } else if show_runnables || show_breakpoints {
23430            ch_width * 3.0
23431        } else if show_git_gutter && show_line_numbers {
23432            ch_width * 2.0
23433        } else if show_git_gutter || show_line_numbers {
23434            ch_width
23435        } else {
23436            px(0.)
23437        };
23438
23439        let shows_folds = is_singleton && gutter_settings.folds;
23440
23441        let right_padding = if shows_folds && show_line_numbers {
23442            ch_width * 4.0
23443        } else if shows_folds || (!is_singleton && show_line_numbers) {
23444            ch_width * 3.0
23445        } else if show_line_numbers {
23446            ch_width
23447        } else {
23448            px(0.)
23449        };
23450
23451        Some(GutterDimensions {
23452            left_padding,
23453            right_padding,
23454            width: line_gutter_width + left_padding + right_padding,
23455            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23456            git_blame_entries_width,
23457        })
23458    }
23459
23460    pub fn render_crease_toggle(
23461        &self,
23462        buffer_row: MultiBufferRow,
23463        row_contains_cursor: bool,
23464        editor: Entity<Editor>,
23465        window: &mut Window,
23466        cx: &mut App,
23467    ) -> Option<AnyElement> {
23468        let folded = self.is_line_folded(buffer_row);
23469        let mut is_foldable = false;
23470
23471        if let Some(crease) = self
23472            .crease_snapshot
23473            .query_row(buffer_row, self.buffer_snapshot())
23474        {
23475            is_foldable = true;
23476            match crease {
23477                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23478                    if let Some(render_toggle) = render_toggle {
23479                        let toggle_callback =
23480                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23481                                if folded {
23482                                    editor.update(cx, |editor, cx| {
23483                                        editor.fold_at(buffer_row, window, cx)
23484                                    });
23485                                } else {
23486                                    editor.update(cx, |editor, cx| {
23487                                        editor.unfold_at(buffer_row, window, cx)
23488                                    });
23489                                }
23490                            });
23491                        return Some((render_toggle)(
23492                            buffer_row,
23493                            folded,
23494                            toggle_callback,
23495                            window,
23496                            cx,
23497                        ));
23498                    }
23499                }
23500            }
23501        }
23502
23503        is_foldable |= self.starts_indent(buffer_row);
23504
23505        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23506            Some(
23507                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23508                    .toggle_state(folded)
23509                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23510                        if folded {
23511                            this.unfold_at(buffer_row, window, cx);
23512                        } else {
23513                            this.fold_at(buffer_row, window, cx);
23514                        }
23515                    }))
23516                    .into_any_element(),
23517            )
23518        } else {
23519            None
23520        }
23521    }
23522
23523    pub fn render_crease_trailer(
23524        &self,
23525        buffer_row: MultiBufferRow,
23526        window: &mut Window,
23527        cx: &mut App,
23528    ) -> Option<AnyElement> {
23529        let folded = self.is_line_folded(buffer_row);
23530        if let Crease::Inline { render_trailer, .. } = self
23531            .crease_snapshot
23532            .query_row(buffer_row, self.buffer_snapshot())?
23533        {
23534            let render_trailer = render_trailer.as_ref()?;
23535            Some(render_trailer(buffer_row, folded, window, cx))
23536        } else {
23537            None
23538        }
23539    }
23540}
23541
23542impl Deref for EditorSnapshot {
23543    type Target = DisplaySnapshot;
23544
23545    fn deref(&self) -> &Self::Target {
23546        &self.display_snapshot
23547    }
23548}
23549
23550#[derive(Clone, Debug, PartialEq, Eq)]
23551pub enum EditorEvent {
23552    InputIgnored {
23553        text: Arc<str>,
23554    },
23555    InputHandled {
23556        utf16_range_to_replace: Option<Range<isize>>,
23557        text: Arc<str>,
23558    },
23559    ExcerptsAdded {
23560        buffer: Entity<Buffer>,
23561        predecessor: ExcerptId,
23562        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23563    },
23564    ExcerptsRemoved {
23565        ids: Vec<ExcerptId>,
23566        removed_buffer_ids: Vec<BufferId>,
23567    },
23568    BufferFoldToggled {
23569        ids: Vec<ExcerptId>,
23570        folded: bool,
23571    },
23572    ExcerptsEdited {
23573        ids: Vec<ExcerptId>,
23574    },
23575    ExcerptsExpanded {
23576        ids: Vec<ExcerptId>,
23577    },
23578    BufferEdited,
23579    Edited {
23580        transaction_id: clock::Lamport,
23581    },
23582    Reparsed(BufferId),
23583    Focused,
23584    FocusedIn,
23585    Blurred,
23586    DirtyChanged,
23587    Saved,
23588    TitleChanged,
23589    SelectionsChanged {
23590        local: bool,
23591    },
23592    ScrollPositionChanged {
23593        local: bool,
23594        autoscroll: bool,
23595    },
23596    TransactionUndone {
23597        transaction_id: clock::Lamport,
23598    },
23599    TransactionBegun {
23600        transaction_id: clock::Lamport,
23601    },
23602    CursorShapeChanged,
23603    BreadcrumbsChanged,
23604    PushedToNavHistory {
23605        anchor: Anchor,
23606        is_deactivate: bool,
23607    },
23608}
23609
23610impl EventEmitter<EditorEvent> for Editor {}
23611
23612impl Focusable for Editor {
23613    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23614        self.focus_handle.clone()
23615    }
23616}
23617
23618impl Render for Editor {
23619    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23620        let settings = ThemeSettings::get_global(cx);
23621
23622        let mut text_style = match self.mode {
23623            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23624                color: cx.theme().colors().editor_foreground,
23625                font_family: settings.ui_font.family.clone(),
23626                font_features: settings.ui_font.features.clone(),
23627                font_fallbacks: settings.ui_font.fallbacks.clone(),
23628                font_size: rems(0.875).into(),
23629                font_weight: settings.ui_font.weight,
23630                line_height: relative(settings.buffer_line_height.value()),
23631                ..Default::default()
23632            },
23633            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23634                color: cx.theme().colors().editor_foreground,
23635                font_family: settings.buffer_font.family.clone(),
23636                font_features: settings.buffer_font.features.clone(),
23637                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23638                font_size: settings.buffer_font_size(cx).into(),
23639                font_weight: settings.buffer_font.weight,
23640                line_height: relative(settings.buffer_line_height.value()),
23641                ..Default::default()
23642            },
23643        };
23644        if let Some(text_style_refinement) = &self.text_style_refinement {
23645            text_style.refine(text_style_refinement)
23646        }
23647
23648        let background = match self.mode {
23649            EditorMode::SingleLine => cx.theme().system().transparent,
23650            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23651            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23652            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23653        };
23654
23655        EditorElement::new(
23656            &cx.entity(),
23657            EditorStyle {
23658                background,
23659                border: cx.theme().colors().border,
23660                local_player: cx.theme().players().local(),
23661                text: text_style,
23662                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23663                syntax: cx.theme().syntax().clone(),
23664                status: cx.theme().status().clone(),
23665                inlay_hints_style: make_inlay_hints_style(cx),
23666                edit_prediction_styles: make_suggestion_styles(cx),
23667                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23668                show_underlines: self.diagnostics_enabled(),
23669            },
23670        )
23671    }
23672}
23673
23674impl EntityInputHandler for Editor {
23675    fn text_for_range(
23676        &mut self,
23677        range_utf16: Range<usize>,
23678        adjusted_range: &mut Option<Range<usize>>,
23679        _: &mut Window,
23680        cx: &mut Context<Self>,
23681    ) -> Option<String> {
23682        let snapshot = self.buffer.read(cx).read(cx);
23683        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23684        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23685        if (start.0..end.0) != range_utf16 {
23686            adjusted_range.replace(start.0..end.0);
23687        }
23688        Some(snapshot.text_for_range(start..end).collect())
23689    }
23690
23691    fn selected_text_range(
23692        &mut self,
23693        ignore_disabled_input: bool,
23694        _: &mut Window,
23695        cx: &mut Context<Self>,
23696    ) -> Option<UTF16Selection> {
23697        // Prevent the IME menu from appearing when holding down an alphabetic key
23698        // while input is disabled.
23699        if !ignore_disabled_input && !self.input_enabled {
23700            return None;
23701        }
23702
23703        let selection = self
23704            .selections
23705            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
23706        let range = selection.range();
23707
23708        Some(UTF16Selection {
23709            range: range.start.0..range.end.0,
23710            reversed: selection.reversed,
23711        })
23712    }
23713
23714    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23715        let snapshot = self.buffer.read(cx).read(cx);
23716        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23717        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23718    }
23719
23720    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23721        self.clear_highlights::<InputComposition>(cx);
23722        self.ime_transaction.take();
23723    }
23724
23725    fn replace_text_in_range(
23726        &mut self,
23727        range_utf16: Option<Range<usize>>,
23728        text: &str,
23729        window: &mut Window,
23730        cx: &mut Context<Self>,
23731    ) {
23732        if !self.input_enabled {
23733            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23734            return;
23735        }
23736
23737        self.transact(window, cx, |this, window, cx| {
23738            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23739                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23740                Some(this.selection_replacement_ranges(range_utf16, cx))
23741            } else {
23742                this.marked_text_ranges(cx)
23743            };
23744
23745            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23746                let newest_selection_id = this.selections.newest_anchor().id;
23747                this.selections
23748                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23749                    .iter()
23750                    .zip(ranges_to_replace.iter())
23751                    .find_map(|(selection, range)| {
23752                        if selection.id == newest_selection_id {
23753                            Some(
23754                                (range.start.0 as isize - selection.head().0 as isize)
23755                                    ..(range.end.0 as isize - selection.head().0 as isize),
23756                            )
23757                        } else {
23758                            None
23759                        }
23760                    })
23761            });
23762
23763            cx.emit(EditorEvent::InputHandled {
23764                utf16_range_to_replace: range_to_replace,
23765                text: text.into(),
23766            });
23767
23768            if let Some(new_selected_ranges) = new_selected_ranges {
23769                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23770                    selections.select_ranges(new_selected_ranges)
23771                });
23772                this.backspace(&Default::default(), window, cx);
23773            }
23774
23775            this.handle_input(text, window, cx);
23776        });
23777
23778        if let Some(transaction) = self.ime_transaction {
23779            self.buffer.update(cx, |buffer, cx| {
23780                buffer.group_until_transaction(transaction, cx);
23781            });
23782        }
23783
23784        self.unmark_text(window, cx);
23785    }
23786
23787    fn replace_and_mark_text_in_range(
23788        &mut self,
23789        range_utf16: Option<Range<usize>>,
23790        text: &str,
23791        new_selected_range_utf16: Option<Range<usize>>,
23792        window: &mut Window,
23793        cx: &mut Context<Self>,
23794    ) {
23795        if !self.input_enabled {
23796            return;
23797        }
23798
23799        let transaction = self.transact(window, cx, |this, window, cx| {
23800            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23801                let snapshot = this.buffer.read(cx).read(cx);
23802                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23803                    for marked_range in &mut marked_ranges {
23804                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23805                        marked_range.start.0 += relative_range_utf16.start;
23806                        marked_range.start =
23807                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23808                        marked_range.end =
23809                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23810                    }
23811                }
23812                Some(marked_ranges)
23813            } else if let Some(range_utf16) = range_utf16 {
23814                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23815                Some(this.selection_replacement_ranges(range_utf16, cx))
23816            } else {
23817                None
23818            };
23819
23820            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23821                let newest_selection_id = this.selections.newest_anchor().id;
23822                this.selections
23823                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23824                    .iter()
23825                    .zip(ranges_to_replace.iter())
23826                    .find_map(|(selection, range)| {
23827                        if selection.id == newest_selection_id {
23828                            Some(
23829                                (range.start.0 as isize - selection.head().0 as isize)
23830                                    ..(range.end.0 as isize - selection.head().0 as isize),
23831                            )
23832                        } else {
23833                            None
23834                        }
23835                    })
23836            });
23837
23838            cx.emit(EditorEvent::InputHandled {
23839                utf16_range_to_replace: range_to_replace,
23840                text: text.into(),
23841            });
23842
23843            if let Some(ranges) = ranges_to_replace {
23844                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23845                    s.select_ranges(ranges)
23846                });
23847            }
23848
23849            let marked_ranges = {
23850                let snapshot = this.buffer.read(cx).read(cx);
23851                this.selections
23852                    .disjoint_anchors_arc()
23853                    .iter()
23854                    .map(|selection| {
23855                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23856                    })
23857                    .collect::<Vec<_>>()
23858            };
23859
23860            if text.is_empty() {
23861                this.unmark_text(window, cx);
23862            } else {
23863                this.highlight_text::<InputComposition>(
23864                    marked_ranges.clone(),
23865                    HighlightStyle {
23866                        underline: Some(UnderlineStyle {
23867                            thickness: px(1.),
23868                            color: None,
23869                            wavy: false,
23870                        }),
23871                        ..Default::default()
23872                    },
23873                    cx,
23874                );
23875            }
23876
23877            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23878            let use_autoclose = this.use_autoclose;
23879            let use_auto_surround = this.use_auto_surround;
23880            this.set_use_autoclose(false);
23881            this.set_use_auto_surround(false);
23882            this.handle_input(text, window, cx);
23883            this.set_use_autoclose(use_autoclose);
23884            this.set_use_auto_surround(use_auto_surround);
23885
23886            if let Some(new_selected_range) = new_selected_range_utf16 {
23887                let snapshot = this.buffer.read(cx).read(cx);
23888                let new_selected_ranges = marked_ranges
23889                    .into_iter()
23890                    .map(|marked_range| {
23891                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23892                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23893                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23894                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23895                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23896                    })
23897                    .collect::<Vec<_>>();
23898
23899                drop(snapshot);
23900                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23901                    selections.select_ranges(new_selected_ranges)
23902                });
23903            }
23904        });
23905
23906        self.ime_transaction = self.ime_transaction.or(transaction);
23907        if let Some(transaction) = self.ime_transaction {
23908            self.buffer.update(cx, |buffer, cx| {
23909                buffer.group_until_transaction(transaction, cx);
23910            });
23911        }
23912
23913        if self.text_highlights::<InputComposition>(cx).is_none() {
23914            self.ime_transaction.take();
23915        }
23916    }
23917
23918    fn bounds_for_range(
23919        &mut self,
23920        range_utf16: Range<usize>,
23921        element_bounds: gpui::Bounds<Pixels>,
23922        window: &mut Window,
23923        cx: &mut Context<Self>,
23924    ) -> Option<gpui::Bounds<Pixels>> {
23925        let text_layout_details = self.text_layout_details(window);
23926        let CharacterDimensions {
23927            em_width,
23928            em_advance,
23929            line_height,
23930        } = self.character_dimensions(window);
23931
23932        let snapshot = self.snapshot(window, cx);
23933        let scroll_position = snapshot.scroll_position();
23934        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
23935
23936        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23937        let x = Pixels::from(
23938            ScrollOffset::from(
23939                snapshot.x_for_display_point(start, &text_layout_details)
23940                    + self.gutter_dimensions.full_width(),
23941            ) - scroll_left,
23942        );
23943        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
23944
23945        Some(Bounds {
23946            origin: element_bounds.origin + point(x, y),
23947            size: size(em_width, line_height),
23948        })
23949    }
23950
23951    fn character_index_for_point(
23952        &mut self,
23953        point: gpui::Point<Pixels>,
23954        _window: &mut Window,
23955        _cx: &mut Context<Self>,
23956    ) -> Option<usize> {
23957        let position_map = self.last_position_map.as_ref()?;
23958        if !position_map.text_hitbox.contains(&point) {
23959            return None;
23960        }
23961        let display_point = position_map.point_for_position(point).previous_valid;
23962        let anchor = position_map
23963            .snapshot
23964            .display_point_to_anchor(display_point, Bias::Left);
23965        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
23966        Some(utf16_offset.0)
23967    }
23968}
23969
23970trait SelectionExt {
23971    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23972    fn spanned_rows(
23973        &self,
23974        include_end_if_at_line_start: bool,
23975        map: &DisplaySnapshot,
23976    ) -> Range<MultiBufferRow>;
23977}
23978
23979impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23980    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23981        let start = self
23982            .start
23983            .to_point(map.buffer_snapshot())
23984            .to_display_point(map);
23985        let end = self
23986            .end
23987            .to_point(map.buffer_snapshot())
23988            .to_display_point(map);
23989        if self.reversed {
23990            end..start
23991        } else {
23992            start..end
23993        }
23994    }
23995
23996    fn spanned_rows(
23997        &self,
23998        include_end_if_at_line_start: bool,
23999        map: &DisplaySnapshot,
24000    ) -> Range<MultiBufferRow> {
24001        let start = self.start.to_point(map.buffer_snapshot());
24002        let mut end = self.end.to_point(map.buffer_snapshot());
24003        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24004            end.row -= 1;
24005        }
24006
24007        let buffer_start = map.prev_line_boundary(start).0;
24008        let buffer_end = map.next_line_boundary(end).0;
24009        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24010    }
24011}
24012
24013impl<T: InvalidationRegion> InvalidationStack<T> {
24014    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24015    where
24016        S: Clone + ToOffset,
24017    {
24018        while let Some(region) = self.last() {
24019            let all_selections_inside_invalidation_ranges =
24020                if selections.len() == region.ranges().len() {
24021                    selections
24022                        .iter()
24023                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24024                        .all(|(selection, invalidation_range)| {
24025                            let head = selection.head().to_offset(buffer);
24026                            invalidation_range.start <= head && invalidation_range.end >= head
24027                        })
24028                } else {
24029                    false
24030                };
24031
24032            if all_selections_inside_invalidation_ranges {
24033                break;
24034            } else {
24035                self.pop();
24036            }
24037        }
24038    }
24039}
24040
24041impl<T> Default for InvalidationStack<T> {
24042    fn default() -> Self {
24043        Self(Default::default())
24044    }
24045}
24046
24047impl<T> Deref for InvalidationStack<T> {
24048    type Target = Vec<T>;
24049
24050    fn deref(&self) -> &Self::Target {
24051        &self.0
24052    }
24053}
24054
24055impl<T> DerefMut for InvalidationStack<T> {
24056    fn deref_mut(&mut self) -> &mut Self::Target {
24057        &mut self.0
24058    }
24059}
24060
24061impl InvalidationRegion for SnippetState {
24062    fn ranges(&self) -> &[Range<Anchor>] {
24063        &self.ranges[self.active_index]
24064    }
24065}
24066
24067fn edit_prediction_edit_text(
24068    current_snapshot: &BufferSnapshot,
24069    edits: &[(Range<Anchor>, String)],
24070    edit_preview: &EditPreview,
24071    include_deletions: bool,
24072    cx: &App,
24073) -> HighlightedText {
24074    let edits = edits
24075        .iter()
24076        .map(|(anchor, text)| {
24077            (
24078                anchor.start.text_anchor..anchor.end.text_anchor,
24079                text.clone(),
24080            )
24081        })
24082        .collect::<Vec<_>>();
24083
24084    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24085}
24086
24087fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24088    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24089    // Just show the raw edit text with basic styling
24090    let mut text = String::new();
24091    let mut highlights = Vec::new();
24092
24093    let insertion_highlight_style = HighlightStyle {
24094        color: Some(cx.theme().colors().text),
24095        ..Default::default()
24096    };
24097
24098    for (_, edit_text) in edits {
24099        let start_offset = text.len();
24100        text.push_str(edit_text);
24101        let end_offset = text.len();
24102
24103        if start_offset < end_offset {
24104            highlights.push((start_offset..end_offset, insertion_highlight_style));
24105        }
24106    }
24107
24108    HighlightedText {
24109        text: text.into(),
24110        highlights,
24111    }
24112}
24113
24114pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24115    match severity {
24116        lsp::DiagnosticSeverity::ERROR => colors.error,
24117        lsp::DiagnosticSeverity::WARNING => colors.warning,
24118        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24119        lsp::DiagnosticSeverity::HINT => colors.info,
24120        _ => colors.ignored,
24121    }
24122}
24123
24124pub fn styled_runs_for_code_label<'a>(
24125    label: &'a CodeLabel,
24126    syntax_theme: &'a theme::SyntaxTheme,
24127) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24128    let fade_out = HighlightStyle {
24129        fade_out: Some(0.35),
24130        ..Default::default()
24131    };
24132
24133    let mut prev_end = label.filter_range.end;
24134    label
24135        .runs
24136        .iter()
24137        .enumerate()
24138        .flat_map(move |(ix, (range, highlight_id))| {
24139            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24140                style
24141            } else {
24142                return Default::default();
24143            };
24144            let muted_style = style.highlight(fade_out);
24145
24146            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24147            if range.start >= label.filter_range.end {
24148                if range.start > prev_end {
24149                    runs.push((prev_end..range.start, fade_out));
24150                }
24151                runs.push((range.clone(), muted_style));
24152            } else if range.end <= label.filter_range.end {
24153                runs.push((range.clone(), style));
24154            } else {
24155                runs.push((range.start..label.filter_range.end, style));
24156                runs.push((label.filter_range.end..range.end, muted_style));
24157            }
24158            prev_end = cmp::max(prev_end, range.end);
24159
24160            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24161                runs.push((prev_end..label.text.len(), fade_out));
24162            }
24163
24164            runs
24165        })
24166}
24167
24168pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24169    let mut prev_index = 0;
24170    let mut prev_codepoint: Option<char> = None;
24171    text.char_indices()
24172        .chain([(text.len(), '\0')])
24173        .filter_map(move |(index, codepoint)| {
24174            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24175            let is_boundary = index == text.len()
24176                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24177                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24178            if is_boundary {
24179                let chunk = &text[prev_index..index];
24180                prev_index = index;
24181                Some(chunk)
24182            } else {
24183                None
24184            }
24185        })
24186}
24187
24188pub trait RangeToAnchorExt: Sized {
24189    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24190
24191    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24192        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24193        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24194    }
24195}
24196
24197impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24198    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24199        let start_offset = self.start.to_offset(snapshot);
24200        let end_offset = self.end.to_offset(snapshot);
24201        if start_offset == end_offset {
24202            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24203        } else {
24204            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24205        }
24206    }
24207}
24208
24209pub trait RowExt {
24210    fn as_f64(&self) -> f64;
24211
24212    fn next_row(&self) -> Self;
24213
24214    fn previous_row(&self) -> Self;
24215
24216    fn minus(&self, other: Self) -> u32;
24217}
24218
24219impl RowExt for DisplayRow {
24220    fn as_f64(&self) -> f64 {
24221        self.0 as _
24222    }
24223
24224    fn next_row(&self) -> Self {
24225        Self(self.0 + 1)
24226    }
24227
24228    fn previous_row(&self) -> Self {
24229        Self(self.0.saturating_sub(1))
24230    }
24231
24232    fn minus(&self, other: Self) -> u32 {
24233        self.0 - other.0
24234    }
24235}
24236
24237impl RowExt for MultiBufferRow {
24238    fn as_f64(&self) -> f64 {
24239        self.0 as _
24240    }
24241
24242    fn next_row(&self) -> Self {
24243        Self(self.0 + 1)
24244    }
24245
24246    fn previous_row(&self) -> Self {
24247        Self(self.0.saturating_sub(1))
24248    }
24249
24250    fn minus(&self, other: Self) -> u32 {
24251        self.0 - other.0
24252    }
24253}
24254
24255trait RowRangeExt {
24256    type Row;
24257
24258    fn len(&self) -> usize;
24259
24260    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24261}
24262
24263impl RowRangeExt for Range<MultiBufferRow> {
24264    type Row = MultiBufferRow;
24265
24266    fn len(&self) -> usize {
24267        (self.end.0 - self.start.0) as usize
24268    }
24269
24270    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24271        (self.start.0..self.end.0).map(MultiBufferRow)
24272    }
24273}
24274
24275impl RowRangeExt for Range<DisplayRow> {
24276    type Row = DisplayRow;
24277
24278    fn len(&self) -> usize {
24279        (self.end.0 - self.start.0) as usize
24280    }
24281
24282    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24283        (self.start.0..self.end.0).map(DisplayRow)
24284    }
24285}
24286
24287/// If select range has more than one line, we
24288/// just point the cursor to range.start.
24289fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24290    if range.start.row == range.end.row {
24291        range
24292    } else {
24293        range.start..range.start
24294    }
24295}
24296pub struct KillRing(ClipboardItem);
24297impl Global for KillRing {}
24298
24299const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24300
24301enum BreakpointPromptEditAction {
24302    Log,
24303    Condition,
24304    HitCondition,
24305}
24306
24307struct BreakpointPromptEditor {
24308    pub(crate) prompt: Entity<Editor>,
24309    editor: WeakEntity<Editor>,
24310    breakpoint_anchor: Anchor,
24311    breakpoint: Breakpoint,
24312    edit_action: BreakpointPromptEditAction,
24313    block_ids: HashSet<CustomBlockId>,
24314    editor_margins: Arc<Mutex<EditorMargins>>,
24315    _subscriptions: Vec<Subscription>,
24316}
24317
24318impl BreakpointPromptEditor {
24319    const MAX_LINES: u8 = 4;
24320
24321    fn new(
24322        editor: WeakEntity<Editor>,
24323        breakpoint_anchor: Anchor,
24324        breakpoint: Breakpoint,
24325        edit_action: BreakpointPromptEditAction,
24326        window: &mut Window,
24327        cx: &mut Context<Self>,
24328    ) -> Self {
24329        let base_text = match edit_action {
24330            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24331            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24332            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24333        }
24334        .map(|msg| msg.to_string())
24335        .unwrap_or_default();
24336
24337        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24338        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24339
24340        let prompt = cx.new(|cx| {
24341            let mut prompt = Editor::new(
24342                EditorMode::AutoHeight {
24343                    min_lines: 1,
24344                    max_lines: Some(Self::MAX_LINES as usize),
24345                },
24346                buffer,
24347                None,
24348                window,
24349                cx,
24350            );
24351            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24352            prompt.set_show_cursor_when_unfocused(false, cx);
24353            prompt.set_placeholder_text(
24354                match edit_action {
24355                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24356                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24357                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24358                },
24359                window,
24360                cx,
24361            );
24362
24363            prompt
24364        });
24365
24366        Self {
24367            prompt,
24368            editor,
24369            breakpoint_anchor,
24370            breakpoint,
24371            edit_action,
24372            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24373            block_ids: Default::default(),
24374            _subscriptions: vec![],
24375        }
24376    }
24377
24378    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24379        self.block_ids.extend(block_ids)
24380    }
24381
24382    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24383        if let Some(editor) = self.editor.upgrade() {
24384            let message = self
24385                .prompt
24386                .read(cx)
24387                .buffer
24388                .read(cx)
24389                .as_singleton()
24390                .expect("A multi buffer in breakpoint prompt isn't possible")
24391                .read(cx)
24392                .as_rope()
24393                .to_string();
24394
24395            editor.update(cx, |editor, cx| {
24396                editor.edit_breakpoint_at_anchor(
24397                    self.breakpoint_anchor,
24398                    self.breakpoint.clone(),
24399                    match self.edit_action {
24400                        BreakpointPromptEditAction::Log => {
24401                            BreakpointEditAction::EditLogMessage(message.into())
24402                        }
24403                        BreakpointPromptEditAction::Condition => {
24404                            BreakpointEditAction::EditCondition(message.into())
24405                        }
24406                        BreakpointPromptEditAction::HitCondition => {
24407                            BreakpointEditAction::EditHitCondition(message.into())
24408                        }
24409                    },
24410                    cx,
24411                );
24412
24413                editor.remove_blocks(self.block_ids.clone(), None, cx);
24414                cx.focus_self(window);
24415            });
24416        }
24417    }
24418
24419    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24420        self.editor
24421            .update(cx, |editor, cx| {
24422                editor.remove_blocks(self.block_ids.clone(), None, cx);
24423                window.focus(&editor.focus_handle);
24424            })
24425            .log_err();
24426    }
24427
24428    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24429        let settings = ThemeSettings::get_global(cx);
24430        let text_style = TextStyle {
24431            color: if self.prompt.read(cx).read_only(cx) {
24432                cx.theme().colors().text_disabled
24433            } else {
24434                cx.theme().colors().text
24435            },
24436            font_family: settings.buffer_font.family.clone(),
24437            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24438            font_size: settings.buffer_font_size(cx).into(),
24439            font_weight: settings.buffer_font.weight,
24440            line_height: relative(settings.buffer_line_height.value()),
24441            ..Default::default()
24442        };
24443        EditorElement::new(
24444            &self.prompt,
24445            EditorStyle {
24446                background: cx.theme().colors().editor_background,
24447                local_player: cx.theme().players().local(),
24448                text: text_style,
24449                ..Default::default()
24450            },
24451        )
24452    }
24453}
24454
24455impl Render for BreakpointPromptEditor {
24456    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24457        let editor_margins = *self.editor_margins.lock();
24458        let gutter_dimensions = editor_margins.gutter;
24459        h_flex()
24460            .key_context("Editor")
24461            .bg(cx.theme().colors().editor_background)
24462            .border_y_1()
24463            .border_color(cx.theme().status().info_border)
24464            .size_full()
24465            .py(window.line_height() / 2.5)
24466            .on_action(cx.listener(Self::confirm))
24467            .on_action(cx.listener(Self::cancel))
24468            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24469            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24470    }
24471}
24472
24473impl Focusable for BreakpointPromptEditor {
24474    fn focus_handle(&self, cx: &App) -> FocusHandle {
24475        self.prompt.focus_handle(cx)
24476    }
24477}
24478
24479fn all_edits_insertions_or_deletions(
24480    edits: &Vec<(Range<Anchor>, String)>,
24481    snapshot: &MultiBufferSnapshot,
24482) -> bool {
24483    let mut all_insertions = true;
24484    let mut all_deletions = true;
24485
24486    for (range, new_text) in edits.iter() {
24487        let range_is_empty = range.to_offset(snapshot).is_empty();
24488        let text_is_empty = new_text.is_empty();
24489
24490        if range_is_empty != text_is_empty {
24491            if range_is_empty {
24492                all_deletions = false;
24493            } else {
24494                all_insertions = false;
24495            }
24496        } else {
24497            return false;
24498        }
24499
24500        if !all_insertions && !all_deletions {
24501            return false;
24502        }
24503    }
24504    all_insertions || all_deletions
24505}
24506
24507struct MissingEditPredictionKeybindingTooltip;
24508
24509impl Render for MissingEditPredictionKeybindingTooltip {
24510    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24511        ui::tooltip_container(cx, |container, cx| {
24512            container
24513                .flex_shrink_0()
24514                .max_w_80()
24515                .min_h(rems_from_px(124.))
24516                .justify_between()
24517                .child(
24518                    v_flex()
24519                        .flex_1()
24520                        .text_ui_sm(cx)
24521                        .child(Label::new("Conflict with Accept Keybinding"))
24522                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24523                )
24524                .child(
24525                    h_flex()
24526                        .pb_1()
24527                        .gap_1()
24528                        .items_end()
24529                        .w_full()
24530                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24531                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24532                        }))
24533                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24534                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24535                        })),
24536                )
24537        })
24538    }
24539}
24540
24541#[derive(Debug, Clone, Copy, PartialEq)]
24542pub struct LineHighlight {
24543    pub background: Background,
24544    pub border: Option<gpui::Hsla>,
24545    pub include_gutter: bool,
24546    pub type_id: Option<TypeId>,
24547}
24548
24549struct LineManipulationResult {
24550    pub new_text: String,
24551    pub line_count_before: usize,
24552    pub line_count_after: usize,
24553}
24554
24555fn render_diff_hunk_controls(
24556    row: u32,
24557    status: &DiffHunkStatus,
24558    hunk_range: Range<Anchor>,
24559    is_created_file: bool,
24560    line_height: Pixels,
24561    editor: &Entity<Editor>,
24562    _window: &mut Window,
24563    cx: &mut App,
24564) -> AnyElement {
24565    h_flex()
24566        .h(line_height)
24567        .mr_1()
24568        .gap_1()
24569        .px_0p5()
24570        .pb_1()
24571        .border_x_1()
24572        .border_b_1()
24573        .border_color(cx.theme().colors().border_variant)
24574        .rounded_b_lg()
24575        .bg(cx.theme().colors().editor_background)
24576        .gap_1()
24577        .block_mouse_except_scroll()
24578        .shadow_md()
24579        .child(if status.has_secondary_hunk() {
24580            Button::new(("stage", row as u64), "Stage")
24581                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24582                .tooltip({
24583                    let focus_handle = editor.focus_handle(cx);
24584                    move |_window, cx| {
24585                        Tooltip::for_action_in(
24586                            "Stage Hunk",
24587                            &::git::ToggleStaged,
24588                            &focus_handle,
24589                            cx,
24590                        )
24591                    }
24592                })
24593                .on_click({
24594                    let editor = editor.clone();
24595                    move |_event, _window, cx| {
24596                        editor.update(cx, |editor, cx| {
24597                            editor.stage_or_unstage_diff_hunks(
24598                                true,
24599                                vec![hunk_range.start..hunk_range.start],
24600                                cx,
24601                            );
24602                        });
24603                    }
24604                })
24605        } else {
24606            Button::new(("unstage", row as u64), "Unstage")
24607                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24608                .tooltip({
24609                    let focus_handle = editor.focus_handle(cx);
24610                    move |_window, cx| {
24611                        Tooltip::for_action_in(
24612                            "Unstage Hunk",
24613                            &::git::ToggleStaged,
24614                            &focus_handle,
24615                            cx,
24616                        )
24617                    }
24618                })
24619                .on_click({
24620                    let editor = editor.clone();
24621                    move |_event, _window, cx| {
24622                        editor.update(cx, |editor, cx| {
24623                            editor.stage_or_unstage_diff_hunks(
24624                                false,
24625                                vec![hunk_range.start..hunk_range.start],
24626                                cx,
24627                            );
24628                        });
24629                    }
24630                })
24631        })
24632        .child(
24633            Button::new(("restore", row as u64), "Restore")
24634                .tooltip({
24635                    let focus_handle = editor.focus_handle(cx);
24636                    move |_window, cx| {
24637                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
24638                    }
24639                })
24640                .on_click({
24641                    let editor = editor.clone();
24642                    move |_event, window, cx| {
24643                        editor.update(cx, |editor, cx| {
24644                            let snapshot = editor.snapshot(window, cx);
24645                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24646                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24647                        });
24648                    }
24649                })
24650                .disabled(is_created_file),
24651        )
24652        .when(
24653            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24654            |el| {
24655                el.child(
24656                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24657                        .shape(IconButtonShape::Square)
24658                        .icon_size(IconSize::Small)
24659                        // .disabled(!has_multiple_hunks)
24660                        .tooltip({
24661                            let focus_handle = editor.focus_handle(cx);
24662                            move |_window, cx| {
24663                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
24664                            }
24665                        })
24666                        .on_click({
24667                            let editor = editor.clone();
24668                            move |_event, window, cx| {
24669                                editor.update(cx, |editor, cx| {
24670                                    let snapshot = editor.snapshot(window, cx);
24671                                    let position =
24672                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24673                                    editor.go_to_hunk_before_or_after_position(
24674                                        &snapshot,
24675                                        position,
24676                                        Direction::Next,
24677                                        window,
24678                                        cx,
24679                                    );
24680                                    editor.expand_selected_diff_hunks(cx);
24681                                });
24682                            }
24683                        }),
24684                )
24685                .child(
24686                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24687                        .shape(IconButtonShape::Square)
24688                        .icon_size(IconSize::Small)
24689                        // .disabled(!has_multiple_hunks)
24690                        .tooltip({
24691                            let focus_handle = editor.focus_handle(cx);
24692                            move |_window, cx| {
24693                                Tooltip::for_action_in(
24694                                    "Previous Hunk",
24695                                    &GoToPreviousHunk,
24696                                    &focus_handle,
24697                                    cx,
24698                                )
24699                            }
24700                        })
24701                        .on_click({
24702                            let editor = editor.clone();
24703                            move |_event, window, cx| {
24704                                editor.update(cx, |editor, cx| {
24705                                    let snapshot = editor.snapshot(window, cx);
24706                                    let point =
24707                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24708                                    editor.go_to_hunk_before_or_after_position(
24709                                        &snapshot,
24710                                        point,
24711                                        Direction::Prev,
24712                                        window,
24713                                        cx,
24714                                    );
24715                                    editor.expand_selected_diff_hunks(cx);
24716                                });
24717                            }
24718                        }),
24719                )
24720            },
24721        )
24722        .into_any_element()
24723}
24724
24725pub fn multibuffer_context_lines(cx: &App) -> u32 {
24726    EditorSettings::try_get(cx)
24727        .map(|settings| settings.excerpt_context_lines)
24728        .unwrap_or(2)
24729        .min(32)
24730}