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//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlay_hint_cache;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod edit_prediction_tests;
   46#[cfg(test)]
   47mod editor_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   54pub use edit_prediction::Direction;
   55pub use editor_settings::{
   56    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   57    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61};
   62pub use git::blame::BlameRenderer;
   63pub use hover_popover::hover_markdown_style;
   64pub use items::MAX_TAB_TITLE_LEN;
   65pub use lsp::CompletionContext;
   66pub use lsp_ext::lsp_tasks;
   67pub use multi_buffer::{
   68    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   69    RowInfo, ToOffset, ToPoint,
   70};
   71pub use proposed_changes_editor::{
   72    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   73};
   74pub use text::Bias;
   75
   76use ::git::{
   77    Restore,
   78    blame::{BlameEntry, ParsedCommitMessage},
   79};
   80use aho_corasick::AhoCorasick;
   81use anyhow::{Context as _, Result, anyhow};
   82use blink_manager::BlinkManager;
   83use buffer_diff::DiffHunkStatus;
   84use client::{Collaborator, ParticipantIndex, parse_zed_link};
   85use clock::{AGENT_REPLICA_ID, ReplicaId};
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   91use convert_case::{Case, Casing};
   92use dap::TelemetrySpawnLocation;
   93use display_map::*;
   94use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   95use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   96use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   97use futures::{
   98    FutureExt, StreamExt as _,
   99    future::{self, Shared, join},
  100    stream::FuturesUnordered,
  101};
  102use fuzzy::{StringMatch, StringMatchCandidate};
  103use git::blame::{GitBlame, GlobalBlameRenderer};
  104use gpui::{
  105    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  106    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  107    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  108    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  109    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  110    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  111    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  112    div, point, prelude::*, pulsating_between, px, relative, size,
  113};
  114use highlight_matching_bracket::refresh_matching_bracket_highlights;
  115use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  116use hover_popover::{HoverState, hide_hover};
  117use indent_guides::ActiveIndentGuidesState;
  118use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  119use itertools::{Either, Itertools};
  120use language::{
  121    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  122    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  123    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  124    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  125    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  126    language_settings::{
  127        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  128        all_language_settings, language_settings,
  129    },
  130    point_from_lsp, point_to_lsp, text_diff_with_options,
  131};
  132use linked_editing_ranges::refresh_linked_ranges;
  133use lsp::{
  134    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  135    LanguageServerId,
  136};
  137use lsp_colors::LspColorData;
  138use markdown::Markdown;
  139use mouse_context_menu::MouseContextMenu;
  140use movement::TextLayoutDetails;
  141use multi_buffer::{
  142    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  143    ToOffsetUtf16,
  144};
  145use parking_lot::Mutex;
  146use persistence::DB;
  147use project::{
  148    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  149    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  150    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  151    ProjectTransaction, TaskSourceKind,
  152    debugger::{
  153        breakpoint_store::{
  154            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  155            BreakpointStore, BreakpointStoreEvent,
  156        },
  157        session::{Session, SessionEvent},
  158    },
  159    git_store::{GitStoreEvent, RepositoryEvent},
  160    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  161    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  162};
  163use rand::seq::SliceRandom;
  164use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  165use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  166use selections_collection::{
  167    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  168};
  169use serde::{Deserialize, Serialize};
  170use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  171use smallvec::{SmallVec, smallvec};
  172use snippet::Snippet;
  173use std::{
  174    any::{Any, TypeId},
  175    borrow::Cow,
  176    cell::{OnceCell, RefCell},
  177    cmp::{self, Ordering, Reverse},
  178    iter::{self, Peekable},
  179    mem,
  180    num::NonZeroU32,
  181    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  182    path::{Path, PathBuf},
  183    rc::Rc,
  184    sync::Arc,
  185    time::{Duration, Instant},
  186};
  187use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  188use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  189use theme::{
  190    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  191    observe_buffer_font_size_adjustment,
  192};
  193use ui::{
  194    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  195    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  196};
  197use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  198use workspace::{
  199    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  200    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  201    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  202    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  203    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  204    searchable::SearchEvent,
  205};
  206
  207use crate::{
  208    code_context_menus::CompletionsMenuSource,
  209    editor_settings::MultiCursorModifier,
  210    hover_links::{find_url, find_url_from_range},
  211    scroll::{ScrollOffset, ScrollPixelOffset},
  212    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  213};
  214
  215pub const FILE_HEADER_HEIGHT: u32 = 2;
  216pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  217const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  218const MAX_LINE_LEN: usize = 1024;
  219const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  220const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  221pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  222#[doc(hidden)]
  223pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  224pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  225
  226pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  227pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  229pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  230
  231pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  232pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  233pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  234
  235pub type RenderDiffHunkControlsFn = Arc<
  236    dyn Fn(
  237        u32,
  238        &DiffHunkStatus,
  239        Range<Anchor>,
  240        bool,
  241        Pixels,
  242        &Entity<Editor>,
  243        &mut Window,
  244        &mut App,
  245    ) -> AnyElement,
  246>;
  247
  248enum ReportEditorEvent {
  249    Saved { auto_saved: bool },
  250    EditorOpened,
  251    Closed,
  252}
  253
  254impl ReportEditorEvent {
  255    pub fn event_type(&self) -> &'static str {
  256        match self {
  257            Self::Saved { .. } => "Editor Saved",
  258            Self::EditorOpened => "Editor Opened",
  259            Self::Closed => "Editor Closed",
  260        }
  261    }
  262}
  263
  264struct InlineValueCache {
  265    enabled: bool,
  266    inlays: Vec<InlayId>,
  267    refresh_task: Task<Option<()>>,
  268}
  269
  270impl InlineValueCache {
  271    fn new(enabled: bool) -> Self {
  272        Self {
  273            enabled,
  274            inlays: Vec::new(),
  275            refresh_task: Task::ready(None),
  276        }
  277    }
  278}
  279
  280#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  281pub enum InlayId {
  282    EditPrediction(u32),
  283    DebuggerValue(u32),
  284    // LSP
  285    Hint(u32),
  286    Color(u32),
  287}
  288
  289impl InlayId {
  290    fn id(&self) -> u32 {
  291        match self {
  292            Self::EditPrediction(id) => *id,
  293            Self::DebuggerValue(id) => *id,
  294            Self::Hint(id) => *id,
  295            Self::Color(id) => *id,
  296        }
  297    }
  298}
  299
  300pub enum ActiveDebugLine {}
  301pub enum DebugStackFrameLine {}
  302enum DocumentHighlightRead {}
  303enum DocumentHighlightWrite {}
  304enum InputComposition {}
  305pub enum PendingInput {}
  306enum SelectedTextHighlight {}
  307
  308pub enum ConflictsOuter {}
  309pub enum ConflictsOurs {}
  310pub enum ConflictsTheirs {}
  311pub enum ConflictsOursMarker {}
  312pub enum ConflictsTheirsMarker {}
  313
  314#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  315pub enum Navigated {
  316    Yes,
  317    No,
  318}
  319
  320impl Navigated {
  321    pub fn from_bool(yes: bool) -> Navigated {
  322        if yes { Navigated::Yes } else { Navigated::No }
  323    }
  324}
  325
  326#[derive(Debug, Clone, PartialEq, Eq)]
  327enum DisplayDiffHunk {
  328    Folded {
  329        display_row: DisplayRow,
  330    },
  331    Unfolded {
  332        is_created_file: bool,
  333        diff_base_byte_range: Range<usize>,
  334        display_row_range: Range<DisplayRow>,
  335        multi_buffer_range: Range<Anchor>,
  336        status: DiffHunkStatus,
  337    },
  338}
  339
  340pub enum HideMouseCursorOrigin {
  341    TypingAction,
  342    MovementAction,
  343}
  344
  345pub fn init_settings(cx: &mut App) {
  346    EditorSettings::register(cx);
  347}
  348
  349pub fn init(cx: &mut App) {
  350    init_settings(cx);
  351
  352    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  353
  354    workspace::register_project_item::<Editor>(cx);
  355    workspace::FollowableViewRegistry::register::<Editor>(cx);
  356    workspace::register_serializable_item::<Editor>(cx);
  357
  358    cx.observe_new(
  359        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  360            workspace.register_action(Editor::new_file);
  361            workspace.register_action(Editor::new_file_vertical);
  362            workspace.register_action(Editor::new_file_horizontal);
  363            workspace.register_action(Editor::cancel_language_server_work);
  364            workspace.register_action(Editor::toggle_focus);
  365        },
  366    )
  367    .detach();
  368
  369    cx.on_action(move |_: &workspace::NewFile, cx| {
  370        let app_state = workspace::AppState::global(cx);
  371        if let Some(app_state) = app_state.upgrade() {
  372            workspace::open_new(
  373                Default::default(),
  374                app_state,
  375                cx,
  376                |workspace, window, cx| {
  377                    Editor::new_file(workspace, &Default::default(), window, cx)
  378                },
  379            )
  380            .detach();
  381        }
  382    });
  383    cx.on_action(move |_: &workspace::NewWindow, cx| {
  384        let app_state = workspace::AppState::global(cx);
  385        if let Some(app_state) = app_state.upgrade() {
  386            workspace::open_new(
  387                Default::default(),
  388                app_state,
  389                cx,
  390                |workspace, window, cx| {
  391                    cx.activate(true);
  392                    Editor::new_file(workspace, &Default::default(), window, cx)
  393                },
  394            )
  395            .detach();
  396        }
  397    });
  398}
  399
  400pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  401    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  402}
  403
  404pub trait DiagnosticRenderer {
  405    fn render_group(
  406        &self,
  407        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  408        buffer_id: BufferId,
  409        snapshot: EditorSnapshot,
  410        editor: WeakEntity<Editor>,
  411        cx: &mut App,
  412    ) -> Vec<BlockProperties<Anchor>>;
  413
  414    fn render_hover(
  415        &self,
  416        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  417        range: Range<Point>,
  418        buffer_id: BufferId,
  419        cx: &mut App,
  420    ) -> Option<Entity<markdown::Markdown>>;
  421
  422    fn open_link(
  423        &self,
  424        editor: &mut Editor,
  425        link: SharedString,
  426        window: &mut Window,
  427        cx: &mut Context<Editor>,
  428    );
  429}
  430
  431pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  432
  433impl GlobalDiagnosticRenderer {
  434    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  435        cx.try_global::<Self>().map(|g| g.0.clone())
  436    }
  437}
  438
  439impl gpui::Global for GlobalDiagnosticRenderer {}
  440pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  441    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  442}
  443
  444pub struct SearchWithinRange;
  445
  446trait InvalidationRegion {
  447    fn ranges(&self) -> &[Range<Anchor>];
  448}
  449
  450#[derive(Clone, Debug, PartialEq)]
  451pub enum SelectPhase {
  452    Begin {
  453        position: DisplayPoint,
  454        add: bool,
  455        click_count: usize,
  456    },
  457    BeginColumnar {
  458        position: DisplayPoint,
  459        reset: bool,
  460        mode: ColumnarMode,
  461        goal_column: u32,
  462    },
  463    Extend {
  464        position: DisplayPoint,
  465        click_count: usize,
  466    },
  467    Update {
  468        position: DisplayPoint,
  469        goal_column: u32,
  470        scroll_delta: gpui::Point<f32>,
  471    },
  472    End,
  473}
  474
  475#[derive(Clone, Debug, PartialEq)]
  476pub enum ColumnarMode {
  477    FromMouse,
  478    FromSelection,
  479}
  480
  481#[derive(Clone, Debug)]
  482pub enum SelectMode {
  483    Character,
  484    Word(Range<Anchor>),
  485    Line(Range<Anchor>),
  486    All,
  487}
  488
  489#[derive(Clone, PartialEq, Eq, Debug)]
  490pub enum EditorMode {
  491    SingleLine,
  492    AutoHeight {
  493        min_lines: usize,
  494        max_lines: Option<usize>,
  495    },
  496    Full {
  497        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  498        scale_ui_elements_with_buffer_font_size: bool,
  499        /// When set to `true`, the editor will render a background for the active line.
  500        show_active_line_background: bool,
  501        /// When set to `true`, the editor's height will be determined by its content.
  502        sized_by_content: bool,
  503    },
  504    Minimap {
  505        parent: WeakEntity<Editor>,
  506    },
  507}
  508
  509impl EditorMode {
  510    pub fn full() -> Self {
  511        Self::Full {
  512            scale_ui_elements_with_buffer_font_size: true,
  513            show_active_line_background: true,
  514            sized_by_content: false,
  515        }
  516    }
  517
  518    #[inline]
  519    pub fn is_full(&self) -> bool {
  520        matches!(self, Self::Full { .. })
  521    }
  522
  523    #[inline]
  524    pub fn is_single_line(&self) -> bool {
  525        matches!(self, Self::SingleLine { .. })
  526    }
  527
  528    #[inline]
  529    fn is_minimap(&self) -> bool {
  530        matches!(self, Self::Minimap { .. })
  531    }
  532}
  533
  534#[derive(Copy, Clone, Debug)]
  535pub enum SoftWrap {
  536    /// Prefer not to wrap at all.
  537    ///
  538    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  539    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  540    GitDiff,
  541    /// Prefer a single line generally, unless an overly long line is encountered.
  542    None,
  543    /// Soft wrap lines that exceed the editor width.
  544    EditorWidth,
  545    /// Soft wrap lines at the preferred line length.
  546    Column(u32),
  547    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  548    Bounded(u32),
  549}
  550
  551#[derive(Clone)]
  552pub struct EditorStyle {
  553    pub background: Hsla,
  554    pub border: Hsla,
  555    pub local_player: PlayerColor,
  556    pub text: TextStyle,
  557    pub scrollbar_width: Pixels,
  558    pub syntax: Arc<SyntaxTheme>,
  559    pub status: StatusColors,
  560    pub inlay_hints_style: HighlightStyle,
  561    pub edit_prediction_styles: EditPredictionStyles,
  562    pub unnecessary_code_fade: f32,
  563    pub show_underlines: bool,
  564}
  565
  566impl Default for EditorStyle {
  567    fn default() -> Self {
  568        Self {
  569            background: Hsla::default(),
  570            border: Hsla::default(),
  571            local_player: PlayerColor::default(),
  572            text: TextStyle::default(),
  573            scrollbar_width: Pixels::default(),
  574            syntax: Default::default(),
  575            // HACK: Status colors don't have a real default.
  576            // We should look into removing the status colors from the editor
  577            // style and retrieve them directly from the theme.
  578            status: StatusColors::dark(),
  579            inlay_hints_style: HighlightStyle::default(),
  580            edit_prediction_styles: EditPredictionStyles {
  581                insertion: HighlightStyle::default(),
  582                whitespace: HighlightStyle::default(),
  583            },
  584            unnecessary_code_fade: Default::default(),
  585            show_underlines: true,
  586        }
  587    }
  588}
  589
  590pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  591    let show_background = language_settings::language_settings(None, None, cx)
  592        .inlay_hints
  593        .show_background;
  594
  595    let mut style = cx.theme().syntax().get("hint");
  596
  597    if style.color.is_none() {
  598        style.color = Some(cx.theme().status().hint);
  599    }
  600
  601    if !show_background {
  602        style.background_color = None;
  603        return style;
  604    }
  605
  606    if style.background_color.is_none() {
  607        style.background_color = Some(cx.theme().status().hint_background);
  608    }
  609
  610    style
  611}
  612
  613pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  614    EditPredictionStyles {
  615        insertion: HighlightStyle {
  616            color: Some(cx.theme().status().predictive),
  617            ..HighlightStyle::default()
  618        },
  619        whitespace: HighlightStyle {
  620            background_color: Some(cx.theme().status().created_background),
  621            ..HighlightStyle::default()
  622        },
  623    }
  624}
  625
  626type CompletionId = usize;
  627
  628pub(crate) enum EditDisplayMode {
  629    TabAccept,
  630    DiffPopover,
  631    Inline,
  632}
  633
  634enum EditPrediction {
  635    Edit {
  636        edits: Vec<(Range<Anchor>, String)>,
  637        edit_preview: Option<EditPreview>,
  638        display_mode: EditDisplayMode,
  639        snapshot: BufferSnapshot,
  640    },
  641    /// Move to a specific location in the active editor
  642    MoveWithin {
  643        target: Anchor,
  644        snapshot: BufferSnapshot,
  645    },
  646    /// Move to a specific location in a different editor (not the active one)
  647    MoveOutside {
  648        target: language::Anchor,
  649        snapshot: BufferSnapshot,
  650    },
  651}
  652
  653struct EditPredictionState {
  654    inlay_ids: Vec<InlayId>,
  655    completion: EditPrediction,
  656    completion_id: Option<SharedString>,
  657    invalidation_range: Option<Range<Anchor>>,
  658}
  659
  660enum EditPredictionSettings {
  661    Disabled,
  662    Enabled {
  663        show_in_menu: bool,
  664        preview_requires_modifier: bool,
  665    },
  666}
  667
  668enum EditPredictionHighlight {}
  669
  670#[derive(Debug, Clone)]
  671struct InlineDiagnostic {
  672    message: SharedString,
  673    group_id: usize,
  674    is_primary: bool,
  675    start: Point,
  676    severity: lsp::DiagnosticSeverity,
  677}
  678
  679pub enum MenuEditPredictionsPolicy {
  680    Never,
  681    ByProvider,
  682}
  683
  684pub enum EditPredictionPreview {
  685    /// Modifier is not pressed
  686    Inactive { released_too_fast: bool },
  687    /// Modifier pressed
  688    Active {
  689        since: Instant,
  690        previous_scroll_position: Option<ScrollAnchor>,
  691    },
  692}
  693
  694impl EditPredictionPreview {
  695    pub fn released_too_fast(&self) -> bool {
  696        match self {
  697            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  698            EditPredictionPreview::Active { .. } => false,
  699        }
  700    }
  701
  702    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  703        if let EditPredictionPreview::Active {
  704            previous_scroll_position,
  705            ..
  706        } = self
  707        {
  708            *previous_scroll_position = scroll_position;
  709        }
  710    }
  711}
  712
  713pub struct ContextMenuOptions {
  714    pub min_entries_visible: usize,
  715    pub max_entries_visible: usize,
  716    pub placement: Option<ContextMenuPlacement>,
  717}
  718
  719#[derive(Debug, Clone, PartialEq, Eq)]
  720pub enum ContextMenuPlacement {
  721    Above,
  722    Below,
  723}
  724
  725#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  726struct EditorActionId(usize);
  727
  728impl EditorActionId {
  729    pub fn post_inc(&mut self) -> Self {
  730        let answer = self.0;
  731
  732        *self = Self(answer + 1);
  733
  734        Self(answer)
  735    }
  736}
  737
  738// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  739// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  740
  741type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  742type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  743
  744#[derive(Default)]
  745struct ScrollbarMarkerState {
  746    scrollbar_size: Size<Pixels>,
  747    dirty: bool,
  748    markers: Arc<[PaintQuad]>,
  749    pending_refresh: Option<Task<Result<()>>>,
  750}
  751
  752impl ScrollbarMarkerState {
  753    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  754        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  755    }
  756}
  757
  758#[derive(Clone, Copy, PartialEq, Eq)]
  759pub enum MinimapVisibility {
  760    Disabled,
  761    Enabled {
  762        /// The configuration currently present in the users settings.
  763        setting_configuration: bool,
  764        /// Whether to override the currently set visibility from the users setting.
  765        toggle_override: bool,
  766    },
  767}
  768
  769impl MinimapVisibility {
  770    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  771        if mode.is_full() {
  772            Self::Enabled {
  773                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  774                toggle_override: false,
  775            }
  776        } else {
  777            Self::Disabled
  778        }
  779    }
  780
  781    fn hidden(&self) -> Self {
  782        match *self {
  783            Self::Enabled {
  784                setting_configuration,
  785                ..
  786            } => Self::Enabled {
  787                setting_configuration,
  788                toggle_override: setting_configuration,
  789            },
  790            Self::Disabled => Self::Disabled,
  791        }
  792    }
  793
  794    fn disabled(&self) -> bool {
  795        matches!(*self, Self::Disabled)
  796    }
  797
  798    fn settings_visibility(&self) -> bool {
  799        match *self {
  800            Self::Enabled {
  801                setting_configuration,
  802                ..
  803            } => setting_configuration,
  804            _ => false,
  805        }
  806    }
  807
  808    fn visible(&self) -> bool {
  809        match *self {
  810            Self::Enabled {
  811                setting_configuration,
  812                toggle_override,
  813            } => setting_configuration ^ toggle_override,
  814            _ => false,
  815        }
  816    }
  817
  818    fn toggle_visibility(&self) -> Self {
  819        match *self {
  820            Self::Enabled {
  821                toggle_override,
  822                setting_configuration,
  823            } => Self::Enabled {
  824                setting_configuration,
  825                toggle_override: !toggle_override,
  826            },
  827            Self::Disabled => Self::Disabled,
  828        }
  829    }
  830}
  831
  832#[derive(Clone, Debug)]
  833struct RunnableTasks {
  834    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  835    offset: multi_buffer::Anchor,
  836    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  837    column: u32,
  838    // Values of all named captures, including those starting with '_'
  839    extra_variables: HashMap<String, String>,
  840    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  841    context_range: Range<BufferOffset>,
  842}
  843
  844impl RunnableTasks {
  845    fn resolve<'a>(
  846        &'a self,
  847        cx: &'a task::TaskContext,
  848    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  849        self.templates.iter().filter_map(|(kind, template)| {
  850            template
  851                .resolve_task(&kind.to_id_base(), cx)
  852                .map(|task| (kind.clone(), task))
  853        })
  854    }
  855}
  856
  857#[derive(Clone)]
  858pub struct ResolvedTasks {
  859    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  860    position: Anchor,
  861}
  862
  863#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  864struct BufferOffset(usize);
  865
  866/// Addons allow storing per-editor state in other crates (e.g. Vim)
  867pub trait Addon: 'static {
  868    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  869
  870    fn render_buffer_header_controls(
  871        &self,
  872        _: &ExcerptInfo,
  873        _: &Window,
  874        _: &App,
  875    ) -> Option<AnyElement> {
  876        None
  877    }
  878
  879    fn to_any(&self) -> &dyn std::any::Any;
  880
  881    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  882        None
  883    }
  884}
  885
  886struct ChangeLocation {
  887    current: Option<Vec<Anchor>>,
  888    original: Vec<Anchor>,
  889}
  890impl ChangeLocation {
  891    fn locations(&self) -> &[Anchor] {
  892        self.current.as_ref().unwrap_or(&self.original)
  893    }
  894}
  895
  896/// A set of caret positions, registered when the editor was edited.
  897pub struct ChangeList {
  898    changes: Vec<ChangeLocation>,
  899    /// Currently "selected" change.
  900    position: Option<usize>,
  901}
  902
  903impl ChangeList {
  904    pub fn new() -> Self {
  905        Self {
  906            changes: Vec::new(),
  907            position: None,
  908        }
  909    }
  910
  911    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  912    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  913    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  914        if self.changes.is_empty() {
  915            return None;
  916        }
  917
  918        let prev = self.position.unwrap_or(self.changes.len());
  919        let next = if direction == Direction::Prev {
  920            prev.saturating_sub(count)
  921        } else {
  922            (prev + count).min(self.changes.len() - 1)
  923        };
  924        self.position = Some(next);
  925        self.changes.get(next).map(|change| change.locations())
  926    }
  927
  928    /// Adds a new change to the list, resetting the change list position.
  929    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  930        self.position.take();
  931        if let Some(last) = self.changes.last_mut()
  932            && group
  933        {
  934            last.current = Some(new_positions)
  935        } else {
  936            self.changes.push(ChangeLocation {
  937                original: new_positions,
  938                current: None,
  939            });
  940        }
  941    }
  942
  943    pub fn last(&self) -> Option<&[Anchor]> {
  944        self.changes.last().map(|change| change.locations())
  945    }
  946
  947    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  948        self.changes.last().map(|change| change.original.as_slice())
  949    }
  950
  951    pub fn invert_last_group(&mut self) {
  952        if let Some(last) = self.changes.last_mut()
  953            && let Some(current) = last.current.as_mut()
  954        {
  955            mem::swap(&mut last.original, current);
  956        }
  957    }
  958}
  959
  960#[derive(Clone)]
  961struct InlineBlamePopoverState {
  962    scroll_handle: ScrollHandle,
  963    commit_message: Option<ParsedCommitMessage>,
  964    markdown: Entity<Markdown>,
  965}
  966
  967struct InlineBlamePopover {
  968    position: gpui::Point<Pixels>,
  969    hide_task: Option<Task<()>>,
  970    popover_bounds: Option<Bounds<Pixels>>,
  971    popover_state: InlineBlamePopoverState,
  972    keyboard_grace: bool,
  973}
  974
  975enum SelectionDragState {
  976    /// State when no drag related activity is detected.
  977    None,
  978    /// State when the mouse is down on a selection that is about to be dragged.
  979    ReadyToDrag {
  980        selection: Selection<Anchor>,
  981        click_position: gpui::Point<Pixels>,
  982        mouse_down_time: Instant,
  983    },
  984    /// State when the mouse is dragging the selection in the editor.
  985    Dragging {
  986        selection: Selection<Anchor>,
  987        drop_cursor: Selection<Anchor>,
  988        hide_drop_cursor: bool,
  989    },
  990}
  991
  992enum ColumnarSelectionState {
  993    FromMouse {
  994        selection_tail: Anchor,
  995        display_point: Option<DisplayPoint>,
  996    },
  997    FromSelection {
  998        selection_tail: Anchor,
  999    },
 1000}
 1001
 1002/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1003/// a breakpoint on them.
 1004#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1005struct PhantomBreakpointIndicator {
 1006    display_row: DisplayRow,
 1007    /// There's a small debounce between hovering over the line and showing the indicator.
 1008    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1009    is_active: bool,
 1010    collides_with_existing_breakpoint: bool,
 1011}
 1012
 1013/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1014///
 1015/// See the [module level documentation](self) for more information.
 1016pub struct Editor {
 1017    focus_handle: FocusHandle,
 1018    last_focused_descendant: Option<WeakFocusHandle>,
 1019    /// The text buffer being edited
 1020    buffer: Entity<MultiBuffer>,
 1021    /// Map of how text in the buffer should be displayed.
 1022    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1023    pub display_map: Entity<DisplayMap>,
 1024    placeholder_display_map: Option<Entity<DisplayMap>>,
 1025    pub selections: SelectionsCollection,
 1026    pub scroll_manager: ScrollManager,
 1027    /// When inline assist editors are linked, they all render cursors because
 1028    /// typing enters text into each of them, even the ones that aren't focused.
 1029    pub(crate) show_cursor_when_unfocused: bool,
 1030    columnar_selection_state: Option<ColumnarSelectionState>,
 1031    add_selections_state: Option<AddSelectionsState>,
 1032    select_next_state: Option<SelectNextState>,
 1033    select_prev_state: Option<SelectNextState>,
 1034    selection_history: SelectionHistory,
 1035    defer_selection_effects: bool,
 1036    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1037    autoclose_regions: Vec<AutocloseRegion>,
 1038    snippet_stack: InvalidationStack<SnippetState>,
 1039    select_syntax_node_history: SelectSyntaxNodeHistory,
 1040    ime_transaction: Option<TransactionId>,
 1041    pub diagnostics_max_severity: DiagnosticSeverity,
 1042    active_diagnostics: ActiveDiagnostic,
 1043    show_inline_diagnostics: bool,
 1044    inline_diagnostics_update: Task<()>,
 1045    inline_diagnostics_enabled: bool,
 1046    diagnostics_enabled: bool,
 1047    word_completions_enabled: bool,
 1048    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1049    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1050    hard_wrap: Option<usize>,
 1051    project: Option<Entity<Project>>,
 1052    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1053    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1054    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1055    blink_manager: Entity<BlinkManager>,
 1056    show_cursor_names: bool,
 1057    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1058    pub show_local_selections: bool,
 1059    mode: EditorMode,
 1060    show_breadcrumbs: bool,
 1061    show_gutter: bool,
 1062    show_scrollbars: ScrollbarAxes,
 1063    minimap_visibility: MinimapVisibility,
 1064    offset_content: bool,
 1065    disable_expand_excerpt_buttons: bool,
 1066    show_line_numbers: Option<bool>,
 1067    use_relative_line_numbers: Option<bool>,
 1068    show_git_diff_gutter: Option<bool>,
 1069    show_code_actions: Option<bool>,
 1070    show_runnables: Option<bool>,
 1071    show_breakpoints: Option<bool>,
 1072    show_wrap_guides: Option<bool>,
 1073    show_indent_guides: Option<bool>,
 1074    highlight_order: usize,
 1075    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1076    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1077    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1078    scrollbar_marker_state: ScrollbarMarkerState,
 1079    active_indent_guides_state: ActiveIndentGuidesState,
 1080    nav_history: Option<ItemNavHistory>,
 1081    context_menu: RefCell<Option<CodeContextMenu>>,
 1082    context_menu_options: Option<ContextMenuOptions>,
 1083    mouse_context_menu: Option<MouseContextMenu>,
 1084    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1085    inline_blame_popover: Option<InlineBlamePopover>,
 1086    inline_blame_popover_show_task: Option<Task<()>>,
 1087    signature_help_state: SignatureHelpState,
 1088    auto_signature_help: Option<bool>,
 1089    find_all_references_task_sources: Vec<Anchor>,
 1090    next_completion_id: CompletionId,
 1091    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1092    code_actions_task: Option<Task<Result<()>>>,
 1093    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1094    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1095    document_highlights_task: Option<Task<()>>,
 1096    linked_editing_range_task: Option<Task<Option<()>>>,
 1097    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1098    pending_rename: Option<RenameState>,
 1099    searchable: bool,
 1100    cursor_shape: CursorShape,
 1101    current_line_highlight: Option<CurrentLineHighlight>,
 1102    collapse_matches: bool,
 1103    autoindent_mode: Option<AutoindentMode>,
 1104    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1105    input_enabled: bool,
 1106    use_modal_editing: bool,
 1107    read_only: bool,
 1108    leader_id: Option<CollaboratorId>,
 1109    remote_id: Option<ViewId>,
 1110    pub hover_state: HoverState,
 1111    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1112    gutter_hovered: bool,
 1113    hovered_link_state: Option<HoveredLinkState>,
 1114    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1115    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1116    active_edit_prediction: Option<EditPredictionState>,
 1117    /// Used to prevent flickering as the user types while the menu is open
 1118    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1119    edit_prediction_settings: EditPredictionSettings,
 1120    edit_predictions_hidden_for_vim_mode: bool,
 1121    show_edit_predictions_override: Option<bool>,
 1122    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1123    edit_prediction_preview: EditPredictionPreview,
 1124    edit_prediction_indent_conflict: bool,
 1125    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1126    inlay_hint_cache: InlayHintCache,
 1127    next_inlay_id: u32,
 1128    next_color_inlay_id: u32,
 1129    _subscriptions: Vec<Subscription>,
 1130    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1131    gutter_dimensions: GutterDimensions,
 1132    style: Option<EditorStyle>,
 1133    text_style_refinement: Option<TextStyleRefinement>,
 1134    next_editor_action_id: EditorActionId,
 1135    editor_actions: Rc<
 1136        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1137    >,
 1138    use_autoclose: bool,
 1139    use_auto_surround: bool,
 1140    auto_replace_emoji_shortcode: bool,
 1141    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1142    show_git_blame_gutter: bool,
 1143    show_git_blame_inline: bool,
 1144    show_git_blame_inline_delay_task: Option<Task<()>>,
 1145    git_blame_inline_enabled: bool,
 1146    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1147    serialize_dirty_buffers: bool,
 1148    show_selection_menu: Option<bool>,
 1149    blame: Option<Entity<GitBlame>>,
 1150    blame_subscription: Option<Subscription>,
 1151    custom_context_menu: Option<
 1152        Box<
 1153            dyn 'static
 1154                + Fn(
 1155                    &mut Self,
 1156                    DisplayPoint,
 1157                    &mut Window,
 1158                    &mut Context<Self>,
 1159                ) -> Option<Entity<ui::ContextMenu>>,
 1160        >,
 1161    >,
 1162    last_bounds: Option<Bounds<Pixels>>,
 1163    last_position_map: Option<Rc<PositionMap>>,
 1164    expect_bounds_change: Option<Bounds<Pixels>>,
 1165    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1166    tasks_update_task: Option<Task<()>>,
 1167    breakpoint_store: Option<Entity<BreakpointStore>>,
 1168    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1169    hovered_diff_hunk_row: Option<DisplayRow>,
 1170    pull_diagnostics_task: Task<()>,
 1171    in_project_search: bool,
 1172    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1173    breadcrumb_header: Option<String>,
 1174    focused_block: Option<FocusedBlock>,
 1175    next_scroll_position: NextScrollCursorCenterTopBottom,
 1176    addons: HashMap<TypeId, Box<dyn Addon>>,
 1177    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1178    load_diff_task: Option<Shared<Task<()>>>,
 1179    /// Whether we are temporarily displaying a diff other than git's
 1180    temporary_diff_override: bool,
 1181    selection_mark_mode: bool,
 1182    toggle_fold_multiple_buffers: Task<()>,
 1183    _scroll_cursor_center_top_bottom_task: Task<()>,
 1184    serialize_selections: Task<()>,
 1185    serialize_folds: Task<()>,
 1186    mouse_cursor_hidden: bool,
 1187    minimap: Option<Entity<Self>>,
 1188    hide_mouse_mode: HideMouseMode,
 1189    pub change_list: ChangeList,
 1190    inline_value_cache: InlineValueCache,
 1191    selection_drag_state: SelectionDragState,
 1192    colors: Option<LspColorData>,
 1193    refresh_colors_task: Task<()>,
 1194    folding_newlines: Task<()>,
 1195    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1196}
 1197
 1198#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1199enum NextScrollCursorCenterTopBottom {
 1200    #[default]
 1201    Center,
 1202    Top,
 1203    Bottom,
 1204}
 1205
 1206impl NextScrollCursorCenterTopBottom {
 1207    fn next(&self) -> Self {
 1208        match self {
 1209            Self::Center => Self::Top,
 1210            Self::Top => Self::Bottom,
 1211            Self::Bottom => Self::Center,
 1212        }
 1213    }
 1214}
 1215
 1216#[derive(Clone)]
 1217pub struct EditorSnapshot {
 1218    pub mode: EditorMode,
 1219    show_gutter: bool,
 1220    show_line_numbers: Option<bool>,
 1221    show_git_diff_gutter: Option<bool>,
 1222    show_code_actions: Option<bool>,
 1223    show_runnables: Option<bool>,
 1224    show_breakpoints: Option<bool>,
 1225    git_blame_gutter_max_author_length: Option<usize>,
 1226    pub display_snapshot: DisplaySnapshot,
 1227    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1228    is_focused: bool,
 1229    scroll_anchor: ScrollAnchor,
 1230    ongoing_scroll: OngoingScroll,
 1231    current_line_highlight: CurrentLineHighlight,
 1232    gutter_hovered: bool,
 1233}
 1234
 1235#[derive(Default, Debug, Clone, Copy)]
 1236pub struct GutterDimensions {
 1237    pub left_padding: Pixels,
 1238    pub right_padding: Pixels,
 1239    pub width: Pixels,
 1240    pub margin: Pixels,
 1241    pub git_blame_entries_width: Option<Pixels>,
 1242}
 1243
 1244impl GutterDimensions {
 1245    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1246        Self {
 1247            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1248            ..Default::default()
 1249        }
 1250    }
 1251
 1252    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1253        -cx.text_system().descent(font_id, font_size)
 1254    }
 1255    /// The full width of the space taken up by the gutter.
 1256    pub fn full_width(&self) -> Pixels {
 1257        self.margin + self.width
 1258    }
 1259
 1260    /// The width of the space reserved for the fold indicators,
 1261    /// use alongside 'justify_end' and `gutter_width` to
 1262    /// right align content with the line numbers
 1263    pub fn fold_area_width(&self) -> Pixels {
 1264        self.margin + self.right_padding
 1265    }
 1266}
 1267
 1268struct CharacterDimensions {
 1269    em_width: Pixels,
 1270    em_advance: Pixels,
 1271    line_height: Pixels,
 1272}
 1273
 1274#[derive(Debug)]
 1275pub struct RemoteSelection {
 1276    pub replica_id: ReplicaId,
 1277    pub selection: Selection<Anchor>,
 1278    pub cursor_shape: CursorShape,
 1279    pub collaborator_id: CollaboratorId,
 1280    pub line_mode: bool,
 1281    pub user_name: Option<SharedString>,
 1282    pub color: PlayerColor,
 1283}
 1284
 1285#[derive(Clone, Debug)]
 1286struct SelectionHistoryEntry {
 1287    selections: Arc<[Selection<Anchor>]>,
 1288    select_next_state: Option<SelectNextState>,
 1289    select_prev_state: Option<SelectNextState>,
 1290    add_selections_state: Option<AddSelectionsState>,
 1291}
 1292
 1293#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1294enum SelectionHistoryMode {
 1295    Normal,
 1296    Undoing,
 1297    Redoing,
 1298    Skipping,
 1299}
 1300
 1301#[derive(Clone, PartialEq, Eq, Hash)]
 1302struct HoveredCursor {
 1303    replica_id: u16,
 1304    selection_id: usize,
 1305}
 1306
 1307impl Default for SelectionHistoryMode {
 1308    fn default() -> Self {
 1309        Self::Normal
 1310    }
 1311}
 1312
 1313#[derive(Debug)]
 1314/// SelectionEffects controls the side-effects of updating the selection.
 1315///
 1316/// The default behaviour does "what you mostly want":
 1317/// - it pushes to the nav history if the cursor moved by >10 lines
 1318/// - it re-triggers completion requests
 1319/// - it scrolls to fit
 1320///
 1321/// You might want to modify these behaviours. For example when doing a "jump"
 1322/// like go to definition, we always want to add to nav history; but when scrolling
 1323/// in vim mode we never do.
 1324///
 1325/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1326/// move.
 1327#[derive(Clone)]
 1328pub struct SelectionEffects {
 1329    nav_history: Option<bool>,
 1330    completions: bool,
 1331    scroll: Option<Autoscroll>,
 1332}
 1333
 1334impl Default for SelectionEffects {
 1335    fn default() -> Self {
 1336        Self {
 1337            nav_history: None,
 1338            completions: true,
 1339            scroll: Some(Autoscroll::fit()),
 1340        }
 1341    }
 1342}
 1343impl SelectionEffects {
 1344    pub fn scroll(scroll: Autoscroll) -> Self {
 1345        Self {
 1346            scroll: Some(scroll),
 1347            ..Default::default()
 1348        }
 1349    }
 1350
 1351    pub fn no_scroll() -> Self {
 1352        Self {
 1353            scroll: None,
 1354            ..Default::default()
 1355        }
 1356    }
 1357
 1358    pub fn completions(self, completions: bool) -> Self {
 1359        Self {
 1360            completions,
 1361            ..self
 1362        }
 1363    }
 1364
 1365    pub fn nav_history(self, nav_history: bool) -> Self {
 1366        Self {
 1367            nav_history: Some(nav_history),
 1368            ..self
 1369        }
 1370    }
 1371}
 1372
 1373struct DeferredSelectionEffectsState {
 1374    changed: bool,
 1375    effects: SelectionEffects,
 1376    old_cursor_position: Anchor,
 1377    history_entry: SelectionHistoryEntry,
 1378}
 1379
 1380#[derive(Default)]
 1381struct SelectionHistory {
 1382    #[allow(clippy::type_complexity)]
 1383    selections_by_transaction:
 1384        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1385    mode: SelectionHistoryMode,
 1386    undo_stack: VecDeque<SelectionHistoryEntry>,
 1387    redo_stack: VecDeque<SelectionHistoryEntry>,
 1388}
 1389
 1390impl SelectionHistory {
 1391    #[track_caller]
 1392    fn insert_transaction(
 1393        &mut self,
 1394        transaction_id: TransactionId,
 1395        selections: Arc<[Selection<Anchor>]>,
 1396    ) {
 1397        if selections.is_empty() {
 1398            log::error!(
 1399                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1400                std::panic::Location::caller()
 1401            );
 1402            return;
 1403        }
 1404        self.selections_by_transaction
 1405            .insert(transaction_id, (selections, None));
 1406    }
 1407
 1408    #[allow(clippy::type_complexity)]
 1409    fn transaction(
 1410        &self,
 1411        transaction_id: TransactionId,
 1412    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1413        self.selections_by_transaction.get(&transaction_id)
 1414    }
 1415
 1416    #[allow(clippy::type_complexity)]
 1417    fn transaction_mut(
 1418        &mut self,
 1419        transaction_id: TransactionId,
 1420    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1421        self.selections_by_transaction.get_mut(&transaction_id)
 1422    }
 1423
 1424    fn push(&mut self, entry: SelectionHistoryEntry) {
 1425        if !entry.selections.is_empty() {
 1426            match self.mode {
 1427                SelectionHistoryMode::Normal => {
 1428                    self.push_undo(entry);
 1429                    self.redo_stack.clear();
 1430                }
 1431                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1432                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1433                SelectionHistoryMode::Skipping => {}
 1434            }
 1435        }
 1436    }
 1437
 1438    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1439        if self
 1440            .undo_stack
 1441            .back()
 1442            .is_none_or(|e| e.selections != entry.selections)
 1443        {
 1444            self.undo_stack.push_back(entry);
 1445            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1446                self.undo_stack.pop_front();
 1447            }
 1448        }
 1449    }
 1450
 1451    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1452        if self
 1453            .redo_stack
 1454            .back()
 1455            .is_none_or(|e| e.selections != entry.selections)
 1456        {
 1457            self.redo_stack.push_back(entry);
 1458            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1459                self.redo_stack.pop_front();
 1460            }
 1461        }
 1462    }
 1463}
 1464
 1465#[derive(Clone, Copy)]
 1466pub struct RowHighlightOptions {
 1467    pub autoscroll: bool,
 1468    pub include_gutter: bool,
 1469}
 1470
 1471impl Default for RowHighlightOptions {
 1472    fn default() -> Self {
 1473        Self {
 1474            autoscroll: Default::default(),
 1475            include_gutter: true,
 1476        }
 1477    }
 1478}
 1479
 1480struct RowHighlight {
 1481    index: usize,
 1482    range: Range<Anchor>,
 1483    color: Hsla,
 1484    options: RowHighlightOptions,
 1485    type_id: TypeId,
 1486}
 1487
 1488#[derive(Clone, Debug)]
 1489struct AddSelectionsState {
 1490    groups: Vec<AddSelectionsGroup>,
 1491}
 1492
 1493#[derive(Clone, Debug)]
 1494struct AddSelectionsGroup {
 1495    above: bool,
 1496    stack: Vec<usize>,
 1497}
 1498
 1499#[derive(Clone)]
 1500struct SelectNextState {
 1501    query: AhoCorasick,
 1502    wordwise: bool,
 1503    done: bool,
 1504}
 1505
 1506impl std::fmt::Debug for SelectNextState {
 1507    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1508        f.debug_struct(std::any::type_name::<Self>())
 1509            .field("wordwise", &self.wordwise)
 1510            .field("done", &self.done)
 1511            .finish()
 1512    }
 1513}
 1514
 1515#[derive(Debug)]
 1516struct AutocloseRegion {
 1517    selection_id: usize,
 1518    range: Range<Anchor>,
 1519    pair: BracketPair,
 1520}
 1521
 1522#[derive(Debug)]
 1523struct SnippetState {
 1524    ranges: Vec<Vec<Range<Anchor>>>,
 1525    active_index: usize,
 1526    choices: Vec<Option<Vec<String>>>,
 1527}
 1528
 1529#[doc(hidden)]
 1530pub struct RenameState {
 1531    pub range: Range<Anchor>,
 1532    pub old_name: Arc<str>,
 1533    pub editor: Entity<Editor>,
 1534    block_id: CustomBlockId,
 1535}
 1536
 1537struct InvalidationStack<T>(Vec<T>);
 1538
 1539struct RegisteredEditPredictionProvider {
 1540    provider: Arc<dyn EditPredictionProviderHandle>,
 1541    _subscription: Subscription,
 1542}
 1543
 1544#[derive(Debug, PartialEq, Eq)]
 1545pub struct ActiveDiagnosticGroup {
 1546    pub active_range: Range<Anchor>,
 1547    pub active_message: String,
 1548    pub group_id: usize,
 1549    pub blocks: HashSet<CustomBlockId>,
 1550}
 1551
 1552#[derive(Debug, PartialEq, Eq)]
 1553
 1554pub(crate) enum ActiveDiagnostic {
 1555    None,
 1556    All,
 1557    Group(ActiveDiagnosticGroup),
 1558}
 1559
 1560#[derive(Serialize, Deserialize, Clone, Debug)]
 1561pub struct ClipboardSelection {
 1562    /// The number of bytes in this selection.
 1563    pub len: usize,
 1564    /// Whether this was a full-line selection.
 1565    pub is_entire_line: bool,
 1566    /// The indentation of the first line when this content was originally copied.
 1567    pub first_line_indent: u32,
 1568}
 1569
 1570// selections, scroll behavior, was newest selection reversed
 1571type SelectSyntaxNodeHistoryState = (
 1572    Box<[Selection<usize>]>,
 1573    SelectSyntaxNodeScrollBehavior,
 1574    bool,
 1575);
 1576
 1577#[derive(Default)]
 1578struct SelectSyntaxNodeHistory {
 1579    stack: Vec<SelectSyntaxNodeHistoryState>,
 1580    // disable temporarily to allow changing selections without losing the stack
 1581    pub disable_clearing: bool,
 1582}
 1583
 1584impl SelectSyntaxNodeHistory {
 1585    pub fn try_clear(&mut self) {
 1586        if !self.disable_clearing {
 1587            self.stack.clear();
 1588        }
 1589    }
 1590
 1591    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1592        self.stack.push(selection);
 1593    }
 1594
 1595    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1596        self.stack.pop()
 1597    }
 1598}
 1599
 1600enum SelectSyntaxNodeScrollBehavior {
 1601    CursorTop,
 1602    FitSelection,
 1603    CursorBottom,
 1604}
 1605
 1606#[derive(Debug)]
 1607pub(crate) struct NavigationData {
 1608    cursor_anchor: Anchor,
 1609    cursor_position: Point,
 1610    scroll_anchor: ScrollAnchor,
 1611    scroll_top_row: u32,
 1612}
 1613
 1614#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1615pub enum GotoDefinitionKind {
 1616    Symbol,
 1617    Declaration,
 1618    Type,
 1619    Implementation,
 1620}
 1621
 1622#[derive(Debug, Clone)]
 1623enum InlayHintRefreshReason {
 1624    ModifiersChanged(bool),
 1625    Toggle(bool),
 1626    SettingsChange(InlayHintSettings),
 1627    NewLinesShown,
 1628    BufferEdited(HashSet<Arc<Language>>),
 1629    RefreshRequested,
 1630    ExcerptsRemoved(Vec<ExcerptId>),
 1631}
 1632
 1633impl InlayHintRefreshReason {
 1634    fn description(&self) -> &'static str {
 1635        match self {
 1636            Self::ModifiersChanged(_) => "modifiers changed",
 1637            Self::Toggle(_) => "toggle",
 1638            Self::SettingsChange(_) => "settings change",
 1639            Self::NewLinesShown => "new lines shown",
 1640            Self::BufferEdited(_) => "buffer edited",
 1641            Self::RefreshRequested => "refresh requested",
 1642            Self::ExcerptsRemoved(_) => "excerpts removed",
 1643        }
 1644    }
 1645}
 1646
 1647pub enum FormatTarget {
 1648    Buffers(HashSet<Entity<Buffer>>),
 1649    Ranges(Vec<Range<MultiBufferPoint>>),
 1650}
 1651
 1652pub(crate) struct FocusedBlock {
 1653    id: BlockId,
 1654    focus_handle: WeakFocusHandle,
 1655}
 1656
 1657#[derive(Clone)]
 1658enum JumpData {
 1659    MultiBufferRow {
 1660        row: MultiBufferRow,
 1661        line_offset_from_top: u32,
 1662    },
 1663    MultiBufferPoint {
 1664        excerpt_id: ExcerptId,
 1665        position: Point,
 1666        anchor: text::Anchor,
 1667        line_offset_from_top: u32,
 1668    },
 1669}
 1670
 1671pub enum MultibufferSelectionMode {
 1672    First,
 1673    All,
 1674}
 1675
 1676#[derive(Clone, Copy, Debug, Default)]
 1677pub struct RewrapOptions {
 1678    pub override_language_settings: bool,
 1679    pub preserve_existing_whitespace: bool,
 1680}
 1681
 1682impl Editor {
 1683    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1684        let buffer = cx.new(|cx| Buffer::local("", cx));
 1685        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1686        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1687    }
 1688
 1689    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1690        let buffer = cx.new(|cx| Buffer::local("", cx));
 1691        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1692        Self::new(EditorMode::full(), buffer, None, window, cx)
 1693    }
 1694
 1695    pub fn auto_height(
 1696        min_lines: usize,
 1697        max_lines: usize,
 1698        window: &mut Window,
 1699        cx: &mut Context<Self>,
 1700    ) -> Self {
 1701        let buffer = cx.new(|cx| Buffer::local("", cx));
 1702        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1703        Self::new(
 1704            EditorMode::AutoHeight {
 1705                min_lines,
 1706                max_lines: Some(max_lines),
 1707            },
 1708            buffer,
 1709            None,
 1710            window,
 1711            cx,
 1712        )
 1713    }
 1714
 1715    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1716    /// The editor grows as tall as needed to fit its content.
 1717    pub fn auto_height_unbounded(
 1718        min_lines: usize,
 1719        window: &mut Window,
 1720        cx: &mut Context<Self>,
 1721    ) -> Self {
 1722        let buffer = cx.new(|cx| Buffer::local("", cx));
 1723        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1724        Self::new(
 1725            EditorMode::AutoHeight {
 1726                min_lines,
 1727                max_lines: None,
 1728            },
 1729            buffer,
 1730            None,
 1731            window,
 1732            cx,
 1733        )
 1734    }
 1735
 1736    pub fn for_buffer(
 1737        buffer: Entity<Buffer>,
 1738        project: Option<Entity<Project>>,
 1739        window: &mut Window,
 1740        cx: &mut Context<Self>,
 1741    ) -> Self {
 1742        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1743        Self::new(EditorMode::full(), buffer, project, window, cx)
 1744    }
 1745
 1746    pub fn for_multibuffer(
 1747        buffer: Entity<MultiBuffer>,
 1748        project: Option<Entity<Project>>,
 1749        window: &mut Window,
 1750        cx: &mut Context<Self>,
 1751    ) -> Self {
 1752        Self::new(EditorMode::full(), buffer, project, window, cx)
 1753    }
 1754
 1755    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1756        let mut clone = Self::new(
 1757            self.mode.clone(),
 1758            self.buffer.clone(),
 1759            self.project.clone(),
 1760            window,
 1761            cx,
 1762        );
 1763        self.display_map.update(cx, |display_map, cx| {
 1764            let snapshot = display_map.snapshot(cx);
 1765            clone.display_map.update(cx, |display_map, cx| {
 1766                display_map.set_state(&snapshot, cx);
 1767            });
 1768        });
 1769        clone.folds_did_change(cx);
 1770        clone.selections.clone_state(&self.selections);
 1771        clone.scroll_manager.clone_state(&self.scroll_manager);
 1772        clone.searchable = self.searchable;
 1773        clone.read_only = self.read_only;
 1774        clone
 1775    }
 1776
 1777    pub fn new(
 1778        mode: EditorMode,
 1779        buffer: Entity<MultiBuffer>,
 1780        project: Option<Entity<Project>>,
 1781        window: &mut Window,
 1782        cx: &mut Context<Self>,
 1783    ) -> Self {
 1784        Editor::new_internal(mode, buffer, project, None, window, cx)
 1785    }
 1786
 1787    fn new_internal(
 1788        mode: EditorMode,
 1789        buffer: Entity<MultiBuffer>,
 1790        project: Option<Entity<Project>>,
 1791        display_map: Option<Entity<DisplayMap>>,
 1792        window: &mut Window,
 1793        cx: &mut Context<Self>,
 1794    ) -> Self {
 1795        debug_assert!(
 1796            display_map.is_none() || mode.is_minimap(),
 1797            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1798        );
 1799
 1800        let full_mode = mode.is_full();
 1801        let is_minimap = mode.is_minimap();
 1802        let diagnostics_max_severity = if full_mode {
 1803            EditorSettings::get_global(cx)
 1804                .diagnostics_max_severity
 1805                .unwrap_or(DiagnosticSeverity::Hint)
 1806        } else {
 1807            DiagnosticSeverity::Off
 1808        };
 1809        let style = window.text_style();
 1810        let font_size = style.font_size.to_pixels(window.rem_size());
 1811        let editor = cx.entity().downgrade();
 1812        let fold_placeholder = FoldPlaceholder {
 1813            constrain_width: false,
 1814            render: Arc::new(move |fold_id, fold_range, cx| {
 1815                let editor = editor.clone();
 1816                div()
 1817                    .id(fold_id)
 1818                    .bg(cx.theme().colors().ghost_element_background)
 1819                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1820                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1821                    .rounded_xs()
 1822                    .size_full()
 1823                    .cursor_pointer()
 1824                    .child("")
 1825                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1826                    .on_click(move |_, _window, cx| {
 1827                        editor
 1828                            .update(cx, |editor, cx| {
 1829                                editor.unfold_ranges(
 1830                                    &[fold_range.start..fold_range.end],
 1831                                    true,
 1832                                    false,
 1833                                    cx,
 1834                                );
 1835                                cx.stop_propagation();
 1836                            })
 1837                            .ok();
 1838                    })
 1839                    .into_any()
 1840            }),
 1841            merge_adjacent: true,
 1842            ..FoldPlaceholder::default()
 1843        };
 1844        let display_map = display_map.unwrap_or_else(|| {
 1845            cx.new(|cx| {
 1846                DisplayMap::new(
 1847                    buffer.clone(),
 1848                    style.font(),
 1849                    font_size,
 1850                    None,
 1851                    FILE_HEADER_HEIGHT,
 1852                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1853                    fold_placeholder,
 1854                    diagnostics_max_severity,
 1855                    cx,
 1856                )
 1857            })
 1858        });
 1859
 1860        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1861
 1862        let blink_manager = cx.new(|cx| {
 1863            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1864            if is_minimap {
 1865                blink_manager.disable(cx);
 1866            }
 1867            blink_manager
 1868        });
 1869
 1870        let soft_wrap_mode_override =
 1871            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1872
 1873        let mut project_subscriptions = Vec::new();
 1874        if full_mode && let Some(project) = project.as_ref() {
 1875            project_subscriptions.push(cx.subscribe_in(
 1876                project,
 1877                window,
 1878                |editor, _, event, window, cx| match event {
 1879                    project::Event::RefreshCodeLens => {
 1880                        // we always query lens with actions, without storing them, always refreshing them
 1881                    }
 1882                    project::Event::RefreshInlayHints => {
 1883                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1884                    }
 1885                    project::Event::LanguageServerAdded(..)
 1886                    | project::Event::LanguageServerRemoved(..) => {
 1887                        if editor.tasks_update_task.is_none() {
 1888                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1889                        }
 1890                    }
 1891                    project::Event::SnippetEdit(id, snippet_edits) => {
 1892                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1893                            let focus_handle = editor.focus_handle(cx);
 1894                            if focus_handle.is_focused(window) {
 1895                                let snapshot = buffer.read(cx).snapshot();
 1896                                for (range, snippet) in snippet_edits {
 1897                                    let editor_range =
 1898                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1899                                    editor
 1900                                        .insert_snippet(
 1901                                            &[editor_range],
 1902                                            snippet.clone(),
 1903                                            window,
 1904                                            cx,
 1905                                        )
 1906                                        .ok();
 1907                                }
 1908                            }
 1909                        }
 1910                    }
 1911                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1912                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1913                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1914                        }
 1915                    }
 1916
 1917                    project::Event::EntryRenamed(transaction) => {
 1918                        let Some(workspace) = editor.workspace() else {
 1919                            return;
 1920                        };
 1921                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1922                        else {
 1923                            return;
 1924                        };
 1925                        if active_editor.entity_id() == cx.entity_id() {
 1926                            let edited_buffers_already_open = {
 1927                                let other_editors: Vec<Entity<Editor>> = workspace
 1928                                    .read(cx)
 1929                                    .panes()
 1930                                    .iter()
 1931                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1932                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1933                                    .collect();
 1934
 1935                                transaction.0.keys().all(|buffer| {
 1936                                    other_editors.iter().any(|editor| {
 1937                                        let multi_buffer = editor.read(cx).buffer();
 1938                                        multi_buffer.read(cx).is_singleton()
 1939                                            && multi_buffer.read(cx).as_singleton().map_or(
 1940                                                false,
 1941                                                |singleton| {
 1942                                                    singleton.entity_id() == buffer.entity_id()
 1943                                                },
 1944                                            )
 1945                                    })
 1946                                })
 1947                            };
 1948
 1949                            if !edited_buffers_already_open {
 1950                                let workspace = workspace.downgrade();
 1951                                let transaction = transaction.clone();
 1952                                cx.defer_in(window, move |_, window, cx| {
 1953                                    cx.spawn_in(window, async move |editor, cx| {
 1954                                        Self::open_project_transaction(
 1955                                            &editor,
 1956                                            workspace,
 1957                                            transaction,
 1958                                            "Rename".to_string(),
 1959                                            cx,
 1960                                        )
 1961                                        .await
 1962                                        .ok()
 1963                                    })
 1964                                    .detach();
 1965                                });
 1966                            }
 1967                        }
 1968                    }
 1969
 1970                    _ => {}
 1971                },
 1972            ));
 1973            if let Some(task_inventory) = project
 1974                .read(cx)
 1975                .task_store()
 1976                .read(cx)
 1977                .task_inventory()
 1978                .cloned()
 1979            {
 1980                project_subscriptions.push(cx.observe_in(
 1981                    &task_inventory,
 1982                    window,
 1983                    |editor, _, window, cx| {
 1984                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1985                    },
 1986                ));
 1987            };
 1988
 1989            project_subscriptions.push(cx.subscribe_in(
 1990                &project.read(cx).breakpoint_store(),
 1991                window,
 1992                |editor, _, event, window, cx| match event {
 1993                    BreakpointStoreEvent::ClearDebugLines => {
 1994                        editor.clear_row_highlights::<ActiveDebugLine>();
 1995                        editor.refresh_inline_values(cx);
 1996                    }
 1997                    BreakpointStoreEvent::SetDebugLine => {
 1998                        if editor.go_to_active_debug_line(window, cx) {
 1999                            cx.stop_propagation();
 2000                        }
 2001
 2002                        editor.refresh_inline_values(cx);
 2003                    }
 2004                    _ => {}
 2005                },
 2006            ));
 2007            let git_store = project.read(cx).git_store().clone();
 2008            let project = project.clone();
 2009            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2010                if let GitStoreEvent::RepositoryUpdated(
 2011                    _,
 2012                    RepositoryEvent::Updated {
 2013                        new_instance: true, ..
 2014                    },
 2015                    _,
 2016                ) = event
 2017                {
 2018                    this.load_diff_task = Some(
 2019                        update_uncommitted_diff_for_buffer(
 2020                            cx.entity(),
 2021                            &project,
 2022                            this.buffer.read(cx).all_buffers(),
 2023                            this.buffer.clone(),
 2024                            cx,
 2025                        )
 2026                        .shared(),
 2027                    );
 2028                }
 2029            }));
 2030        }
 2031
 2032        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2033
 2034        let inlay_hint_settings =
 2035            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2036        let focus_handle = cx.focus_handle();
 2037        if !is_minimap {
 2038            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2039                .detach();
 2040            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2041                .detach();
 2042            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2043                .detach();
 2044            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2045                .detach();
 2046            cx.observe_pending_input(window, Self::observe_pending_input)
 2047                .detach();
 2048        }
 2049
 2050        let show_indent_guides =
 2051            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2052                Some(false)
 2053            } else {
 2054                None
 2055            };
 2056
 2057        let breakpoint_store = match (&mode, project.as_ref()) {
 2058            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2059            _ => None,
 2060        };
 2061
 2062        let mut code_action_providers = Vec::new();
 2063        let mut load_uncommitted_diff = None;
 2064        if let Some(project) = project.clone() {
 2065            load_uncommitted_diff = Some(
 2066                update_uncommitted_diff_for_buffer(
 2067                    cx.entity(),
 2068                    &project,
 2069                    buffer.read(cx).all_buffers(),
 2070                    buffer.clone(),
 2071                    cx,
 2072                )
 2073                .shared(),
 2074            );
 2075            code_action_providers.push(Rc::new(project) as Rc<_>);
 2076        }
 2077
 2078        let mut editor = Self {
 2079            focus_handle,
 2080            show_cursor_when_unfocused: false,
 2081            last_focused_descendant: None,
 2082            buffer: buffer.clone(),
 2083            display_map: display_map.clone(),
 2084            placeholder_display_map: None,
 2085            selections,
 2086            scroll_manager: ScrollManager::new(cx),
 2087            columnar_selection_state: None,
 2088            add_selections_state: None,
 2089            select_next_state: None,
 2090            select_prev_state: None,
 2091            selection_history: SelectionHistory::default(),
 2092            defer_selection_effects: false,
 2093            deferred_selection_effects_state: None,
 2094            autoclose_regions: Vec::new(),
 2095            snippet_stack: InvalidationStack::default(),
 2096            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2097            ime_transaction: None,
 2098            active_diagnostics: ActiveDiagnostic::None,
 2099            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2100            inline_diagnostics_update: Task::ready(()),
 2101            inline_diagnostics: Vec::new(),
 2102            soft_wrap_mode_override,
 2103            diagnostics_max_severity,
 2104            hard_wrap: None,
 2105            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2106            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2107            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2108            project,
 2109            blink_manager: blink_manager.clone(),
 2110            show_local_selections: true,
 2111            show_scrollbars: ScrollbarAxes {
 2112                horizontal: full_mode,
 2113                vertical: full_mode,
 2114            },
 2115            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2116            offset_content: !matches!(mode, EditorMode::SingleLine),
 2117            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2118            show_gutter: full_mode,
 2119            show_line_numbers: (!full_mode).then_some(false),
 2120            use_relative_line_numbers: None,
 2121            disable_expand_excerpt_buttons: !full_mode,
 2122            show_git_diff_gutter: None,
 2123            show_code_actions: None,
 2124            show_runnables: None,
 2125            show_breakpoints: None,
 2126            show_wrap_guides: None,
 2127            show_indent_guides,
 2128            highlight_order: 0,
 2129            highlighted_rows: HashMap::default(),
 2130            background_highlights: HashMap::default(),
 2131            gutter_highlights: HashMap::default(),
 2132            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2133            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2134            nav_history: None,
 2135            context_menu: RefCell::new(None),
 2136            context_menu_options: None,
 2137            mouse_context_menu: None,
 2138            completion_tasks: Vec::new(),
 2139            inline_blame_popover: None,
 2140            inline_blame_popover_show_task: None,
 2141            signature_help_state: SignatureHelpState::default(),
 2142            auto_signature_help: None,
 2143            find_all_references_task_sources: Vec::new(),
 2144            next_completion_id: 0,
 2145            next_inlay_id: 0,
 2146            code_action_providers,
 2147            available_code_actions: None,
 2148            code_actions_task: None,
 2149            quick_selection_highlight_task: None,
 2150            debounced_selection_highlight_task: None,
 2151            document_highlights_task: None,
 2152            linked_editing_range_task: None,
 2153            pending_rename: None,
 2154            searchable: !is_minimap,
 2155            cursor_shape: EditorSettings::get_global(cx)
 2156                .cursor_shape
 2157                .unwrap_or_default(),
 2158            current_line_highlight: None,
 2159            autoindent_mode: Some(AutoindentMode::EachLine),
 2160            collapse_matches: false,
 2161            workspace: None,
 2162            input_enabled: !is_minimap,
 2163            use_modal_editing: full_mode,
 2164            read_only: is_minimap,
 2165            use_autoclose: true,
 2166            use_auto_surround: true,
 2167            auto_replace_emoji_shortcode: false,
 2168            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2169            leader_id: None,
 2170            remote_id: None,
 2171            hover_state: HoverState::default(),
 2172            pending_mouse_down: None,
 2173            hovered_link_state: None,
 2174            edit_prediction_provider: None,
 2175            active_edit_prediction: None,
 2176            stale_edit_prediction_in_menu: None,
 2177            edit_prediction_preview: EditPredictionPreview::Inactive {
 2178                released_too_fast: false,
 2179            },
 2180            inline_diagnostics_enabled: full_mode,
 2181            diagnostics_enabled: full_mode,
 2182            word_completions_enabled: full_mode,
 2183            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2184            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2185            gutter_hovered: false,
 2186            pixel_position_of_newest_cursor: None,
 2187            last_bounds: None,
 2188            last_position_map: None,
 2189            expect_bounds_change: None,
 2190            gutter_dimensions: GutterDimensions::default(),
 2191            style: None,
 2192            show_cursor_names: false,
 2193            hovered_cursors: HashMap::default(),
 2194            next_editor_action_id: EditorActionId::default(),
 2195            editor_actions: Rc::default(),
 2196            edit_predictions_hidden_for_vim_mode: false,
 2197            show_edit_predictions_override: None,
 2198            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2199            edit_prediction_settings: EditPredictionSettings::Disabled,
 2200            edit_prediction_indent_conflict: false,
 2201            edit_prediction_requires_modifier_in_indent_conflict: true,
 2202            custom_context_menu: None,
 2203            show_git_blame_gutter: false,
 2204            show_git_blame_inline: false,
 2205            show_selection_menu: None,
 2206            show_git_blame_inline_delay_task: None,
 2207            git_blame_inline_enabled: full_mode
 2208                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2209            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2210            serialize_dirty_buffers: !is_minimap
 2211                && ProjectSettings::get_global(cx)
 2212                    .session
 2213                    .restore_unsaved_buffers,
 2214            blame: None,
 2215            blame_subscription: None,
 2216            tasks: BTreeMap::default(),
 2217
 2218            breakpoint_store,
 2219            gutter_breakpoint_indicator: (None, None),
 2220            hovered_diff_hunk_row: None,
 2221            _subscriptions: (!is_minimap)
 2222                .then(|| {
 2223                    vec![
 2224                        cx.observe(&buffer, Self::on_buffer_changed),
 2225                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2226                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2227                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2228                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2229                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2230                        cx.observe_window_activation(window, |editor, window, cx| {
 2231                            let active = window.is_window_active();
 2232                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2233                                if active {
 2234                                    blink_manager.enable(cx);
 2235                                } else {
 2236                                    blink_manager.disable(cx);
 2237                                }
 2238                            });
 2239                            if active {
 2240                                editor.show_mouse_cursor(cx);
 2241                            }
 2242                        }),
 2243                    ]
 2244                })
 2245                .unwrap_or_default(),
 2246            tasks_update_task: None,
 2247            pull_diagnostics_task: Task::ready(()),
 2248            colors: None,
 2249            refresh_colors_task: Task::ready(()),
 2250            next_color_inlay_id: 0,
 2251            linked_edit_ranges: Default::default(),
 2252            in_project_search: false,
 2253            previous_search_ranges: None,
 2254            breadcrumb_header: None,
 2255            focused_block: None,
 2256            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2257            addons: HashMap::default(),
 2258            registered_buffers: HashMap::default(),
 2259            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2260            selection_mark_mode: false,
 2261            toggle_fold_multiple_buffers: Task::ready(()),
 2262            serialize_selections: Task::ready(()),
 2263            serialize_folds: Task::ready(()),
 2264            text_style_refinement: None,
 2265            load_diff_task: load_uncommitted_diff,
 2266            temporary_diff_override: false,
 2267            mouse_cursor_hidden: false,
 2268            minimap: None,
 2269            hide_mouse_mode: EditorSettings::get_global(cx)
 2270                .hide_mouse
 2271                .unwrap_or_default(),
 2272            change_list: ChangeList::new(),
 2273            mode,
 2274            selection_drag_state: SelectionDragState::None,
 2275            folding_newlines: Task::ready(()),
 2276            lookup_key: None,
 2277        };
 2278
 2279        if is_minimap {
 2280            return editor;
 2281        }
 2282
 2283        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2284            editor
 2285                ._subscriptions
 2286                .push(cx.observe(breakpoints, |_, _, cx| {
 2287                    cx.notify();
 2288                }));
 2289        }
 2290        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2291        editor._subscriptions.extend(project_subscriptions);
 2292
 2293        editor._subscriptions.push(cx.subscribe_in(
 2294            &cx.entity(),
 2295            window,
 2296            |editor, _, e: &EditorEvent, window, cx| match e {
 2297                EditorEvent::ScrollPositionChanged { local, .. } => {
 2298                    if *local {
 2299                        let new_anchor = editor.scroll_manager.anchor();
 2300                        let snapshot = editor.snapshot(window, cx);
 2301                        editor.update_restoration_data(cx, move |data| {
 2302                            data.scroll_position = (
 2303                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2304                                new_anchor.offset,
 2305                            );
 2306                        });
 2307                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2308                        editor.inline_blame_popover.take();
 2309                    }
 2310                }
 2311                EditorEvent::Edited { .. } => {
 2312                    if !vim_enabled(cx) {
 2313                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2314                        let pop_state = editor
 2315                            .change_list
 2316                            .last()
 2317                            .map(|previous| {
 2318                                previous.len() == selections.len()
 2319                                    && previous.iter().enumerate().all(|(ix, p)| {
 2320                                        p.to_display_point(&map).row()
 2321                                            == selections[ix].head().row()
 2322                                    })
 2323                            })
 2324                            .unwrap_or(false);
 2325                        let new_positions = selections
 2326                            .into_iter()
 2327                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2328                            .collect();
 2329                        editor
 2330                            .change_list
 2331                            .push_to_change_list(pop_state, new_positions);
 2332                    }
 2333                }
 2334                _ => (),
 2335            },
 2336        ));
 2337
 2338        if let Some(dap_store) = editor
 2339            .project
 2340            .as_ref()
 2341            .map(|project| project.read(cx).dap_store())
 2342        {
 2343            let weak_editor = cx.weak_entity();
 2344
 2345            editor
 2346                ._subscriptions
 2347                .push(
 2348                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2349                        let session_entity = cx.entity();
 2350                        weak_editor
 2351                            .update(cx, |editor, cx| {
 2352                                editor._subscriptions.push(
 2353                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2354                                );
 2355                            })
 2356                            .ok();
 2357                    }),
 2358                );
 2359
 2360            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2361                editor
 2362                    ._subscriptions
 2363                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2364            }
 2365        }
 2366
 2367        // skip adding the initial selection to selection history
 2368        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2369        editor.end_selection(window, cx);
 2370        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2371
 2372        editor.scroll_manager.show_scrollbars(window, cx);
 2373        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2374
 2375        if full_mode {
 2376            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2377            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2378
 2379            if editor.git_blame_inline_enabled {
 2380                editor.start_git_blame_inline(false, window, cx);
 2381            }
 2382
 2383            editor.go_to_active_debug_line(window, cx);
 2384
 2385            if let Some(buffer) = buffer.read(cx).as_singleton()
 2386                && let Some(project) = editor.project()
 2387            {
 2388                let handle = project.update(cx, |project, cx| {
 2389                    project.register_buffer_with_language_servers(&buffer, cx)
 2390                });
 2391                editor
 2392                    .registered_buffers
 2393                    .insert(buffer.read(cx).remote_id(), handle);
 2394            }
 2395
 2396            editor.minimap =
 2397                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2398            editor.colors = Some(LspColorData::new(cx));
 2399            editor.update_lsp_data(false, None, window, cx);
 2400        }
 2401
 2402        if editor.mode.is_full() {
 2403            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2404        }
 2405
 2406        editor
 2407    }
 2408
 2409    pub fn deploy_mouse_context_menu(
 2410        &mut self,
 2411        position: gpui::Point<Pixels>,
 2412        context_menu: Entity<ContextMenu>,
 2413        window: &mut Window,
 2414        cx: &mut Context<Self>,
 2415    ) {
 2416        self.mouse_context_menu = Some(MouseContextMenu::new(
 2417            self,
 2418            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2419            context_menu,
 2420            window,
 2421            cx,
 2422        ));
 2423    }
 2424
 2425    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2426        self.mouse_context_menu
 2427            .as_ref()
 2428            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2429    }
 2430
 2431    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2432        if self
 2433            .selections
 2434            .pending_anchor()
 2435            .is_some_and(|pending_selection| {
 2436                let snapshot = self.buffer().read(cx).snapshot(cx);
 2437                pending_selection.range().includes(range, &snapshot)
 2438            })
 2439        {
 2440            return true;
 2441        }
 2442
 2443        self.selections
 2444            .disjoint_in_range::<usize>(range.clone(), cx)
 2445            .into_iter()
 2446            .any(|selection| {
 2447                // This is needed to cover a corner case, if we just check for an existing
 2448                // selection in the fold range, having a cursor at the start of the fold
 2449                // marks it as selected. Non-empty selections don't cause this.
 2450                let length = selection.end - selection.start;
 2451                length > 0
 2452            })
 2453    }
 2454
 2455    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2456        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2457    }
 2458
 2459    fn key_context_internal(
 2460        &self,
 2461        has_active_edit_prediction: bool,
 2462        window: &Window,
 2463        cx: &App,
 2464    ) -> KeyContext {
 2465        let mut key_context = KeyContext::new_with_defaults();
 2466        key_context.add("Editor");
 2467        let mode = match self.mode {
 2468            EditorMode::SingleLine => "single_line",
 2469            EditorMode::AutoHeight { .. } => "auto_height",
 2470            EditorMode::Minimap { .. } => "minimap",
 2471            EditorMode::Full { .. } => "full",
 2472        };
 2473
 2474        if EditorSettings::jupyter_enabled(cx) {
 2475            key_context.add("jupyter");
 2476        }
 2477
 2478        key_context.set("mode", mode);
 2479        if self.pending_rename.is_some() {
 2480            key_context.add("renaming");
 2481        }
 2482
 2483        match self.context_menu.borrow().as_ref() {
 2484            Some(CodeContextMenu::Completions(menu)) => {
 2485                if menu.visible() {
 2486                    key_context.add("menu");
 2487                    key_context.add("showing_completions");
 2488                }
 2489            }
 2490            Some(CodeContextMenu::CodeActions(menu)) => {
 2491                if menu.visible() {
 2492                    key_context.add("menu");
 2493                    key_context.add("showing_code_actions")
 2494                }
 2495            }
 2496            None => {}
 2497        }
 2498
 2499        if self.signature_help_state.has_multiple_signatures() {
 2500            key_context.add("showing_signature_help");
 2501        }
 2502
 2503        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2504        if !self.focus_handle(cx).contains_focused(window, cx)
 2505            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2506        {
 2507            for addon in self.addons.values() {
 2508                addon.extend_key_context(&mut key_context, cx)
 2509            }
 2510        }
 2511
 2512        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2513            if let Some(extension) = singleton_buffer
 2514                .read(cx)
 2515                .file()
 2516                .and_then(|file| file.path().extension())
 2517            {
 2518                key_context.set("extension", extension.to_string());
 2519            }
 2520        } else {
 2521            key_context.add("multibuffer");
 2522        }
 2523
 2524        if has_active_edit_prediction {
 2525            if self.edit_prediction_in_conflict() {
 2526                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2527            } else {
 2528                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2529                key_context.add("copilot_suggestion");
 2530            }
 2531        }
 2532
 2533        if self.selection_mark_mode {
 2534            key_context.add("selection_mode");
 2535        }
 2536
 2537        key_context
 2538    }
 2539
 2540    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2541        self.last_bounds.as_ref()
 2542    }
 2543
 2544    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2545        if self.mouse_cursor_hidden {
 2546            self.mouse_cursor_hidden = false;
 2547            cx.notify();
 2548        }
 2549    }
 2550
 2551    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2552        let hide_mouse_cursor = match origin {
 2553            HideMouseCursorOrigin::TypingAction => {
 2554                matches!(
 2555                    self.hide_mouse_mode,
 2556                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2557                )
 2558            }
 2559            HideMouseCursorOrigin::MovementAction => {
 2560                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2561            }
 2562        };
 2563        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2564            self.mouse_cursor_hidden = hide_mouse_cursor;
 2565            cx.notify();
 2566        }
 2567    }
 2568
 2569    pub fn edit_prediction_in_conflict(&self) -> bool {
 2570        if !self.show_edit_predictions_in_menu() {
 2571            return false;
 2572        }
 2573
 2574        let showing_completions = self
 2575            .context_menu
 2576            .borrow()
 2577            .as_ref()
 2578            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2579
 2580        showing_completions
 2581            || self.edit_prediction_requires_modifier()
 2582            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2583            // bindings to insert tab characters.
 2584            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2585    }
 2586
 2587    pub fn accept_edit_prediction_keybind(
 2588        &self,
 2589        accept_partial: bool,
 2590        window: &Window,
 2591        cx: &App,
 2592    ) -> AcceptEditPredictionBinding {
 2593        let key_context = self.key_context_internal(true, window, cx);
 2594        let in_conflict = self.edit_prediction_in_conflict();
 2595
 2596        let bindings = if accept_partial {
 2597            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2598        } else {
 2599            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2600        };
 2601
 2602        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2603        // just the first one.
 2604        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2605            !in_conflict
 2606                || binding
 2607                    .keystrokes()
 2608                    .first()
 2609                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2610        }))
 2611    }
 2612
 2613    pub fn new_file(
 2614        workspace: &mut Workspace,
 2615        _: &workspace::NewFile,
 2616        window: &mut Window,
 2617        cx: &mut Context<Workspace>,
 2618    ) {
 2619        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2620            "Failed to create buffer",
 2621            window,
 2622            cx,
 2623            |e, _, _| match e.error_code() {
 2624                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2625                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2626                e.error_tag("required").unwrap_or("the latest version")
 2627            )),
 2628                _ => None,
 2629            },
 2630        );
 2631    }
 2632
 2633    pub fn new_in_workspace(
 2634        workspace: &mut Workspace,
 2635        window: &mut Window,
 2636        cx: &mut Context<Workspace>,
 2637    ) -> Task<Result<Entity<Editor>>> {
 2638        let project = workspace.project().clone();
 2639        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2640
 2641        cx.spawn_in(window, async move |workspace, cx| {
 2642            let buffer = create.await?;
 2643            workspace.update_in(cx, |workspace, window, cx| {
 2644                let editor =
 2645                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2646                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2647                editor
 2648            })
 2649        })
 2650    }
 2651
 2652    fn new_file_vertical(
 2653        workspace: &mut Workspace,
 2654        _: &workspace::NewFileSplitVertical,
 2655        window: &mut Window,
 2656        cx: &mut Context<Workspace>,
 2657    ) {
 2658        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2659    }
 2660
 2661    fn new_file_horizontal(
 2662        workspace: &mut Workspace,
 2663        _: &workspace::NewFileSplitHorizontal,
 2664        window: &mut Window,
 2665        cx: &mut Context<Workspace>,
 2666    ) {
 2667        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2668    }
 2669
 2670    fn new_file_in_direction(
 2671        workspace: &mut Workspace,
 2672        direction: SplitDirection,
 2673        window: &mut Window,
 2674        cx: &mut Context<Workspace>,
 2675    ) {
 2676        let project = workspace.project().clone();
 2677        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2678
 2679        cx.spawn_in(window, async move |workspace, cx| {
 2680            let buffer = create.await?;
 2681            workspace.update_in(cx, move |workspace, window, cx| {
 2682                workspace.split_item(
 2683                    direction,
 2684                    Box::new(
 2685                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2686                    ),
 2687                    window,
 2688                    cx,
 2689                )
 2690            })?;
 2691            anyhow::Ok(())
 2692        })
 2693        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2694            match e.error_code() {
 2695                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2696                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2697                e.error_tag("required").unwrap_or("the latest version")
 2698            )),
 2699                _ => None,
 2700            }
 2701        });
 2702    }
 2703
 2704    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2705        self.leader_id
 2706    }
 2707
 2708    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2709        &self.buffer
 2710    }
 2711
 2712    pub fn project(&self) -> Option<&Entity<Project>> {
 2713        self.project.as_ref()
 2714    }
 2715
 2716    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2717        self.workspace.as_ref()?.0.upgrade()
 2718    }
 2719
 2720    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2721        self.buffer().read(cx).title(cx)
 2722    }
 2723
 2724    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2725        let git_blame_gutter_max_author_length = self
 2726            .render_git_blame_gutter(cx)
 2727            .then(|| {
 2728                if let Some(blame) = self.blame.as_ref() {
 2729                    let max_author_length =
 2730                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2731                    Some(max_author_length)
 2732                } else {
 2733                    None
 2734                }
 2735            })
 2736            .flatten();
 2737
 2738        EditorSnapshot {
 2739            mode: self.mode.clone(),
 2740            show_gutter: self.show_gutter,
 2741            show_line_numbers: self.show_line_numbers,
 2742            show_git_diff_gutter: self.show_git_diff_gutter,
 2743            show_code_actions: self.show_code_actions,
 2744            show_runnables: self.show_runnables,
 2745            show_breakpoints: self.show_breakpoints,
 2746            git_blame_gutter_max_author_length,
 2747            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2748            placeholder_display_snapshot: self
 2749                .placeholder_display_map
 2750                .as_ref()
 2751                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2752            scroll_anchor: self.scroll_manager.anchor(),
 2753            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2754            is_focused: self.focus_handle.is_focused(window),
 2755            current_line_highlight: self
 2756                .current_line_highlight
 2757                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2758            gutter_hovered: self.gutter_hovered,
 2759        }
 2760    }
 2761
 2762    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2763        self.buffer.read(cx).language_at(point, cx)
 2764    }
 2765
 2766    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2767        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2768    }
 2769
 2770    pub fn active_excerpt(
 2771        &self,
 2772        cx: &App,
 2773    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2774        self.buffer
 2775            .read(cx)
 2776            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2777    }
 2778
 2779    pub fn mode(&self) -> &EditorMode {
 2780        &self.mode
 2781    }
 2782
 2783    pub fn set_mode(&mut self, mode: EditorMode) {
 2784        self.mode = mode;
 2785    }
 2786
 2787    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2788        self.collaboration_hub.as_deref()
 2789    }
 2790
 2791    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2792        self.collaboration_hub = Some(hub);
 2793    }
 2794
 2795    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2796        self.in_project_search = in_project_search;
 2797    }
 2798
 2799    pub fn set_custom_context_menu(
 2800        &mut self,
 2801        f: impl 'static
 2802        + Fn(
 2803            &mut Self,
 2804            DisplayPoint,
 2805            &mut Window,
 2806            &mut Context<Self>,
 2807        ) -> Option<Entity<ui::ContextMenu>>,
 2808    ) {
 2809        self.custom_context_menu = Some(Box::new(f))
 2810    }
 2811
 2812    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2813        self.completion_provider = provider;
 2814    }
 2815
 2816    #[cfg(any(test, feature = "test-support"))]
 2817    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2818        self.completion_provider.clone()
 2819    }
 2820
 2821    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2822        self.semantics_provider.clone()
 2823    }
 2824
 2825    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2826        self.semantics_provider = provider;
 2827    }
 2828
 2829    pub fn set_edit_prediction_provider<T>(
 2830        &mut self,
 2831        provider: Option<Entity<T>>,
 2832        window: &mut Window,
 2833        cx: &mut Context<Self>,
 2834    ) where
 2835        T: EditPredictionProvider,
 2836    {
 2837        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2838            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2839                if this.focus_handle.is_focused(window) {
 2840                    this.update_visible_edit_prediction(window, cx);
 2841                }
 2842            }),
 2843            provider: Arc::new(provider),
 2844        });
 2845        self.update_edit_prediction_settings(cx);
 2846        self.refresh_edit_prediction(false, false, window, cx);
 2847    }
 2848
 2849    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2850        self.placeholder_display_map
 2851            .as_ref()
 2852            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2853    }
 2854
 2855    pub fn set_placeholder_text(
 2856        &mut self,
 2857        placeholder_text: &str,
 2858        window: &mut Window,
 2859        cx: &mut Context<Self>,
 2860    ) {
 2861        let multibuffer = cx
 2862            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2863
 2864        let style = window.text_style();
 2865
 2866        self.placeholder_display_map = Some(cx.new(|cx| {
 2867            DisplayMap::new(
 2868                multibuffer,
 2869                style.font(),
 2870                style.font_size.to_pixels(window.rem_size()),
 2871                None,
 2872                FILE_HEADER_HEIGHT,
 2873                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2874                Default::default(),
 2875                DiagnosticSeverity::Off,
 2876                cx,
 2877            )
 2878        }));
 2879        cx.notify();
 2880    }
 2881
 2882    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2883        self.cursor_shape = cursor_shape;
 2884
 2885        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2886        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2887
 2888        cx.notify();
 2889    }
 2890
 2891    pub fn set_current_line_highlight(
 2892        &mut self,
 2893        current_line_highlight: Option<CurrentLineHighlight>,
 2894    ) {
 2895        self.current_line_highlight = current_line_highlight;
 2896    }
 2897
 2898    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2899        self.collapse_matches = collapse_matches;
 2900    }
 2901
 2902    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2903        let buffers = self.buffer.read(cx).all_buffers();
 2904        let Some(project) = self.project.as_ref() else {
 2905            return;
 2906        };
 2907        project.update(cx, |project, cx| {
 2908            for buffer in buffers {
 2909                self.registered_buffers
 2910                    .entry(buffer.read(cx).remote_id())
 2911                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2912            }
 2913        })
 2914    }
 2915
 2916    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2917        if self.collapse_matches {
 2918            return range.start..range.start;
 2919        }
 2920        range.clone()
 2921    }
 2922
 2923    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2924        if self.display_map.read(cx).clip_at_line_ends != clip {
 2925            self.display_map
 2926                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2927        }
 2928    }
 2929
 2930    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2931        self.input_enabled = input_enabled;
 2932    }
 2933
 2934    pub fn set_edit_predictions_hidden_for_vim_mode(
 2935        &mut self,
 2936        hidden: bool,
 2937        window: &mut Window,
 2938        cx: &mut Context<Self>,
 2939    ) {
 2940        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2941            self.edit_predictions_hidden_for_vim_mode = hidden;
 2942            if hidden {
 2943                self.update_visible_edit_prediction(window, cx);
 2944            } else {
 2945                self.refresh_edit_prediction(true, false, window, cx);
 2946            }
 2947        }
 2948    }
 2949
 2950    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2951        self.menu_edit_predictions_policy = value;
 2952    }
 2953
 2954    pub fn set_autoindent(&mut self, autoindent: bool) {
 2955        if autoindent {
 2956            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2957        } else {
 2958            self.autoindent_mode = None;
 2959        }
 2960    }
 2961
 2962    pub fn read_only(&self, cx: &App) -> bool {
 2963        self.read_only || self.buffer.read(cx).read_only()
 2964    }
 2965
 2966    pub fn set_read_only(&mut self, read_only: bool) {
 2967        self.read_only = read_only;
 2968    }
 2969
 2970    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2971        self.use_autoclose = autoclose;
 2972    }
 2973
 2974    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2975        self.use_auto_surround = auto_surround;
 2976    }
 2977
 2978    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2979        self.auto_replace_emoji_shortcode = auto_replace;
 2980    }
 2981
 2982    pub fn toggle_edit_predictions(
 2983        &mut self,
 2984        _: &ToggleEditPrediction,
 2985        window: &mut Window,
 2986        cx: &mut Context<Self>,
 2987    ) {
 2988        if self.show_edit_predictions_override.is_some() {
 2989            self.set_show_edit_predictions(None, window, cx);
 2990        } else {
 2991            let show_edit_predictions = !self.edit_predictions_enabled();
 2992            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2993        }
 2994    }
 2995
 2996    pub fn set_show_edit_predictions(
 2997        &mut self,
 2998        show_edit_predictions: Option<bool>,
 2999        window: &mut Window,
 3000        cx: &mut Context<Self>,
 3001    ) {
 3002        self.show_edit_predictions_override = show_edit_predictions;
 3003        self.update_edit_prediction_settings(cx);
 3004
 3005        if let Some(false) = show_edit_predictions {
 3006            self.discard_edit_prediction(false, cx);
 3007        } else {
 3008            self.refresh_edit_prediction(false, true, window, cx);
 3009        }
 3010    }
 3011
 3012    fn edit_predictions_disabled_in_scope(
 3013        &self,
 3014        buffer: &Entity<Buffer>,
 3015        buffer_position: language::Anchor,
 3016        cx: &App,
 3017    ) -> bool {
 3018        let snapshot = buffer.read(cx).snapshot();
 3019        let settings = snapshot.settings_at(buffer_position, cx);
 3020
 3021        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3022            return false;
 3023        };
 3024
 3025        scope.override_name().is_some_and(|scope_name| {
 3026            settings
 3027                .edit_predictions_disabled_in
 3028                .iter()
 3029                .any(|s| s == scope_name)
 3030        })
 3031    }
 3032
 3033    pub fn set_use_modal_editing(&mut self, to: bool) {
 3034        self.use_modal_editing = to;
 3035    }
 3036
 3037    pub fn use_modal_editing(&self) -> bool {
 3038        self.use_modal_editing
 3039    }
 3040
 3041    fn selections_did_change(
 3042        &mut self,
 3043        local: bool,
 3044        old_cursor_position: &Anchor,
 3045        effects: SelectionEffects,
 3046        window: &mut Window,
 3047        cx: &mut Context<Self>,
 3048    ) {
 3049        window.invalidate_character_coordinates();
 3050
 3051        // Copy selections to primary selection buffer
 3052        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3053        if local {
 3054            let selections = self.selections.all::<usize>(cx);
 3055            let buffer_handle = self.buffer.read(cx).read(cx);
 3056
 3057            let mut text = String::new();
 3058            for (index, selection) in selections.iter().enumerate() {
 3059                let text_for_selection = buffer_handle
 3060                    .text_for_range(selection.start..selection.end)
 3061                    .collect::<String>();
 3062
 3063                text.push_str(&text_for_selection);
 3064                if index != selections.len() - 1 {
 3065                    text.push('\n');
 3066                }
 3067            }
 3068
 3069            if !text.is_empty() {
 3070                cx.write_to_primary(ClipboardItem::new_string(text));
 3071            }
 3072        }
 3073
 3074        let selection_anchors = self.selections.disjoint_anchors_arc();
 3075
 3076        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3077            self.buffer.update(cx, |buffer, cx| {
 3078                buffer.set_active_selections(
 3079                    &selection_anchors,
 3080                    self.selections.line_mode(),
 3081                    self.cursor_shape,
 3082                    cx,
 3083                )
 3084            });
 3085        }
 3086        let display_map = self
 3087            .display_map
 3088            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3089        let buffer = display_map.buffer_snapshot();
 3090        if self.selections.count() == 1 {
 3091            self.add_selections_state = None;
 3092        }
 3093        self.select_next_state = None;
 3094        self.select_prev_state = None;
 3095        self.select_syntax_node_history.try_clear();
 3096        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3097        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3098        self.take_rename(false, window, cx);
 3099
 3100        let newest_selection = self.selections.newest_anchor();
 3101        let new_cursor_position = newest_selection.head();
 3102        let selection_start = newest_selection.start;
 3103
 3104        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3105            self.push_to_nav_history(
 3106                *old_cursor_position,
 3107                Some(new_cursor_position.to_point(buffer)),
 3108                false,
 3109                effects.nav_history == Some(true),
 3110                cx,
 3111            );
 3112        }
 3113
 3114        if local {
 3115            if let Some(buffer_id) = new_cursor_position.buffer_id
 3116                && !self.registered_buffers.contains_key(&buffer_id)
 3117                && let Some(project) = self.project.as_ref()
 3118            {
 3119                project.update(cx, |project, cx| {
 3120                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3121                        return;
 3122                    };
 3123                    self.registered_buffers.insert(
 3124                        buffer_id,
 3125                        project.register_buffer_with_language_servers(&buffer, cx),
 3126                    );
 3127                })
 3128            }
 3129
 3130            let mut context_menu = self.context_menu.borrow_mut();
 3131            let completion_menu = match context_menu.as_ref() {
 3132                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3133                Some(CodeContextMenu::CodeActions(_)) => {
 3134                    *context_menu = None;
 3135                    None
 3136                }
 3137                None => None,
 3138            };
 3139            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3140            drop(context_menu);
 3141
 3142            if effects.completions
 3143                && let Some(completion_position) = completion_position
 3144            {
 3145                let start_offset = selection_start.to_offset(buffer);
 3146                let position_matches = start_offset == completion_position.to_offset(buffer);
 3147                let continue_showing = if position_matches {
 3148                    if self.snippet_stack.is_empty() {
 3149                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3150                            == Some(CharKind::Word)
 3151                    } else {
 3152                        // Snippet choices can be shown even when the cursor is in whitespace.
 3153                        // Dismissing the menu with actions like backspace is handled by
 3154                        // invalidation regions.
 3155                        true
 3156                    }
 3157                } else {
 3158                    false
 3159                };
 3160
 3161                if continue_showing {
 3162                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3163                } else {
 3164                    self.hide_context_menu(window, cx);
 3165                }
 3166            }
 3167
 3168            hide_hover(self, cx);
 3169
 3170            if old_cursor_position.to_display_point(&display_map).row()
 3171                != new_cursor_position.to_display_point(&display_map).row()
 3172            {
 3173                self.available_code_actions.take();
 3174            }
 3175            self.refresh_code_actions(window, cx);
 3176            self.refresh_document_highlights(cx);
 3177            self.refresh_selected_text_highlights(false, window, cx);
 3178            refresh_matching_bracket_highlights(self, cx);
 3179            self.update_visible_edit_prediction(window, cx);
 3180            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3181            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3182            self.inline_blame_popover.take();
 3183            if self.git_blame_inline_enabled {
 3184                self.start_inline_blame_timer(window, cx);
 3185            }
 3186        }
 3187
 3188        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3189        cx.emit(EditorEvent::SelectionsChanged { local });
 3190
 3191        let selections = &self.selections.disjoint_anchors_arc();
 3192        if selections.len() == 1 {
 3193            cx.emit(SearchEvent::ActiveMatchChanged)
 3194        }
 3195        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3196            let inmemory_selections = selections
 3197                .iter()
 3198                .map(|s| {
 3199                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3200                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3201                })
 3202                .collect();
 3203            self.update_restoration_data(cx, |data| {
 3204                data.selections = inmemory_selections;
 3205            });
 3206
 3207            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3208                && let Some(workspace_id) =
 3209                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3210            {
 3211                let snapshot = self.buffer().read(cx).snapshot(cx);
 3212                let selections = selections.clone();
 3213                let background_executor = cx.background_executor().clone();
 3214                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3215                self.serialize_selections = cx.background_spawn(async move {
 3216                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3217                    let db_selections = selections
 3218                        .iter()
 3219                        .map(|selection| {
 3220                            (
 3221                                selection.start.to_offset(&snapshot),
 3222                                selection.end.to_offset(&snapshot),
 3223                            )
 3224                        })
 3225                        .collect();
 3226
 3227                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3228                        .await
 3229                        .with_context(|| {
 3230                            format!(
 3231                                "persisting editor selections for editor {editor_id}, \
 3232                                workspace {workspace_id:?}"
 3233                            )
 3234                        })
 3235                        .log_err();
 3236                });
 3237            }
 3238        }
 3239
 3240        cx.notify();
 3241    }
 3242
 3243    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3244        use text::ToOffset as _;
 3245        use text::ToPoint as _;
 3246
 3247        if self.mode.is_minimap()
 3248            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3249        {
 3250            return;
 3251        }
 3252
 3253        if !self.buffer().read(cx).is_singleton() {
 3254            return;
 3255        }
 3256
 3257        let display_snapshot = self
 3258            .display_map
 3259            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3260        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3261            return;
 3262        };
 3263        let inmemory_folds = display_snapshot
 3264            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3265            .map(|fold| {
 3266                fold.range.start.text_anchor.to_point(&snapshot)
 3267                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3268            })
 3269            .collect();
 3270        self.update_restoration_data(cx, |data| {
 3271            data.folds = inmemory_folds;
 3272        });
 3273
 3274        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3275            return;
 3276        };
 3277        let background_executor = cx.background_executor().clone();
 3278        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3279        let db_folds = display_snapshot
 3280            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3281            .map(|fold| {
 3282                (
 3283                    fold.range.start.text_anchor.to_offset(&snapshot),
 3284                    fold.range.end.text_anchor.to_offset(&snapshot),
 3285                )
 3286            })
 3287            .collect();
 3288        self.serialize_folds = cx.background_spawn(async move {
 3289            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3290            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3291                .await
 3292                .with_context(|| {
 3293                    format!(
 3294                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3295                    )
 3296                })
 3297                .log_err();
 3298        });
 3299    }
 3300
 3301    pub fn sync_selections(
 3302        &mut self,
 3303        other: Entity<Editor>,
 3304        cx: &mut Context<Self>,
 3305    ) -> gpui::Subscription {
 3306        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3307        if !other_selections.is_empty() {
 3308            self.selections.change_with(cx, |selections| {
 3309                selections.select_anchors(other_selections);
 3310            });
 3311        }
 3312
 3313        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3314            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3315                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3316                if other_selections.is_empty() {
 3317                    return;
 3318                }
 3319                this.selections.change_with(cx, |selections| {
 3320                    selections.select_anchors(other_selections);
 3321                });
 3322            }
 3323        });
 3324
 3325        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3326            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3327                let these_selections = this.selections.disjoint_anchors().to_vec();
 3328                if these_selections.is_empty() {
 3329                    return;
 3330                }
 3331                other.update(cx, |other_editor, cx| {
 3332                    other_editor.selections.change_with(cx, |selections| {
 3333                        selections.select_anchors(these_selections);
 3334                    })
 3335                });
 3336            }
 3337        });
 3338
 3339        Subscription::join(other_subscription, this_subscription)
 3340    }
 3341
 3342    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3343    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3344    /// effects of selection change occur at the end of the transaction.
 3345    pub fn change_selections<R>(
 3346        &mut self,
 3347        effects: SelectionEffects,
 3348        window: &mut Window,
 3349        cx: &mut Context<Self>,
 3350        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3351    ) -> R {
 3352        if let Some(state) = &mut self.deferred_selection_effects_state {
 3353            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3354            state.effects.completions = effects.completions;
 3355            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3356            let (changed, result) = self.selections.change_with(cx, change);
 3357            state.changed |= changed;
 3358            return result;
 3359        }
 3360        let mut state = DeferredSelectionEffectsState {
 3361            changed: false,
 3362            effects,
 3363            old_cursor_position: self.selections.newest_anchor().head(),
 3364            history_entry: SelectionHistoryEntry {
 3365                selections: self.selections.disjoint_anchors_arc(),
 3366                select_next_state: self.select_next_state.clone(),
 3367                select_prev_state: self.select_prev_state.clone(),
 3368                add_selections_state: self.add_selections_state.clone(),
 3369            },
 3370        };
 3371        let (changed, result) = self.selections.change_with(cx, change);
 3372        state.changed = state.changed || changed;
 3373        if self.defer_selection_effects {
 3374            self.deferred_selection_effects_state = Some(state);
 3375        } else {
 3376            self.apply_selection_effects(state, window, cx);
 3377        }
 3378        result
 3379    }
 3380
 3381    /// Defers the effects of selection change, so that the effects of multiple calls to
 3382    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3383    /// to selection history and the state of popovers based on selection position aren't
 3384    /// erroneously updated.
 3385    pub fn with_selection_effects_deferred<R>(
 3386        &mut self,
 3387        window: &mut Window,
 3388        cx: &mut Context<Self>,
 3389        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3390    ) -> R {
 3391        let already_deferred = self.defer_selection_effects;
 3392        self.defer_selection_effects = true;
 3393        let result = update(self, window, cx);
 3394        if !already_deferred {
 3395            self.defer_selection_effects = false;
 3396            if let Some(state) = self.deferred_selection_effects_state.take() {
 3397                self.apply_selection_effects(state, window, cx);
 3398            }
 3399        }
 3400        result
 3401    }
 3402
 3403    fn apply_selection_effects(
 3404        &mut self,
 3405        state: DeferredSelectionEffectsState,
 3406        window: &mut Window,
 3407        cx: &mut Context<Self>,
 3408    ) {
 3409        if state.changed {
 3410            self.selection_history.push(state.history_entry);
 3411
 3412            if let Some(autoscroll) = state.effects.scroll {
 3413                self.request_autoscroll(autoscroll, cx);
 3414            }
 3415
 3416            let old_cursor_position = &state.old_cursor_position;
 3417
 3418            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3419
 3420            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3421                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3422            }
 3423        }
 3424    }
 3425
 3426    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3427    where
 3428        I: IntoIterator<Item = (Range<S>, T)>,
 3429        S: ToOffset,
 3430        T: Into<Arc<str>>,
 3431    {
 3432        if self.read_only(cx) {
 3433            return;
 3434        }
 3435
 3436        self.buffer
 3437            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3438    }
 3439
 3440    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3441    where
 3442        I: IntoIterator<Item = (Range<S>, T)>,
 3443        S: ToOffset,
 3444        T: Into<Arc<str>>,
 3445    {
 3446        if self.read_only(cx) {
 3447            return;
 3448        }
 3449
 3450        self.buffer.update(cx, |buffer, cx| {
 3451            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3452        });
 3453    }
 3454
 3455    pub fn edit_with_block_indent<I, S, T>(
 3456        &mut self,
 3457        edits: I,
 3458        original_indent_columns: Vec<Option<u32>>,
 3459        cx: &mut Context<Self>,
 3460    ) where
 3461        I: IntoIterator<Item = (Range<S>, T)>,
 3462        S: ToOffset,
 3463        T: Into<Arc<str>>,
 3464    {
 3465        if self.read_only(cx) {
 3466            return;
 3467        }
 3468
 3469        self.buffer.update(cx, |buffer, cx| {
 3470            buffer.edit(
 3471                edits,
 3472                Some(AutoindentMode::Block {
 3473                    original_indent_columns,
 3474                }),
 3475                cx,
 3476            )
 3477        });
 3478    }
 3479
 3480    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3481        self.hide_context_menu(window, cx);
 3482
 3483        match phase {
 3484            SelectPhase::Begin {
 3485                position,
 3486                add,
 3487                click_count,
 3488            } => self.begin_selection(position, add, click_count, window, cx),
 3489            SelectPhase::BeginColumnar {
 3490                position,
 3491                goal_column,
 3492                reset,
 3493                mode,
 3494            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3495            SelectPhase::Extend {
 3496                position,
 3497                click_count,
 3498            } => self.extend_selection(position, click_count, window, cx),
 3499            SelectPhase::Update {
 3500                position,
 3501                goal_column,
 3502                scroll_delta,
 3503            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3504            SelectPhase::End => self.end_selection(window, cx),
 3505        }
 3506    }
 3507
 3508    fn extend_selection(
 3509        &mut self,
 3510        position: DisplayPoint,
 3511        click_count: usize,
 3512        window: &mut Window,
 3513        cx: &mut Context<Self>,
 3514    ) {
 3515        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3516        let tail = self.selections.newest::<usize>(cx).tail();
 3517        let click_count = click_count.max(match self.selections.select_mode() {
 3518            SelectMode::Character => 1,
 3519            SelectMode::Word(_) => 2,
 3520            SelectMode::Line(_) => 3,
 3521            SelectMode::All => 4,
 3522        });
 3523        self.begin_selection(position, false, click_count, window, cx);
 3524
 3525        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3526
 3527        let current_selection = match self.selections.select_mode() {
 3528            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3529            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3530        };
 3531
 3532        let mut pending_selection = self
 3533            .selections
 3534            .pending_anchor()
 3535            .cloned()
 3536            .expect("extend_selection not called with pending selection");
 3537
 3538        if pending_selection
 3539            .start
 3540            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3541            == Ordering::Greater
 3542        {
 3543            pending_selection.start = current_selection.start;
 3544        }
 3545        if pending_selection
 3546            .end
 3547            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3548            == Ordering::Less
 3549        {
 3550            pending_selection.end = current_selection.end;
 3551            pending_selection.reversed = true;
 3552        }
 3553
 3554        let mut pending_mode = self.selections.pending_mode().unwrap();
 3555        match &mut pending_mode {
 3556            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3557            _ => {}
 3558        }
 3559
 3560        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3561            SelectionEffects::scroll(Autoscroll::fit())
 3562        } else {
 3563            SelectionEffects::no_scroll()
 3564        };
 3565
 3566        self.change_selections(effects, window, cx, |s| {
 3567            s.set_pending(pending_selection.clone(), pending_mode);
 3568            s.set_is_extending(true);
 3569        });
 3570    }
 3571
 3572    fn begin_selection(
 3573        &mut self,
 3574        position: DisplayPoint,
 3575        add: bool,
 3576        click_count: usize,
 3577        window: &mut Window,
 3578        cx: &mut Context<Self>,
 3579    ) {
 3580        if !self.focus_handle.is_focused(window) {
 3581            self.last_focused_descendant = None;
 3582            window.focus(&self.focus_handle);
 3583        }
 3584
 3585        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3586        let buffer = display_map.buffer_snapshot();
 3587        let position = display_map.clip_point(position, Bias::Left);
 3588
 3589        let start;
 3590        let end;
 3591        let mode;
 3592        let mut auto_scroll;
 3593        match click_count {
 3594            1 => {
 3595                start = buffer.anchor_before(position.to_point(&display_map));
 3596                end = start;
 3597                mode = SelectMode::Character;
 3598                auto_scroll = true;
 3599            }
 3600            2 => {
 3601                let position = display_map
 3602                    .clip_point(position, Bias::Left)
 3603                    .to_offset(&display_map, Bias::Left);
 3604                let (range, _) = buffer.surrounding_word(position, None);
 3605                start = buffer.anchor_before(range.start);
 3606                end = buffer.anchor_before(range.end);
 3607                mode = SelectMode::Word(start..end);
 3608                auto_scroll = true;
 3609            }
 3610            3 => {
 3611                let position = display_map
 3612                    .clip_point(position, Bias::Left)
 3613                    .to_point(&display_map);
 3614                let line_start = display_map.prev_line_boundary(position).0;
 3615                let next_line_start = buffer.clip_point(
 3616                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3617                    Bias::Left,
 3618                );
 3619                start = buffer.anchor_before(line_start);
 3620                end = buffer.anchor_before(next_line_start);
 3621                mode = SelectMode::Line(start..end);
 3622                auto_scroll = true;
 3623            }
 3624            _ => {
 3625                start = buffer.anchor_before(0);
 3626                end = buffer.anchor_before(buffer.len());
 3627                mode = SelectMode::All;
 3628                auto_scroll = false;
 3629            }
 3630        }
 3631        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3632
 3633        let point_to_delete: Option<usize> = {
 3634            let selected_points: Vec<Selection<Point>> =
 3635                self.selections.disjoint_in_range(start..end, cx);
 3636
 3637            if !add || click_count > 1 {
 3638                None
 3639            } else if !selected_points.is_empty() {
 3640                Some(selected_points[0].id)
 3641            } else {
 3642                let clicked_point_already_selected =
 3643                    self.selections.disjoint_anchors().iter().find(|selection| {
 3644                        selection.start.to_point(buffer) == start.to_point(buffer)
 3645                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3646                    });
 3647
 3648                clicked_point_already_selected.map(|selection| selection.id)
 3649            }
 3650        };
 3651
 3652        let selections_count = self.selections.count();
 3653        let effects = if auto_scroll {
 3654            SelectionEffects::default()
 3655        } else {
 3656            SelectionEffects::no_scroll()
 3657        };
 3658
 3659        self.change_selections(effects, window, cx, |s| {
 3660            if let Some(point_to_delete) = point_to_delete {
 3661                s.delete(point_to_delete);
 3662
 3663                if selections_count == 1 {
 3664                    s.set_pending_anchor_range(start..end, mode);
 3665                }
 3666            } else {
 3667                if !add {
 3668                    s.clear_disjoint();
 3669                }
 3670
 3671                s.set_pending_anchor_range(start..end, mode);
 3672            }
 3673        });
 3674    }
 3675
 3676    fn begin_columnar_selection(
 3677        &mut self,
 3678        position: DisplayPoint,
 3679        goal_column: u32,
 3680        reset: bool,
 3681        mode: ColumnarMode,
 3682        window: &mut Window,
 3683        cx: &mut Context<Self>,
 3684    ) {
 3685        if !self.focus_handle.is_focused(window) {
 3686            self.last_focused_descendant = None;
 3687            window.focus(&self.focus_handle);
 3688        }
 3689
 3690        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3691
 3692        if reset {
 3693            let pointer_position = display_map
 3694                .buffer_snapshot()
 3695                .anchor_before(position.to_point(&display_map));
 3696
 3697            self.change_selections(
 3698                SelectionEffects::scroll(Autoscroll::newest()),
 3699                window,
 3700                cx,
 3701                |s| {
 3702                    s.clear_disjoint();
 3703                    s.set_pending_anchor_range(
 3704                        pointer_position..pointer_position,
 3705                        SelectMode::Character,
 3706                    );
 3707                },
 3708            );
 3709        };
 3710
 3711        let tail = self.selections.newest::<Point>(cx).tail();
 3712        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3713        self.columnar_selection_state = match mode {
 3714            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3715                selection_tail: selection_anchor,
 3716                display_point: if reset {
 3717                    if position.column() != goal_column {
 3718                        Some(DisplayPoint::new(position.row(), goal_column))
 3719                    } else {
 3720                        None
 3721                    }
 3722                } else {
 3723                    None
 3724                },
 3725            }),
 3726            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3727                selection_tail: selection_anchor,
 3728            }),
 3729        };
 3730
 3731        if !reset {
 3732            self.select_columns(position, goal_column, &display_map, window, cx);
 3733        }
 3734    }
 3735
 3736    fn update_selection(
 3737        &mut self,
 3738        position: DisplayPoint,
 3739        goal_column: u32,
 3740        scroll_delta: gpui::Point<f32>,
 3741        window: &mut Window,
 3742        cx: &mut Context<Self>,
 3743    ) {
 3744        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3745
 3746        if self.columnar_selection_state.is_some() {
 3747            self.select_columns(position, goal_column, &display_map, window, cx);
 3748        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3749            let buffer = display_map.buffer_snapshot();
 3750            let head;
 3751            let tail;
 3752            let mode = self.selections.pending_mode().unwrap();
 3753            match &mode {
 3754                SelectMode::Character => {
 3755                    head = position.to_point(&display_map);
 3756                    tail = pending.tail().to_point(buffer);
 3757                }
 3758                SelectMode::Word(original_range) => {
 3759                    let offset = display_map
 3760                        .clip_point(position, Bias::Left)
 3761                        .to_offset(&display_map, Bias::Left);
 3762                    let original_range = original_range.to_offset(buffer);
 3763
 3764                    let head_offset = if buffer.is_inside_word(offset, None)
 3765                        || original_range.contains(&offset)
 3766                    {
 3767                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3768                        if word_range.start < original_range.start {
 3769                            word_range.start
 3770                        } else {
 3771                            word_range.end
 3772                        }
 3773                    } else {
 3774                        offset
 3775                    };
 3776
 3777                    head = head_offset.to_point(buffer);
 3778                    if head_offset <= original_range.start {
 3779                        tail = original_range.end.to_point(buffer);
 3780                    } else {
 3781                        tail = original_range.start.to_point(buffer);
 3782                    }
 3783                }
 3784                SelectMode::Line(original_range) => {
 3785                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3786
 3787                    let position = display_map
 3788                        .clip_point(position, Bias::Left)
 3789                        .to_point(&display_map);
 3790                    let line_start = display_map.prev_line_boundary(position).0;
 3791                    let next_line_start = buffer.clip_point(
 3792                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3793                        Bias::Left,
 3794                    );
 3795
 3796                    if line_start < original_range.start {
 3797                        head = line_start
 3798                    } else {
 3799                        head = next_line_start
 3800                    }
 3801
 3802                    if head <= original_range.start {
 3803                        tail = original_range.end;
 3804                    } else {
 3805                        tail = original_range.start;
 3806                    }
 3807                }
 3808                SelectMode::All => {
 3809                    return;
 3810                }
 3811            };
 3812
 3813            if head < tail {
 3814                pending.start = buffer.anchor_before(head);
 3815                pending.end = buffer.anchor_before(tail);
 3816                pending.reversed = true;
 3817            } else {
 3818                pending.start = buffer.anchor_before(tail);
 3819                pending.end = buffer.anchor_before(head);
 3820                pending.reversed = false;
 3821            }
 3822
 3823            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3824                s.set_pending(pending.clone(), mode);
 3825            });
 3826        } else {
 3827            log::error!("update_selection dispatched with no pending selection");
 3828            return;
 3829        }
 3830
 3831        self.apply_scroll_delta(scroll_delta, window, cx);
 3832        cx.notify();
 3833    }
 3834
 3835    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3836        self.columnar_selection_state.take();
 3837        if let Some(pending_mode) = self.selections.pending_mode() {
 3838            let selections = self.selections.all::<usize>(cx);
 3839            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3840                s.select(selections);
 3841                s.clear_pending();
 3842                if s.is_extending() {
 3843                    s.set_is_extending(false);
 3844                } else {
 3845                    s.set_select_mode(pending_mode);
 3846                }
 3847            });
 3848        }
 3849    }
 3850
 3851    fn select_columns(
 3852        &mut self,
 3853        head: DisplayPoint,
 3854        goal_column: u32,
 3855        display_map: &DisplaySnapshot,
 3856        window: &mut Window,
 3857        cx: &mut Context<Self>,
 3858    ) {
 3859        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3860            return;
 3861        };
 3862
 3863        let tail = match columnar_state {
 3864            ColumnarSelectionState::FromMouse {
 3865                selection_tail,
 3866                display_point,
 3867            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3868            ColumnarSelectionState::FromSelection { selection_tail } => {
 3869                selection_tail.to_display_point(display_map)
 3870            }
 3871        };
 3872
 3873        let start_row = cmp::min(tail.row(), head.row());
 3874        let end_row = cmp::max(tail.row(), head.row());
 3875        let start_column = cmp::min(tail.column(), goal_column);
 3876        let end_column = cmp::max(tail.column(), goal_column);
 3877        let reversed = start_column < tail.column();
 3878
 3879        let selection_ranges = (start_row.0..=end_row.0)
 3880            .map(DisplayRow)
 3881            .filter_map(|row| {
 3882                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3883                    || start_column <= display_map.line_len(row))
 3884                    && !display_map.is_block_line(row)
 3885                {
 3886                    let start = display_map
 3887                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3888                        .to_point(display_map);
 3889                    let end = display_map
 3890                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3891                        .to_point(display_map);
 3892                    if reversed {
 3893                        Some(end..start)
 3894                    } else {
 3895                        Some(start..end)
 3896                    }
 3897                } else {
 3898                    None
 3899                }
 3900            })
 3901            .collect::<Vec<_>>();
 3902        if selection_ranges.is_empty() {
 3903            return;
 3904        }
 3905
 3906        let ranges = match columnar_state {
 3907            ColumnarSelectionState::FromMouse { .. } => {
 3908                let mut non_empty_ranges = selection_ranges
 3909                    .iter()
 3910                    .filter(|selection_range| selection_range.start != selection_range.end)
 3911                    .peekable();
 3912                if non_empty_ranges.peek().is_some() {
 3913                    non_empty_ranges.cloned().collect()
 3914                } else {
 3915                    selection_ranges
 3916                }
 3917            }
 3918            _ => selection_ranges,
 3919        };
 3920
 3921        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3922            s.select_ranges(ranges);
 3923        });
 3924        cx.notify();
 3925    }
 3926
 3927    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3928        self.selections
 3929            .all_adjusted(cx)
 3930            .iter()
 3931            .any(|selection| !selection.is_empty())
 3932    }
 3933
 3934    pub fn has_pending_nonempty_selection(&self) -> bool {
 3935        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3936            Some(Selection { start, end, .. }) => start != end,
 3937            None => false,
 3938        };
 3939
 3940        pending_nonempty_selection
 3941            || (self.columnar_selection_state.is_some()
 3942                && self.selections.disjoint_anchors().len() > 1)
 3943    }
 3944
 3945    pub fn has_pending_selection(&self) -> bool {
 3946        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3947    }
 3948
 3949    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3950        self.selection_mark_mode = false;
 3951        self.selection_drag_state = SelectionDragState::None;
 3952
 3953        if self.clear_expanded_diff_hunks(cx) {
 3954            cx.notify();
 3955            return;
 3956        }
 3957        if self.dismiss_menus_and_popups(true, window, cx) {
 3958            return;
 3959        }
 3960
 3961        if self.mode.is_full()
 3962            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3963        {
 3964            return;
 3965        }
 3966
 3967        cx.propagate();
 3968    }
 3969
 3970    pub fn dismiss_menus_and_popups(
 3971        &mut self,
 3972        is_user_requested: bool,
 3973        window: &mut Window,
 3974        cx: &mut Context<Self>,
 3975    ) -> bool {
 3976        if self.take_rename(false, window, cx).is_some() {
 3977            return true;
 3978        }
 3979
 3980        if hide_hover(self, cx) {
 3981            return true;
 3982        }
 3983
 3984        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3985            return true;
 3986        }
 3987
 3988        if self.hide_context_menu(window, cx).is_some() {
 3989            return true;
 3990        }
 3991
 3992        if self.mouse_context_menu.take().is_some() {
 3993            return true;
 3994        }
 3995
 3996        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3997            return true;
 3998        }
 3999
 4000        if self.snippet_stack.pop().is_some() {
 4001            return true;
 4002        }
 4003
 4004        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4005            self.dismiss_diagnostics(cx);
 4006            return true;
 4007        }
 4008
 4009        false
 4010    }
 4011
 4012    fn linked_editing_ranges_for(
 4013        &self,
 4014        selection: Range<text::Anchor>,
 4015        cx: &App,
 4016    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4017        if self.linked_edit_ranges.is_empty() {
 4018            return None;
 4019        }
 4020        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4021            selection.end.buffer_id.and_then(|end_buffer_id| {
 4022                if selection.start.buffer_id != Some(end_buffer_id) {
 4023                    return None;
 4024                }
 4025                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4026                let snapshot = buffer.read(cx).snapshot();
 4027                self.linked_edit_ranges
 4028                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4029                    .map(|ranges| (ranges, snapshot, buffer))
 4030            })?;
 4031        use text::ToOffset as TO;
 4032        // find offset from the start of current range to current cursor position
 4033        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4034
 4035        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4036        let start_difference = start_offset - start_byte_offset;
 4037        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4038        let end_difference = end_offset - start_byte_offset;
 4039        // Current range has associated linked ranges.
 4040        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4041        for range in linked_ranges.iter() {
 4042            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4043            let end_offset = start_offset + end_difference;
 4044            let start_offset = start_offset + start_difference;
 4045            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4046                continue;
 4047            }
 4048            if self.selections.disjoint_anchor_ranges().any(|s| {
 4049                if s.start.buffer_id != selection.start.buffer_id
 4050                    || s.end.buffer_id != selection.end.buffer_id
 4051                {
 4052                    return false;
 4053                }
 4054                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4055                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4056            }) {
 4057                continue;
 4058            }
 4059            let start = buffer_snapshot.anchor_after(start_offset);
 4060            let end = buffer_snapshot.anchor_after(end_offset);
 4061            linked_edits
 4062                .entry(buffer.clone())
 4063                .or_default()
 4064                .push(start..end);
 4065        }
 4066        Some(linked_edits)
 4067    }
 4068
 4069    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4070        let text: Arc<str> = text.into();
 4071
 4072        if self.read_only(cx) {
 4073            return;
 4074        }
 4075
 4076        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4077
 4078        let selections = self.selections.all_adjusted(cx);
 4079        let mut bracket_inserted = false;
 4080        let mut edits = Vec::new();
 4081        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4082        let mut new_selections = Vec::with_capacity(selections.len());
 4083        let mut new_autoclose_regions = Vec::new();
 4084        let snapshot = self.buffer.read(cx).read(cx);
 4085        let mut clear_linked_edit_ranges = false;
 4086
 4087        for (selection, autoclose_region) in
 4088            self.selections_with_autoclose_regions(selections, &snapshot)
 4089        {
 4090            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4091                // Determine if the inserted text matches the opening or closing
 4092                // bracket of any of this language's bracket pairs.
 4093                let mut bracket_pair = None;
 4094                let mut is_bracket_pair_start = false;
 4095                let mut is_bracket_pair_end = false;
 4096                if !text.is_empty() {
 4097                    let mut bracket_pair_matching_end = None;
 4098                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4099                    //  and they are removing the character that triggered IME popup.
 4100                    for (pair, enabled) in scope.brackets() {
 4101                        if !pair.close && !pair.surround {
 4102                            continue;
 4103                        }
 4104
 4105                        if enabled && pair.start.ends_with(text.as_ref()) {
 4106                            let prefix_len = pair.start.len() - text.len();
 4107                            let preceding_text_matches_prefix = prefix_len == 0
 4108                                || (selection.start.column >= (prefix_len as u32)
 4109                                    && snapshot.contains_str_at(
 4110                                        Point::new(
 4111                                            selection.start.row,
 4112                                            selection.start.column - (prefix_len as u32),
 4113                                        ),
 4114                                        &pair.start[..prefix_len],
 4115                                    ));
 4116                            if preceding_text_matches_prefix {
 4117                                bracket_pair = Some(pair.clone());
 4118                                is_bracket_pair_start = true;
 4119                                break;
 4120                            }
 4121                        }
 4122                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4123                        {
 4124                            // take first bracket pair matching end, but don't break in case a later bracket
 4125                            // pair matches start
 4126                            bracket_pair_matching_end = Some(pair.clone());
 4127                        }
 4128                    }
 4129                    if let Some(end) = bracket_pair_matching_end
 4130                        && bracket_pair.is_none()
 4131                    {
 4132                        bracket_pair = Some(end);
 4133                        is_bracket_pair_end = true;
 4134                    }
 4135                }
 4136
 4137                if let Some(bracket_pair) = bracket_pair {
 4138                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4139                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4140                    let auto_surround =
 4141                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4142                    if selection.is_empty() {
 4143                        if is_bracket_pair_start {
 4144                            // If the inserted text is a suffix of an opening bracket and the
 4145                            // selection is preceded by the rest of the opening bracket, then
 4146                            // insert the closing bracket.
 4147                            let following_text_allows_autoclose = snapshot
 4148                                .chars_at(selection.start)
 4149                                .next()
 4150                                .is_none_or(|c| scope.should_autoclose_before(c));
 4151
 4152                            let preceding_text_allows_autoclose = selection.start.column == 0
 4153                                || snapshot
 4154                                    .reversed_chars_at(selection.start)
 4155                                    .next()
 4156                                    .is_none_or(|c| {
 4157                                        bracket_pair.start != bracket_pair.end
 4158                                            || !snapshot
 4159                                                .char_classifier_at(selection.start)
 4160                                                .is_word(c)
 4161                                    });
 4162
 4163                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4164                                && bracket_pair.start.len() == 1
 4165                            {
 4166                                let target = bracket_pair.start.chars().next().unwrap();
 4167                                let current_line_count = snapshot
 4168                                    .reversed_chars_at(selection.start)
 4169                                    .take_while(|&c| c != '\n')
 4170                                    .filter(|&c| c == target)
 4171                                    .count();
 4172                                current_line_count % 2 == 1
 4173                            } else {
 4174                                false
 4175                            };
 4176
 4177                            if autoclose
 4178                                && bracket_pair.close
 4179                                && following_text_allows_autoclose
 4180                                && preceding_text_allows_autoclose
 4181                                && !is_closing_quote
 4182                            {
 4183                                let anchor = snapshot.anchor_before(selection.end);
 4184                                new_selections.push((selection.map(|_| anchor), text.len()));
 4185                                new_autoclose_regions.push((
 4186                                    anchor,
 4187                                    text.len(),
 4188                                    selection.id,
 4189                                    bracket_pair.clone(),
 4190                                ));
 4191                                edits.push((
 4192                                    selection.range(),
 4193                                    format!("{}{}", text, bracket_pair.end).into(),
 4194                                ));
 4195                                bracket_inserted = true;
 4196                                continue;
 4197                            }
 4198                        }
 4199
 4200                        if let Some(region) = autoclose_region {
 4201                            // If the selection is followed by an auto-inserted closing bracket,
 4202                            // then don't insert that closing bracket again; just move the selection
 4203                            // past the closing bracket.
 4204                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4205                                && text.as_ref() == region.pair.end.as_str()
 4206                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4207                            if should_skip {
 4208                                let anchor = snapshot.anchor_after(selection.end);
 4209                                new_selections
 4210                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4211                                continue;
 4212                            }
 4213                        }
 4214
 4215                        let always_treat_brackets_as_autoclosed = snapshot
 4216                            .language_settings_at(selection.start, cx)
 4217                            .always_treat_brackets_as_autoclosed;
 4218                        if always_treat_brackets_as_autoclosed
 4219                            && is_bracket_pair_end
 4220                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4221                        {
 4222                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4223                            // and the inserted text is a closing bracket and the selection is followed
 4224                            // by the closing bracket then move the selection past the closing bracket.
 4225                            let anchor = snapshot.anchor_after(selection.end);
 4226                            new_selections.push((selection.map(|_| anchor), text.len()));
 4227                            continue;
 4228                        }
 4229                    }
 4230                    // If an opening bracket is 1 character long and is typed while
 4231                    // text is selected, then surround that text with the bracket pair.
 4232                    else if auto_surround
 4233                        && bracket_pair.surround
 4234                        && is_bracket_pair_start
 4235                        && bracket_pair.start.chars().count() == 1
 4236                    {
 4237                        edits.push((selection.start..selection.start, text.clone()));
 4238                        edits.push((
 4239                            selection.end..selection.end,
 4240                            bracket_pair.end.as_str().into(),
 4241                        ));
 4242                        bracket_inserted = true;
 4243                        new_selections.push((
 4244                            Selection {
 4245                                id: selection.id,
 4246                                start: snapshot.anchor_after(selection.start),
 4247                                end: snapshot.anchor_before(selection.end),
 4248                                reversed: selection.reversed,
 4249                                goal: selection.goal,
 4250                            },
 4251                            0,
 4252                        ));
 4253                        continue;
 4254                    }
 4255                }
 4256            }
 4257
 4258            if self.auto_replace_emoji_shortcode
 4259                && selection.is_empty()
 4260                && text.as_ref().ends_with(':')
 4261                && let Some(possible_emoji_short_code) =
 4262                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4263                && !possible_emoji_short_code.is_empty()
 4264                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4265            {
 4266                let emoji_shortcode_start = Point::new(
 4267                    selection.start.row,
 4268                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4269                );
 4270
 4271                // Remove shortcode from buffer
 4272                edits.push((
 4273                    emoji_shortcode_start..selection.start,
 4274                    "".to_string().into(),
 4275                ));
 4276                new_selections.push((
 4277                    Selection {
 4278                        id: selection.id,
 4279                        start: snapshot.anchor_after(emoji_shortcode_start),
 4280                        end: snapshot.anchor_before(selection.start),
 4281                        reversed: selection.reversed,
 4282                        goal: selection.goal,
 4283                    },
 4284                    0,
 4285                ));
 4286
 4287                // Insert emoji
 4288                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4289                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4290                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4291
 4292                continue;
 4293            }
 4294
 4295            // If not handling any auto-close operation, then just replace the selected
 4296            // text with the given input and move the selection to the end of the
 4297            // newly inserted text.
 4298            let anchor = snapshot.anchor_after(selection.end);
 4299            if !self.linked_edit_ranges.is_empty() {
 4300                let start_anchor = snapshot.anchor_before(selection.start);
 4301
 4302                let is_word_char = text.chars().next().is_none_or(|char| {
 4303                    let classifier = snapshot
 4304                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4305                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4306                    classifier.is_word(char)
 4307                });
 4308
 4309                if is_word_char {
 4310                    if let Some(ranges) = self
 4311                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4312                    {
 4313                        for (buffer, edits) in ranges {
 4314                            linked_edits
 4315                                .entry(buffer.clone())
 4316                                .or_default()
 4317                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4318                        }
 4319                    }
 4320                } else {
 4321                    clear_linked_edit_ranges = true;
 4322                }
 4323            }
 4324
 4325            new_selections.push((selection.map(|_| anchor), 0));
 4326            edits.push((selection.start..selection.end, text.clone()));
 4327        }
 4328
 4329        drop(snapshot);
 4330
 4331        self.transact(window, cx, |this, window, cx| {
 4332            if clear_linked_edit_ranges {
 4333                this.linked_edit_ranges.clear();
 4334            }
 4335            let initial_buffer_versions =
 4336                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4337
 4338            this.buffer.update(cx, |buffer, cx| {
 4339                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4340            });
 4341            for (buffer, edits) in linked_edits {
 4342                buffer.update(cx, |buffer, cx| {
 4343                    let snapshot = buffer.snapshot();
 4344                    let edits = edits
 4345                        .into_iter()
 4346                        .map(|(range, text)| {
 4347                            use text::ToPoint as TP;
 4348                            let end_point = TP::to_point(&range.end, &snapshot);
 4349                            let start_point = TP::to_point(&range.start, &snapshot);
 4350                            (start_point..end_point, text)
 4351                        })
 4352                        .sorted_by_key(|(range, _)| range.start);
 4353                    buffer.edit(edits, None, cx);
 4354                })
 4355            }
 4356            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4357            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4358            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4359            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4360                .zip(new_selection_deltas)
 4361                .map(|(selection, delta)| Selection {
 4362                    id: selection.id,
 4363                    start: selection.start + delta,
 4364                    end: selection.end + delta,
 4365                    reversed: selection.reversed,
 4366                    goal: SelectionGoal::None,
 4367                })
 4368                .collect::<Vec<_>>();
 4369
 4370            let mut i = 0;
 4371            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4372                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4373                let start = map.buffer_snapshot().anchor_before(position);
 4374                let end = map.buffer_snapshot().anchor_after(position);
 4375                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4376                    match existing_state
 4377                        .range
 4378                        .start
 4379                        .cmp(&start, map.buffer_snapshot())
 4380                    {
 4381                        Ordering::Less => i += 1,
 4382                        Ordering::Greater => break,
 4383                        Ordering::Equal => {
 4384                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4385                                Ordering::Less => i += 1,
 4386                                Ordering::Equal => break,
 4387                                Ordering::Greater => break,
 4388                            }
 4389                        }
 4390                    }
 4391                }
 4392                this.autoclose_regions.insert(
 4393                    i,
 4394                    AutocloseRegion {
 4395                        selection_id,
 4396                        range: start..end,
 4397                        pair,
 4398                    },
 4399                );
 4400            }
 4401
 4402            let had_active_edit_prediction = this.has_active_edit_prediction();
 4403            this.change_selections(
 4404                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4405                window,
 4406                cx,
 4407                |s| s.select(new_selections),
 4408            );
 4409
 4410            if !bracket_inserted
 4411                && let Some(on_type_format_task) =
 4412                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4413            {
 4414                on_type_format_task.detach_and_log_err(cx);
 4415            }
 4416
 4417            let editor_settings = EditorSettings::get_global(cx);
 4418            if bracket_inserted
 4419                && (editor_settings.auto_signature_help
 4420                    || editor_settings.show_signature_help_after_edits)
 4421            {
 4422                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4423            }
 4424
 4425            let trigger_in_words =
 4426                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4427            if this.hard_wrap.is_some() {
 4428                let latest: Range<Point> = this.selections.newest(cx).range();
 4429                if latest.is_empty()
 4430                    && this
 4431                        .buffer()
 4432                        .read(cx)
 4433                        .snapshot(cx)
 4434                        .line_len(MultiBufferRow(latest.start.row))
 4435                        == latest.start.column
 4436                {
 4437                    this.rewrap_impl(
 4438                        RewrapOptions {
 4439                            override_language_settings: true,
 4440                            preserve_existing_whitespace: true,
 4441                        },
 4442                        cx,
 4443                    )
 4444                }
 4445            }
 4446            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4447            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4448            this.refresh_edit_prediction(true, false, window, cx);
 4449            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4450        });
 4451    }
 4452
 4453    fn find_possible_emoji_shortcode_at_position(
 4454        snapshot: &MultiBufferSnapshot,
 4455        position: Point,
 4456    ) -> Option<String> {
 4457        let mut chars = Vec::new();
 4458        let mut found_colon = false;
 4459        for char in snapshot.reversed_chars_at(position).take(100) {
 4460            // Found a possible emoji shortcode in the middle of the buffer
 4461            if found_colon {
 4462                if char.is_whitespace() {
 4463                    chars.reverse();
 4464                    return Some(chars.iter().collect());
 4465                }
 4466                // If the previous character is not a whitespace, we are in the middle of a word
 4467                // and we only want to complete the shortcode if the word is made up of other emojis
 4468                let mut containing_word = String::new();
 4469                for ch in snapshot
 4470                    .reversed_chars_at(position)
 4471                    .skip(chars.len() + 1)
 4472                    .take(100)
 4473                {
 4474                    if ch.is_whitespace() {
 4475                        break;
 4476                    }
 4477                    containing_word.push(ch);
 4478                }
 4479                let containing_word = containing_word.chars().rev().collect::<String>();
 4480                if util::word_consists_of_emojis(containing_word.as_str()) {
 4481                    chars.reverse();
 4482                    return Some(chars.iter().collect());
 4483                }
 4484            }
 4485
 4486            if char.is_whitespace() || !char.is_ascii() {
 4487                return None;
 4488            }
 4489            if char == ':' {
 4490                found_colon = true;
 4491            } else {
 4492                chars.push(char);
 4493            }
 4494        }
 4495        // Found a possible emoji shortcode at the beginning of the buffer
 4496        chars.reverse();
 4497        Some(chars.iter().collect())
 4498    }
 4499
 4500    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4501        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4502        self.transact(window, cx, |this, window, cx| {
 4503            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4504                let selections = this.selections.all::<usize>(cx);
 4505                let multi_buffer = this.buffer.read(cx);
 4506                let buffer = multi_buffer.snapshot(cx);
 4507                selections
 4508                    .iter()
 4509                    .map(|selection| {
 4510                        let start_point = selection.start.to_point(&buffer);
 4511                        let mut existing_indent =
 4512                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4513                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4514                        let start = selection.start;
 4515                        let end = selection.end;
 4516                        let selection_is_empty = start == end;
 4517                        let language_scope = buffer.language_scope_at(start);
 4518                        let (
 4519                            comment_delimiter,
 4520                            doc_delimiter,
 4521                            insert_extra_newline,
 4522                            indent_on_newline,
 4523                            indent_on_extra_newline,
 4524                        ) = if let Some(language) = &language_scope {
 4525                            let mut insert_extra_newline =
 4526                                insert_extra_newline_brackets(&buffer, start..end, language)
 4527                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4528
 4529                            // Comment extension on newline is allowed only for cursor selections
 4530                            let comment_delimiter = maybe!({
 4531                                if !selection_is_empty {
 4532                                    return None;
 4533                                }
 4534
 4535                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4536                                    return None;
 4537                                }
 4538
 4539                                let delimiters = language.line_comment_prefixes();
 4540                                let max_len_of_delimiter =
 4541                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4542                                let (snapshot, range) =
 4543                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4544
 4545                                let num_of_whitespaces = snapshot
 4546                                    .chars_for_range(range.clone())
 4547                                    .take_while(|c| c.is_whitespace())
 4548                                    .count();
 4549                                let comment_candidate = snapshot
 4550                                    .chars_for_range(range.clone())
 4551                                    .skip(num_of_whitespaces)
 4552                                    .take(max_len_of_delimiter)
 4553                                    .collect::<String>();
 4554                                let (delimiter, trimmed_len) = delimiters
 4555                                    .iter()
 4556                                    .filter_map(|delimiter| {
 4557                                        let prefix = delimiter.trim_end();
 4558                                        if comment_candidate.starts_with(prefix) {
 4559                                            Some((delimiter, prefix.len()))
 4560                                        } else {
 4561                                            None
 4562                                        }
 4563                                    })
 4564                                    .max_by_key(|(_, len)| *len)?;
 4565
 4566                                if let Some(BlockCommentConfig {
 4567                                    start: block_start, ..
 4568                                }) = language.block_comment()
 4569                                {
 4570                                    let block_start_trimmed = block_start.trim_end();
 4571                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4572                                        let line_content = snapshot
 4573                                            .chars_for_range(range)
 4574                                            .skip(num_of_whitespaces)
 4575                                            .take(block_start_trimmed.len())
 4576                                            .collect::<String>();
 4577
 4578                                        if line_content.starts_with(block_start_trimmed) {
 4579                                            return None;
 4580                                        }
 4581                                    }
 4582                                }
 4583
 4584                                let cursor_is_placed_after_comment_marker =
 4585                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4586                                if cursor_is_placed_after_comment_marker {
 4587                                    Some(delimiter.clone())
 4588                                } else {
 4589                                    None
 4590                                }
 4591                            });
 4592
 4593                            let mut indent_on_newline = IndentSize::spaces(0);
 4594                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4595
 4596                            let doc_delimiter = maybe!({
 4597                                if !selection_is_empty {
 4598                                    return None;
 4599                                }
 4600
 4601                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4602                                    return None;
 4603                                }
 4604
 4605                                let BlockCommentConfig {
 4606                                    start: start_tag,
 4607                                    end: end_tag,
 4608                                    prefix: delimiter,
 4609                                    tab_size: len,
 4610                                } = language.documentation_comment()?;
 4611                                let is_within_block_comment = buffer
 4612                                    .language_scope_at(start_point)
 4613                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4614                                if !is_within_block_comment {
 4615                                    return None;
 4616                                }
 4617
 4618                                let (snapshot, range) =
 4619                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4620
 4621                                let num_of_whitespaces = snapshot
 4622                                    .chars_for_range(range.clone())
 4623                                    .take_while(|c| c.is_whitespace())
 4624                                    .count();
 4625
 4626                                // 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.
 4627                                let column = start_point.column;
 4628                                let cursor_is_after_start_tag = {
 4629                                    let start_tag_len = start_tag.len();
 4630                                    let start_tag_line = snapshot
 4631                                        .chars_for_range(range.clone())
 4632                                        .skip(num_of_whitespaces)
 4633                                        .take(start_tag_len)
 4634                                        .collect::<String>();
 4635                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4636                                        num_of_whitespaces + start_tag_len <= column as usize
 4637                                    } else {
 4638                                        false
 4639                                    }
 4640                                };
 4641
 4642                                let cursor_is_after_delimiter = {
 4643                                    let delimiter_trim = delimiter.trim_end();
 4644                                    let delimiter_line = snapshot
 4645                                        .chars_for_range(range.clone())
 4646                                        .skip(num_of_whitespaces)
 4647                                        .take(delimiter_trim.len())
 4648                                        .collect::<String>();
 4649                                    if delimiter_line.starts_with(delimiter_trim) {
 4650                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4651                                    } else {
 4652                                        false
 4653                                    }
 4654                                };
 4655
 4656                                let cursor_is_before_end_tag_if_exists = {
 4657                                    let mut char_position = 0u32;
 4658                                    let mut end_tag_offset = None;
 4659
 4660                                    'outer: for chunk in snapshot.text_for_range(range) {
 4661                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4662                                            let chars_before_match =
 4663                                                chunk[..byte_pos].chars().count() as u32;
 4664                                            end_tag_offset =
 4665                                                Some(char_position + chars_before_match);
 4666                                            break 'outer;
 4667                                        }
 4668                                        char_position += chunk.chars().count() as u32;
 4669                                    }
 4670
 4671                                    if let Some(end_tag_offset) = end_tag_offset {
 4672                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4673                                        if cursor_is_after_start_tag {
 4674                                            if cursor_is_before_end_tag {
 4675                                                insert_extra_newline = true;
 4676                                            }
 4677                                            let cursor_is_at_start_of_end_tag =
 4678                                                column == end_tag_offset;
 4679                                            if cursor_is_at_start_of_end_tag {
 4680                                                indent_on_extra_newline.len = *len;
 4681                                            }
 4682                                        }
 4683                                        cursor_is_before_end_tag
 4684                                    } else {
 4685                                        true
 4686                                    }
 4687                                };
 4688
 4689                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4690                                    && cursor_is_before_end_tag_if_exists
 4691                                {
 4692                                    if cursor_is_after_start_tag {
 4693                                        indent_on_newline.len = *len;
 4694                                    }
 4695                                    Some(delimiter.clone())
 4696                                } else {
 4697                                    None
 4698                                }
 4699                            });
 4700
 4701                            (
 4702                                comment_delimiter,
 4703                                doc_delimiter,
 4704                                insert_extra_newline,
 4705                                indent_on_newline,
 4706                                indent_on_extra_newline,
 4707                            )
 4708                        } else {
 4709                            (
 4710                                None,
 4711                                None,
 4712                                false,
 4713                                IndentSize::default(),
 4714                                IndentSize::default(),
 4715                            )
 4716                        };
 4717
 4718                        let prevent_auto_indent = doc_delimiter.is_some();
 4719                        let delimiter = comment_delimiter.or(doc_delimiter);
 4720
 4721                        let capacity_for_delimiter =
 4722                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4723                        let mut new_text = String::with_capacity(
 4724                            1 + capacity_for_delimiter
 4725                                + existing_indent.len as usize
 4726                                + indent_on_newline.len as usize
 4727                                + indent_on_extra_newline.len as usize,
 4728                        );
 4729                        new_text.push('\n');
 4730                        new_text.extend(existing_indent.chars());
 4731                        new_text.extend(indent_on_newline.chars());
 4732
 4733                        if let Some(delimiter) = &delimiter {
 4734                            new_text.push_str(delimiter);
 4735                        }
 4736
 4737                        if insert_extra_newline {
 4738                            new_text.push('\n');
 4739                            new_text.extend(existing_indent.chars());
 4740                            new_text.extend(indent_on_extra_newline.chars());
 4741                        }
 4742
 4743                        let anchor = buffer.anchor_after(end);
 4744                        let new_selection = selection.map(|_| anchor);
 4745                        (
 4746                            ((start..end, new_text), prevent_auto_indent),
 4747                            (insert_extra_newline, new_selection),
 4748                        )
 4749                    })
 4750                    .unzip()
 4751            };
 4752
 4753            let mut auto_indent_edits = Vec::new();
 4754            let mut edits = Vec::new();
 4755            for (edit, prevent_auto_indent) in edits_with_flags {
 4756                if prevent_auto_indent {
 4757                    edits.push(edit);
 4758                } else {
 4759                    auto_indent_edits.push(edit);
 4760                }
 4761            }
 4762            if !edits.is_empty() {
 4763                this.edit(edits, cx);
 4764            }
 4765            if !auto_indent_edits.is_empty() {
 4766                this.edit_with_autoindent(auto_indent_edits, cx);
 4767            }
 4768
 4769            let buffer = this.buffer.read(cx).snapshot(cx);
 4770            let new_selections = selection_info
 4771                .into_iter()
 4772                .map(|(extra_newline_inserted, new_selection)| {
 4773                    let mut cursor = new_selection.end.to_point(&buffer);
 4774                    if extra_newline_inserted {
 4775                        cursor.row -= 1;
 4776                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4777                    }
 4778                    new_selection.map(|_| cursor)
 4779                })
 4780                .collect();
 4781
 4782            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4783            this.refresh_edit_prediction(true, false, window, cx);
 4784        });
 4785    }
 4786
 4787    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4788        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4789
 4790        let buffer = self.buffer.read(cx);
 4791        let snapshot = buffer.snapshot(cx);
 4792
 4793        let mut edits = Vec::new();
 4794        let mut rows = Vec::new();
 4795
 4796        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4797            let cursor = selection.head();
 4798            let row = cursor.row;
 4799
 4800            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4801
 4802            let newline = "\n".to_string();
 4803            edits.push((start_of_line..start_of_line, newline));
 4804
 4805            rows.push(row + rows_inserted as u32);
 4806        }
 4807
 4808        self.transact(window, cx, |editor, window, cx| {
 4809            editor.edit(edits, cx);
 4810
 4811            editor.change_selections(Default::default(), window, cx, |s| {
 4812                let mut index = 0;
 4813                s.move_cursors_with(|map, _, _| {
 4814                    let row = rows[index];
 4815                    index += 1;
 4816
 4817                    let point = Point::new(row, 0);
 4818                    let boundary = map.next_line_boundary(point).1;
 4819                    let clipped = map.clip_point(boundary, Bias::Left);
 4820
 4821                    (clipped, SelectionGoal::None)
 4822                });
 4823            });
 4824
 4825            let mut indent_edits = Vec::new();
 4826            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4827            for row in rows {
 4828                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4829                for (row, indent) in indents {
 4830                    if indent.len == 0 {
 4831                        continue;
 4832                    }
 4833
 4834                    let text = match indent.kind {
 4835                        IndentKind::Space => " ".repeat(indent.len as usize),
 4836                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4837                    };
 4838                    let point = Point::new(row.0, 0);
 4839                    indent_edits.push((point..point, text));
 4840                }
 4841            }
 4842            editor.edit(indent_edits, cx);
 4843        });
 4844    }
 4845
 4846    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4847        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4848
 4849        let buffer = self.buffer.read(cx);
 4850        let snapshot = buffer.snapshot(cx);
 4851
 4852        let mut edits = Vec::new();
 4853        let mut rows = Vec::new();
 4854        let mut rows_inserted = 0;
 4855
 4856        for selection in self.selections.all_adjusted(cx) {
 4857            let cursor = selection.head();
 4858            let row = cursor.row;
 4859
 4860            let point = Point::new(row + 1, 0);
 4861            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4862
 4863            let newline = "\n".to_string();
 4864            edits.push((start_of_line..start_of_line, newline));
 4865
 4866            rows_inserted += 1;
 4867            rows.push(row + rows_inserted);
 4868        }
 4869
 4870        self.transact(window, cx, |editor, window, cx| {
 4871            editor.edit(edits, cx);
 4872
 4873            editor.change_selections(Default::default(), window, cx, |s| {
 4874                let mut index = 0;
 4875                s.move_cursors_with(|map, _, _| {
 4876                    let row = rows[index];
 4877                    index += 1;
 4878
 4879                    let point = Point::new(row, 0);
 4880                    let boundary = map.next_line_boundary(point).1;
 4881                    let clipped = map.clip_point(boundary, Bias::Left);
 4882
 4883                    (clipped, SelectionGoal::None)
 4884                });
 4885            });
 4886
 4887            let mut indent_edits = Vec::new();
 4888            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4889            for row in rows {
 4890                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4891                for (row, indent) in indents {
 4892                    if indent.len == 0 {
 4893                        continue;
 4894                    }
 4895
 4896                    let text = match indent.kind {
 4897                        IndentKind::Space => " ".repeat(indent.len as usize),
 4898                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4899                    };
 4900                    let point = Point::new(row.0, 0);
 4901                    indent_edits.push((point..point, text));
 4902                }
 4903            }
 4904            editor.edit(indent_edits, cx);
 4905        });
 4906    }
 4907
 4908    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4909        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4910            original_indent_columns: Vec::new(),
 4911        });
 4912        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4913    }
 4914
 4915    fn insert_with_autoindent_mode(
 4916        &mut self,
 4917        text: &str,
 4918        autoindent_mode: Option<AutoindentMode>,
 4919        window: &mut Window,
 4920        cx: &mut Context<Self>,
 4921    ) {
 4922        if self.read_only(cx) {
 4923            return;
 4924        }
 4925
 4926        let text: Arc<str> = text.into();
 4927        self.transact(window, cx, |this, window, cx| {
 4928            let old_selections = this.selections.all_adjusted(cx);
 4929            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4930                let anchors = {
 4931                    let snapshot = buffer.read(cx);
 4932                    old_selections
 4933                        .iter()
 4934                        .map(|s| {
 4935                            let anchor = snapshot.anchor_after(s.head());
 4936                            s.map(|_| anchor)
 4937                        })
 4938                        .collect::<Vec<_>>()
 4939                };
 4940                buffer.edit(
 4941                    old_selections
 4942                        .iter()
 4943                        .map(|s| (s.start..s.end, text.clone())),
 4944                    autoindent_mode,
 4945                    cx,
 4946                );
 4947                anchors
 4948            });
 4949
 4950            this.change_selections(Default::default(), window, cx, |s| {
 4951                s.select_anchors(selection_anchors);
 4952            });
 4953
 4954            cx.notify();
 4955        });
 4956    }
 4957
 4958    fn trigger_completion_on_input(
 4959        &mut self,
 4960        text: &str,
 4961        trigger_in_words: bool,
 4962        window: &mut Window,
 4963        cx: &mut Context<Self>,
 4964    ) {
 4965        let completions_source = self
 4966            .context_menu
 4967            .borrow()
 4968            .as_ref()
 4969            .and_then(|menu| match menu {
 4970                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4971                CodeContextMenu::CodeActions(_) => None,
 4972            });
 4973
 4974        match completions_source {
 4975            Some(CompletionsMenuSource::Words { .. }) => {
 4976                self.open_or_update_completions_menu(
 4977                    Some(CompletionsMenuSource::Words {
 4978                        ignore_threshold: false,
 4979                    }),
 4980                    None,
 4981                    window,
 4982                    cx,
 4983                );
 4984            }
 4985            Some(CompletionsMenuSource::Normal)
 4986            | Some(CompletionsMenuSource::SnippetChoices)
 4987            | None
 4988                if self.is_completion_trigger(
 4989                    text,
 4990                    trigger_in_words,
 4991                    completions_source.is_some(),
 4992                    cx,
 4993                ) =>
 4994            {
 4995                self.show_completions(
 4996                    &ShowCompletions {
 4997                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4998                    },
 4999                    window,
 5000                    cx,
 5001                )
 5002            }
 5003            _ => {
 5004                self.hide_context_menu(window, cx);
 5005            }
 5006        }
 5007    }
 5008
 5009    fn is_completion_trigger(
 5010        &self,
 5011        text: &str,
 5012        trigger_in_words: bool,
 5013        menu_is_open: bool,
 5014        cx: &mut Context<Self>,
 5015    ) -> bool {
 5016        let position = self.selections.newest_anchor().head();
 5017        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 5018            return false;
 5019        };
 5020
 5021        if let Some(completion_provider) = &self.completion_provider {
 5022            completion_provider.is_completion_trigger(
 5023                &buffer,
 5024                position.text_anchor,
 5025                text,
 5026                trigger_in_words,
 5027                menu_is_open,
 5028                cx,
 5029            )
 5030        } else {
 5031            false
 5032        }
 5033    }
 5034
 5035    /// If any empty selections is touching the start of its innermost containing autoclose
 5036    /// region, expand it to select the brackets.
 5037    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5038        let selections = self.selections.all::<usize>(cx);
 5039        let buffer = self.buffer.read(cx).read(cx);
 5040        let new_selections = self
 5041            .selections_with_autoclose_regions(selections, &buffer)
 5042            .map(|(mut selection, region)| {
 5043                if !selection.is_empty() {
 5044                    return selection;
 5045                }
 5046
 5047                if let Some(region) = region {
 5048                    let mut range = region.range.to_offset(&buffer);
 5049                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5050                        range.start -= region.pair.start.len();
 5051                        if buffer.contains_str_at(range.start, &region.pair.start)
 5052                            && buffer.contains_str_at(range.end, &region.pair.end)
 5053                        {
 5054                            range.end += region.pair.end.len();
 5055                            selection.start = range.start;
 5056                            selection.end = range.end;
 5057
 5058                            return selection;
 5059                        }
 5060                    }
 5061                }
 5062
 5063                let always_treat_brackets_as_autoclosed = buffer
 5064                    .language_settings_at(selection.start, cx)
 5065                    .always_treat_brackets_as_autoclosed;
 5066
 5067                if !always_treat_brackets_as_autoclosed {
 5068                    return selection;
 5069                }
 5070
 5071                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5072                    for (pair, enabled) in scope.brackets() {
 5073                        if !enabled || !pair.close {
 5074                            continue;
 5075                        }
 5076
 5077                        if buffer.contains_str_at(selection.start, &pair.end) {
 5078                            let pair_start_len = pair.start.len();
 5079                            if buffer.contains_str_at(
 5080                                selection.start.saturating_sub(pair_start_len),
 5081                                &pair.start,
 5082                            ) {
 5083                                selection.start -= pair_start_len;
 5084                                selection.end += pair.end.len();
 5085
 5086                                return selection;
 5087                            }
 5088                        }
 5089                    }
 5090                }
 5091
 5092                selection
 5093            })
 5094            .collect();
 5095
 5096        drop(buffer);
 5097        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5098            selections.select(new_selections)
 5099        });
 5100    }
 5101
 5102    /// Iterate the given selections, and for each one, find the smallest surrounding
 5103    /// autoclose region. This uses the ordering of the selections and the autoclose
 5104    /// regions to avoid repeated comparisons.
 5105    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5106        &'a self,
 5107        selections: impl IntoIterator<Item = Selection<D>>,
 5108        buffer: &'a MultiBufferSnapshot,
 5109    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5110        let mut i = 0;
 5111        let mut regions = self.autoclose_regions.as_slice();
 5112        selections.into_iter().map(move |selection| {
 5113            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5114
 5115            let mut enclosing = None;
 5116            while let Some(pair_state) = regions.get(i) {
 5117                if pair_state.range.end.to_offset(buffer) < range.start {
 5118                    regions = &regions[i + 1..];
 5119                    i = 0;
 5120                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5121                    break;
 5122                } else {
 5123                    if pair_state.selection_id == selection.id {
 5124                        enclosing = Some(pair_state);
 5125                    }
 5126                    i += 1;
 5127                }
 5128            }
 5129
 5130            (selection, enclosing)
 5131        })
 5132    }
 5133
 5134    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5135    fn invalidate_autoclose_regions(
 5136        &mut self,
 5137        mut selections: &[Selection<Anchor>],
 5138        buffer: &MultiBufferSnapshot,
 5139    ) {
 5140        self.autoclose_regions.retain(|state| {
 5141            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5142                return false;
 5143            }
 5144
 5145            let mut i = 0;
 5146            while let Some(selection) = selections.get(i) {
 5147                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5148                    selections = &selections[1..];
 5149                    continue;
 5150                }
 5151                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5152                    break;
 5153                }
 5154                if selection.id == state.selection_id {
 5155                    return true;
 5156                } else {
 5157                    i += 1;
 5158                }
 5159            }
 5160            false
 5161        });
 5162    }
 5163
 5164    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5165        let offset = position.to_offset(buffer);
 5166        let (word_range, kind) =
 5167            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5168        if offset > word_range.start && kind == Some(CharKind::Word) {
 5169            Some(
 5170                buffer
 5171                    .text_for_range(word_range.start..offset)
 5172                    .collect::<String>(),
 5173            )
 5174        } else {
 5175            None
 5176        }
 5177    }
 5178
 5179    pub fn toggle_inline_values(
 5180        &mut self,
 5181        _: &ToggleInlineValues,
 5182        _: &mut Window,
 5183        cx: &mut Context<Self>,
 5184    ) {
 5185        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5186
 5187        self.refresh_inline_values(cx);
 5188    }
 5189
 5190    pub fn toggle_inlay_hints(
 5191        &mut self,
 5192        _: &ToggleInlayHints,
 5193        _: &mut Window,
 5194        cx: &mut Context<Self>,
 5195    ) {
 5196        self.refresh_inlay_hints(
 5197            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5198            cx,
 5199        );
 5200    }
 5201
 5202    pub fn inlay_hints_enabled(&self) -> bool {
 5203        self.inlay_hint_cache.enabled
 5204    }
 5205
 5206    pub fn inline_values_enabled(&self) -> bool {
 5207        self.inline_value_cache.enabled
 5208    }
 5209
 5210    #[cfg(any(test, feature = "test-support"))]
 5211    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5212        self.display_map
 5213            .read(cx)
 5214            .current_inlays()
 5215            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5216            .cloned()
 5217            .collect()
 5218    }
 5219
 5220    #[cfg(any(test, feature = "test-support"))]
 5221    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5222        self.display_map
 5223            .read(cx)
 5224            .current_inlays()
 5225            .cloned()
 5226            .collect()
 5227    }
 5228
 5229    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5230        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5231            return;
 5232        }
 5233
 5234        let reason_description = reason.description();
 5235        let ignore_debounce = matches!(
 5236            reason,
 5237            InlayHintRefreshReason::SettingsChange(_)
 5238                | InlayHintRefreshReason::Toggle(_)
 5239                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5240                | InlayHintRefreshReason::ModifiersChanged(_)
 5241        );
 5242        let (invalidate_cache, required_languages) = match reason {
 5243            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5244                match self.inlay_hint_cache.modifiers_override(enabled) {
 5245                    Some(enabled) => {
 5246                        if enabled {
 5247                            (InvalidationStrategy::RefreshRequested, None)
 5248                        } else {
 5249                            self.clear_inlay_hints(cx);
 5250                            return;
 5251                        }
 5252                    }
 5253                    None => return,
 5254                }
 5255            }
 5256            InlayHintRefreshReason::Toggle(enabled) => {
 5257                if self.inlay_hint_cache.toggle(enabled) {
 5258                    if enabled {
 5259                        (InvalidationStrategy::RefreshRequested, None)
 5260                    } else {
 5261                        self.clear_inlay_hints(cx);
 5262                        return;
 5263                    }
 5264                } else {
 5265                    return;
 5266                }
 5267            }
 5268            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5269                match self.inlay_hint_cache.update_settings(
 5270                    &self.buffer,
 5271                    new_settings,
 5272                    self.visible_inlay_hints(cx).cloned().collect::<Vec<_>>(),
 5273                    cx,
 5274                ) {
 5275                    ControlFlow::Break(Some(InlaySplice {
 5276                        to_remove,
 5277                        to_insert,
 5278                    })) => {
 5279                        self.splice_inlays(&to_remove, to_insert, cx);
 5280                        return;
 5281                    }
 5282                    ControlFlow::Break(None) => return,
 5283                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5284                }
 5285            }
 5286            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5287                if let Some(InlaySplice {
 5288                    to_remove,
 5289                    to_insert,
 5290                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5291                {
 5292                    self.splice_inlays(&to_remove, to_insert, cx);
 5293                }
 5294                self.display_map.update(cx, |display_map, _| {
 5295                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5296                });
 5297                return;
 5298            }
 5299            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5300            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5301                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5302            }
 5303            InlayHintRefreshReason::RefreshRequested => {
 5304                (InvalidationStrategy::RefreshRequested, None)
 5305            }
 5306        };
 5307
 5308        if let Some(InlaySplice {
 5309            to_remove,
 5310            to_insert,
 5311        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5312            reason_description,
 5313            self.visible_excerpts(required_languages.as_ref(), cx),
 5314            invalidate_cache,
 5315            ignore_debounce,
 5316            cx,
 5317        ) {
 5318            self.splice_inlays(&to_remove, to_insert, cx);
 5319        }
 5320    }
 5321
 5322    pub fn clear_inlay_hints(&self, cx: &mut Context<Editor>) {
 5323        self.splice_inlays(
 5324            &self
 5325                .visible_inlay_hints(cx)
 5326                .map(|inlay| inlay.id)
 5327                .collect::<Vec<_>>(),
 5328            Vec::new(),
 5329            cx,
 5330        );
 5331    }
 5332
 5333    fn visible_inlay_hints<'a>(
 5334        &'a self,
 5335        cx: &'a Context<Editor>,
 5336    ) -> impl Iterator<Item = &'a Inlay> {
 5337        self.display_map
 5338            .read(cx)
 5339            .current_inlays()
 5340            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5341    }
 5342
 5343    pub fn visible_excerpts(
 5344        &self,
 5345        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5346        cx: &mut Context<Editor>,
 5347    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5348        let Some(project) = self.project() else {
 5349            return HashMap::default();
 5350        };
 5351        let project = project.read(cx);
 5352        let multi_buffer = self.buffer().read(cx);
 5353        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5354        let multi_buffer_visible_start = self
 5355            .scroll_manager
 5356            .anchor()
 5357            .anchor
 5358            .to_point(&multi_buffer_snapshot);
 5359        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5360            multi_buffer_visible_start
 5361                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5362            Bias::Left,
 5363        );
 5364        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5365        multi_buffer_snapshot
 5366            .range_to_buffer_ranges(multi_buffer_visible_range)
 5367            .into_iter()
 5368            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5369            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5370                let buffer_file = project::File::from_dyn(buffer.file())?;
 5371                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5372                let worktree_entry = buffer_worktree
 5373                    .read(cx)
 5374                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5375                if worktree_entry.is_ignored {
 5376                    return None;
 5377                }
 5378
 5379                let language = buffer.language()?;
 5380                if let Some(restrict_to_languages) = restrict_to_languages
 5381                    && !restrict_to_languages.contains(language)
 5382                {
 5383                    return None;
 5384                }
 5385                Some((
 5386                    excerpt_id,
 5387                    (
 5388                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5389                        buffer.version().clone(),
 5390                        excerpt_visible_range,
 5391                    ),
 5392                ))
 5393            })
 5394            .collect()
 5395    }
 5396
 5397    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5398        TextLayoutDetails {
 5399            text_system: window.text_system().clone(),
 5400            editor_style: self.style.clone().unwrap(),
 5401            rem_size: window.rem_size(),
 5402            scroll_anchor: self.scroll_manager.anchor(),
 5403            visible_rows: self.visible_line_count(),
 5404            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5405        }
 5406    }
 5407
 5408    pub fn splice_inlays(
 5409        &self,
 5410        to_remove: &[InlayId],
 5411        to_insert: Vec<Inlay>,
 5412        cx: &mut Context<Self>,
 5413    ) {
 5414        self.display_map.update(cx, |display_map, cx| {
 5415            display_map.splice_inlays(to_remove, to_insert, cx)
 5416        });
 5417        cx.notify();
 5418    }
 5419
 5420    fn trigger_on_type_formatting(
 5421        &self,
 5422        input: String,
 5423        window: &mut Window,
 5424        cx: &mut Context<Self>,
 5425    ) -> Option<Task<Result<()>>> {
 5426        if input.len() != 1 {
 5427            return None;
 5428        }
 5429
 5430        let project = self.project()?;
 5431        let position = self.selections.newest_anchor().head();
 5432        let (buffer, buffer_position) = self
 5433            .buffer
 5434            .read(cx)
 5435            .text_anchor_for_position(position, cx)?;
 5436
 5437        let settings = language_settings::language_settings(
 5438            buffer
 5439                .read(cx)
 5440                .language_at(buffer_position)
 5441                .map(|l| l.name()),
 5442            buffer.read(cx).file(),
 5443            cx,
 5444        );
 5445        if !settings.use_on_type_format {
 5446            return None;
 5447        }
 5448
 5449        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5450        // hence we do LSP request & edit on host side only — add formats to host's history.
 5451        let push_to_lsp_host_history = true;
 5452        // If this is not the host, append its history with new edits.
 5453        let push_to_client_history = project.read(cx).is_via_collab();
 5454
 5455        let on_type_formatting = project.update(cx, |project, cx| {
 5456            project.on_type_format(
 5457                buffer.clone(),
 5458                buffer_position,
 5459                input,
 5460                push_to_lsp_host_history,
 5461                cx,
 5462            )
 5463        });
 5464        Some(cx.spawn_in(window, async move |editor, cx| {
 5465            if let Some(transaction) = on_type_formatting.await? {
 5466                if push_to_client_history {
 5467                    buffer
 5468                        .update(cx, |buffer, _| {
 5469                            buffer.push_transaction(transaction, Instant::now());
 5470                            buffer.finalize_last_transaction();
 5471                        })
 5472                        .ok();
 5473                }
 5474                editor.update(cx, |editor, cx| {
 5475                    editor.refresh_document_highlights(cx);
 5476                })?;
 5477            }
 5478            Ok(())
 5479        }))
 5480    }
 5481
 5482    pub fn show_word_completions(
 5483        &mut self,
 5484        _: &ShowWordCompletions,
 5485        window: &mut Window,
 5486        cx: &mut Context<Self>,
 5487    ) {
 5488        self.open_or_update_completions_menu(
 5489            Some(CompletionsMenuSource::Words {
 5490                ignore_threshold: true,
 5491            }),
 5492            None,
 5493            window,
 5494            cx,
 5495        );
 5496    }
 5497
 5498    pub fn show_completions(
 5499        &mut self,
 5500        options: &ShowCompletions,
 5501        window: &mut Window,
 5502        cx: &mut Context<Self>,
 5503    ) {
 5504        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5505    }
 5506
 5507    fn open_or_update_completions_menu(
 5508        &mut self,
 5509        requested_source: Option<CompletionsMenuSource>,
 5510        trigger: Option<&str>,
 5511        window: &mut Window,
 5512        cx: &mut Context<Self>,
 5513    ) {
 5514        if self.pending_rename.is_some() {
 5515            return;
 5516        }
 5517
 5518        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5519
 5520        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5521        // inserted and selected. To handle that case, the start of the selection is used so that
 5522        // the menu starts with all choices.
 5523        let position = self
 5524            .selections
 5525            .newest_anchor()
 5526            .start
 5527            .bias_right(&multibuffer_snapshot);
 5528        if position.diff_base_anchor.is_some() {
 5529            return;
 5530        }
 5531        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5532        let Some(buffer) = buffer_position
 5533            .buffer_id
 5534            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5535        else {
 5536            return;
 5537        };
 5538        let buffer_snapshot = buffer.read(cx).snapshot();
 5539
 5540        let query: Option<Arc<String>> =
 5541            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5542                .map(|query| query.into());
 5543
 5544        drop(multibuffer_snapshot);
 5545
 5546        // Hide the current completions menu when query is empty. Without this, cached
 5547        // completions from before the trigger char may be reused (#32774).
 5548        if query.is_none() {
 5549            let menu_is_open = matches!(
 5550                self.context_menu.borrow().as_ref(),
 5551                Some(CodeContextMenu::Completions(_))
 5552            );
 5553            if menu_is_open {
 5554                self.hide_context_menu(window, cx);
 5555            }
 5556        }
 5557
 5558        let mut ignore_word_threshold = false;
 5559        let provider = match requested_source {
 5560            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5561            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5562                ignore_word_threshold = ignore_threshold;
 5563                None
 5564            }
 5565            Some(CompletionsMenuSource::SnippetChoices) => {
 5566                log::error!("bug: SnippetChoices requested_source is not handled");
 5567                None
 5568            }
 5569        };
 5570
 5571        let sort_completions = provider
 5572            .as_ref()
 5573            .is_some_and(|provider| provider.sort_completions());
 5574
 5575        let filter_completions = provider
 5576            .as_ref()
 5577            .is_none_or(|provider| provider.filter_completions());
 5578
 5579        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5580            if filter_completions {
 5581                menu.filter(query.clone(), provider.clone(), window, cx);
 5582            }
 5583            // When `is_incomplete` is false, no need to re-query completions when the current query
 5584            // is a suffix of the initial query.
 5585            if !menu.is_incomplete {
 5586                // If the new query is a suffix of the old query (typing more characters) and
 5587                // the previous result was complete, the existing completions can be filtered.
 5588                //
 5589                // Note that this is always true for snippet completions.
 5590                let query_matches = match (&menu.initial_query, &query) {
 5591                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5592                    (None, _) => true,
 5593                    _ => false,
 5594                };
 5595                if query_matches {
 5596                    let position_matches = if menu.initial_position == position {
 5597                        true
 5598                    } else {
 5599                        let snapshot = self.buffer.read(cx).read(cx);
 5600                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5601                    };
 5602                    if position_matches {
 5603                        return;
 5604                    }
 5605                }
 5606            }
 5607        };
 5608
 5609        let trigger_kind = match trigger {
 5610            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5611                CompletionTriggerKind::TRIGGER_CHARACTER
 5612            }
 5613            _ => CompletionTriggerKind::INVOKED,
 5614        };
 5615        let completion_context = CompletionContext {
 5616            trigger_character: trigger.and_then(|trigger| {
 5617                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5618                    Some(String::from(trigger))
 5619                } else {
 5620                    None
 5621                }
 5622            }),
 5623            trigger_kind,
 5624        };
 5625
 5626        let Anchor {
 5627            excerpt_id: buffer_excerpt_id,
 5628            text_anchor: buffer_position,
 5629            ..
 5630        } = buffer_position;
 5631
 5632        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5633            buffer_snapshot.surrounding_word(buffer_position, None)
 5634        {
 5635            let word_to_exclude = buffer_snapshot
 5636                .text_for_range(word_range.clone())
 5637                .collect::<String>();
 5638            (
 5639                buffer_snapshot.anchor_before(word_range.start)
 5640                    ..buffer_snapshot.anchor_after(buffer_position),
 5641                Some(word_to_exclude),
 5642            )
 5643        } else {
 5644            (buffer_position..buffer_position, None)
 5645        };
 5646
 5647        let language = buffer_snapshot
 5648            .language_at(buffer_position)
 5649            .map(|language| language.name());
 5650
 5651        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5652            .completions
 5653            .clone();
 5654
 5655        let show_completion_documentation = buffer_snapshot
 5656            .settings_at(buffer_position, cx)
 5657            .show_completion_documentation;
 5658
 5659        // The document can be large, so stay in reasonable bounds when searching for words,
 5660        // otherwise completion pop-up might be slow to appear.
 5661        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5662        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5663        let min_word_search = buffer_snapshot.clip_point(
 5664            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5665            Bias::Left,
 5666        );
 5667        let max_word_search = buffer_snapshot.clip_point(
 5668            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5669            Bias::Right,
 5670        );
 5671        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5672            ..buffer_snapshot.point_to_offset(max_word_search);
 5673
 5674        let skip_digits = query
 5675            .as_ref()
 5676            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5677
 5678        let omit_word_completions = !self.word_completions_enabled
 5679            || (!ignore_word_threshold
 5680                && match &query {
 5681                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5682                    None => completion_settings.words_min_length != 0,
 5683                });
 5684
 5685        let (mut words, provider_responses) = match &provider {
 5686            Some(provider) => {
 5687                let provider_responses = provider.completions(
 5688                    buffer_excerpt_id,
 5689                    &buffer,
 5690                    buffer_position,
 5691                    completion_context,
 5692                    window,
 5693                    cx,
 5694                );
 5695
 5696                let words = match (omit_word_completions, completion_settings.words) {
 5697                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5698                        Task::ready(BTreeMap::default())
 5699                    }
 5700                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5701                        .background_spawn(async move {
 5702                            buffer_snapshot.words_in_range(WordsQuery {
 5703                                fuzzy_contents: None,
 5704                                range: word_search_range,
 5705                                skip_digits,
 5706                            })
 5707                        }),
 5708                };
 5709
 5710                (words, provider_responses)
 5711            }
 5712            None => {
 5713                let words = if omit_word_completions {
 5714                    Task::ready(BTreeMap::default())
 5715                } else {
 5716                    cx.background_spawn(async move {
 5717                        buffer_snapshot.words_in_range(WordsQuery {
 5718                            fuzzy_contents: None,
 5719                            range: word_search_range,
 5720                            skip_digits,
 5721                        })
 5722                    })
 5723                };
 5724                (words, Task::ready(Ok(Vec::new())))
 5725            }
 5726        };
 5727
 5728        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5729
 5730        let id = post_inc(&mut self.next_completion_id);
 5731        let task = cx.spawn_in(window, async move |editor, cx| {
 5732            let Ok(()) = editor.update(cx, |this, _| {
 5733                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5734            }) else {
 5735                return;
 5736            };
 5737
 5738            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5739            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5740            let mut completions = Vec::new();
 5741            let mut is_incomplete = false;
 5742            let mut display_options: Option<CompletionDisplayOptions> = None;
 5743            if let Some(provider_responses) = provider_responses.await.log_err()
 5744                && !provider_responses.is_empty()
 5745            {
 5746                for response in provider_responses {
 5747                    completions.extend(response.completions);
 5748                    is_incomplete = is_incomplete || response.is_incomplete;
 5749                    match display_options.as_mut() {
 5750                        None => {
 5751                            display_options = Some(response.display_options);
 5752                        }
 5753                        Some(options) => options.merge(&response.display_options),
 5754                    }
 5755                }
 5756                if completion_settings.words == WordsCompletionMode::Fallback {
 5757                    words = Task::ready(BTreeMap::default());
 5758                }
 5759            }
 5760            let display_options = display_options.unwrap_or_default();
 5761
 5762            let mut words = words.await;
 5763            if let Some(word_to_exclude) = &word_to_exclude {
 5764                words.remove(word_to_exclude);
 5765            }
 5766            for lsp_completion in &completions {
 5767                words.remove(&lsp_completion.new_text);
 5768            }
 5769            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5770                replace_range: word_replace_range.clone(),
 5771                new_text: word.clone(),
 5772                label: CodeLabel::plain(word, None),
 5773                icon_path: None,
 5774                documentation: None,
 5775                source: CompletionSource::BufferWord {
 5776                    word_range,
 5777                    resolved: false,
 5778                },
 5779                insert_text_mode: Some(InsertTextMode::AS_IS),
 5780                confirm: None,
 5781            }));
 5782
 5783            let menu = if completions.is_empty() {
 5784                None
 5785            } else {
 5786                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5787                    let languages = editor
 5788                        .workspace
 5789                        .as_ref()
 5790                        .and_then(|(workspace, _)| workspace.upgrade())
 5791                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5792                    let menu = CompletionsMenu::new(
 5793                        id,
 5794                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5795                        sort_completions,
 5796                        show_completion_documentation,
 5797                        position,
 5798                        query.clone(),
 5799                        is_incomplete,
 5800                        buffer.clone(),
 5801                        completions.into(),
 5802                        display_options,
 5803                        snippet_sort_order,
 5804                        languages,
 5805                        language,
 5806                        cx,
 5807                    );
 5808
 5809                    let query = if filter_completions { query } else { None };
 5810                    let matches_task = if let Some(query) = query {
 5811                        menu.do_async_filtering(query, cx)
 5812                    } else {
 5813                        Task::ready(menu.unfiltered_matches())
 5814                    };
 5815                    (menu, matches_task)
 5816                }) else {
 5817                    return;
 5818                };
 5819
 5820                let matches = matches_task.await;
 5821
 5822                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5823                    // Newer menu already set, so exit.
 5824                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5825                        editor.context_menu.borrow().as_ref()
 5826                        && prev_menu.id > id
 5827                    {
 5828                        return;
 5829                    };
 5830
 5831                    // Only valid to take prev_menu because it the new menu is immediately set
 5832                    // below, or the menu is hidden.
 5833                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5834                        editor.context_menu.borrow_mut().take()
 5835                    {
 5836                        let position_matches =
 5837                            if prev_menu.initial_position == menu.initial_position {
 5838                                true
 5839                            } else {
 5840                                let snapshot = editor.buffer.read(cx).read(cx);
 5841                                prev_menu.initial_position.to_offset(&snapshot)
 5842                                    == menu.initial_position.to_offset(&snapshot)
 5843                            };
 5844                        if position_matches {
 5845                            // Preserve markdown cache before `set_filter_results` because it will
 5846                            // try to populate the documentation cache.
 5847                            menu.preserve_markdown_cache(prev_menu);
 5848                        }
 5849                    };
 5850
 5851                    menu.set_filter_results(matches, provider, window, cx);
 5852                }) else {
 5853                    return;
 5854                };
 5855
 5856                menu.visible().then_some(menu)
 5857            };
 5858
 5859            editor
 5860                .update_in(cx, |editor, window, cx| {
 5861                    if editor.focus_handle.is_focused(window)
 5862                        && let Some(menu) = menu
 5863                    {
 5864                        *editor.context_menu.borrow_mut() =
 5865                            Some(CodeContextMenu::Completions(menu));
 5866
 5867                        crate::hover_popover::hide_hover(editor, cx);
 5868                        if editor.show_edit_predictions_in_menu() {
 5869                            editor.update_visible_edit_prediction(window, cx);
 5870                        } else {
 5871                            editor.discard_edit_prediction(false, cx);
 5872                        }
 5873
 5874                        cx.notify();
 5875                        return;
 5876                    }
 5877
 5878                    if editor.completion_tasks.len() <= 1 {
 5879                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5880                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5881                        // If it was already hidden and we don't show edit predictions in the menu,
 5882                        // we should also show the edit prediction when available.
 5883                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5884                            editor.update_visible_edit_prediction(window, cx);
 5885                        }
 5886                    }
 5887                })
 5888                .ok();
 5889        });
 5890
 5891        self.completion_tasks.push((id, task));
 5892    }
 5893
 5894    #[cfg(feature = "test-support")]
 5895    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5896        let menu = self.context_menu.borrow();
 5897        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5898            let completions = menu.completions.borrow();
 5899            Some(completions.to_vec())
 5900        } else {
 5901            None
 5902        }
 5903    }
 5904
 5905    pub fn with_completions_menu_matching_id<R>(
 5906        &self,
 5907        id: CompletionId,
 5908        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5909    ) -> R {
 5910        let mut context_menu = self.context_menu.borrow_mut();
 5911        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5912            return f(None);
 5913        };
 5914        if completions_menu.id != id {
 5915            return f(None);
 5916        }
 5917        f(Some(completions_menu))
 5918    }
 5919
 5920    pub fn confirm_completion(
 5921        &mut self,
 5922        action: &ConfirmCompletion,
 5923        window: &mut Window,
 5924        cx: &mut Context<Self>,
 5925    ) -> Option<Task<Result<()>>> {
 5926        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5927        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5928    }
 5929
 5930    pub fn confirm_completion_insert(
 5931        &mut self,
 5932        _: &ConfirmCompletionInsert,
 5933        window: &mut Window,
 5934        cx: &mut Context<Self>,
 5935    ) -> Option<Task<Result<()>>> {
 5936        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5937        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5938    }
 5939
 5940    pub fn confirm_completion_replace(
 5941        &mut self,
 5942        _: &ConfirmCompletionReplace,
 5943        window: &mut Window,
 5944        cx: &mut Context<Self>,
 5945    ) -> Option<Task<Result<()>>> {
 5946        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5947        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5948    }
 5949
 5950    pub fn compose_completion(
 5951        &mut self,
 5952        action: &ComposeCompletion,
 5953        window: &mut Window,
 5954        cx: &mut Context<Self>,
 5955    ) -> Option<Task<Result<()>>> {
 5956        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5957        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5958    }
 5959
 5960    fn do_completion(
 5961        &mut self,
 5962        item_ix: Option<usize>,
 5963        intent: CompletionIntent,
 5964        window: &mut Window,
 5965        cx: &mut Context<Editor>,
 5966    ) -> Option<Task<Result<()>>> {
 5967        use language::ToOffset as _;
 5968
 5969        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5970        else {
 5971            return None;
 5972        };
 5973
 5974        let candidate_id = {
 5975            let entries = completions_menu.entries.borrow();
 5976            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5977            if self.show_edit_predictions_in_menu() {
 5978                self.discard_edit_prediction(true, cx);
 5979            }
 5980            mat.candidate_id
 5981        };
 5982
 5983        let completion = completions_menu
 5984            .completions
 5985            .borrow()
 5986            .get(candidate_id)?
 5987            .clone();
 5988        cx.stop_propagation();
 5989
 5990        let buffer_handle = completions_menu.buffer.clone();
 5991
 5992        let CompletionEdit {
 5993            new_text,
 5994            snippet,
 5995            replace_range,
 5996        } = process_completion_for_edit(
 5997            &completion,
 5998            intent,
 5999            &buffer_handle,
 6000            &completions_menu.initial_position.text_anchor,
 6001            cx,
 6002        );
 6003
 6004        let buffer = buffer_handle.read(cx);
 6005        let snapshot = self.buffer.read(cx).snapshot(cx);
 6006        let newest_anchor = self.selections.newest_anchor();
 6007        let replace_range_multibuffer = {
 6008            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6009            let multibuffer_anchor = snapshot
 6010                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 6011                .unwrap()
 6012                ..snapshot
 6013                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 6014                    .unwrap();
 6015            multibuffer_anchor.start.to_offset(&snapshot)
 6016                ..multibuffer_anchor.end.to_offset(&snapshot)
 6017        };
 6018        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6019            return None;
 6020        }
 6021
 6022        let old_text = buffer
 6023            .text_for_range(replace_range.clone())
 6024            .collect::<String>();
 6025        let lookbehind = newest_anchor
 6026            .start
 6027            .text_anchor
 6028            .to_offset(buffer)
 6029            .saturating_sub(replace_range.start);
 6030        let lookahead = replace_range
 6031            .end
 6032            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6033        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6034        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6035
 6036        let selections = self.selections.all::<usize>(cx);
 6037        let mut ranges = Vec::new();
 6038        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6039
 6040        for selection in &selections {
 6041            let range = if selection.id == newest_anchor.id {
 6042                replace_range_multibuffer.clone()
 6043            } else {
 6044                let mut range = selection.range();
 6045
 6046                // if prefix is present, don't duplicate it
 6047                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6048                    range.start = range.start.saturating_sub(lookbehind);
 6049
 6050                    // if suffix is also present, mimic the newest cursor and replace it
 6051                    if selection.id != newest_anchor.id
 6052                        && snapshot.contains_str_at(range.end, suffix)
 6053                    {
 6054                        range.end += lookahead;
 6055                    }
 6056                }
 6057                range
 6058            };
 6059
 6060            ranges.push(range.clone());
 6061
 6062            if !self.linked_edit_ranges.is_empty() {
 6063                let start_anchor = snapshot.anchor_before(range.start);
 6064                let end_anchor = snapshot.anchor_after(range.end);
 6065                if let Some(ranges) = self
 6066                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6067                {
 6068                    for (buffer, edits) in ranges {
 6069                        linked_edits
 6070                            .entry(buffer.clone())
 6071                            .or_default()
 6072                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6073                    }
 6074                }
 6075            }
 6076        }
 6077
 6078        let common_prefix_len = old_text
 6079            .chars()
 6080            .zip(new_text.chars())
 6081            .take_while(|(a, b)| a == b)
 6082            .map(|(a, _)| a.len_utf8())
 6083            .sum::<usize>();
 6084
 6085        cx.emit(EditorEvent::InputHandled {
 6086            utf16_range_to_replace: None,
 6087            text: new_text[common_prefix_len..].into(),
 6088        });
 6089
 6090        self.transact(window, cx, |editor, window, cx| {
 6091            if let Some(mut snippet) = snippet {
 6092                snippet.text = new_text.to_string();
 6093                editor
 6094                    .insert_snippet(&ranges, snippet, window, cx)
 6095                    .log_err();
 6096            } else {
 6097                editor.buffer.update(cx, |multi_buffer, cx| {
 6098                    let auto_indent = match completion.insert_text_mode {
 6099                        Some(InsertTextMode::AS_IS) => None,
 6100                        _ => editor.autoindent_mode.clone(),
 6101                    };
 6102                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6103                    multi_buffer.edit(edits, auto_indent, cx);
 6104                });
 6105            }
 6106            for (buffer, edits) in linked_edits {
 6107                buffer.update(cx, |buffer, cx| {
 6108                    let snapshot = buffer.snapshot();
 6109                    let edits = edits
 6110                        .into_iter()
 6111                        .map(|(range, text)| {
 6112                            use text::ToPoint as TP;
 6113                            let end_point = TP::to_point(&range.end, &snapshot);
 6114                            let start_point = TP::to_point(&range.start, &snapshot);
 6115                            (start_point..end_point, text)
 6116                        })
 6117                        .sorted_by_key(|(range, _)| range.start);
 6118                    buffer.edit(edits, None, cx);
 6119                })
 6120            }
 6121
 6122            editor.refresh_edit_prediction(true, false, window, cx);
 6123        });
 6124        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6125
 6126        let show_new_completions_on_confirm = completion
 6127            .confirm
 6128            .as_ref()
 6129            .is_some_and(|confirm| confirm(intent, window, cx));
 6130        if show_new_completions_on_confirm {
 6131            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6132        }
 6133
 6134        let provider = self.completion_provider.as_ref()?;
 6135        drop(completion);
 6136        let apply_edits = provider.apply_additional_edits_for_completion(
 6137            buffer_handle,
 6138            completions_menu.completions.clone(),
 6139            candidate_id,
 6140            true,
 6141            cx,
 6142        );
 6143
 6144        let editor_settings = EditorSettings::get_global(cx);
 6145        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6146            // After the code completion is finished, users often want to know what signatures are needed.
 6147            // so we should automatically call signature_help
 6148            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6149        }
 6150
 6151        Some(cx.foreground_executor().spawn(async move {
 6152            apply_edits.await?;
 6153            Ok(())
 6154        }))
 6155    }
 6156
 6157    pub fn toggle_code_actions(
 6158        &mut self,
 6159        action: &ToggleCodeActions,
 6160        window: &mut Window,
 6161        cx: &mut Context<Self>,
 6162    ) {
 6163        let quick_launch = action.quick_launch;
 6164        let mut context_menu = self.context_menu.borrow_mut();
 6165        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6166            if code_actions.deployed_from == action.deployed_from {
 6167                // Toggle if we're selecting the same one
 6168                *context_menu = None;
 6169                cx.notify();
 6170                return;
 6171            } else {
 6172                // Otherwise, clear it and start a new one
 6173                *context_menu = None;
 6174                cx.notify();
 6175            }
 6176        }
 6177        drop(context_menu);
 6178        let snapshot = self.snapshot(window, cx);
 6179        let deployed_from = action.deployed_from.clone();
 6180        let action = action.clone();
 6181        self.completion_tasks.clear();
 6182        self.discard_edit_prediction(false, cx);
 6183
 6184        let multibuffer_point = match &action.deployed_from {
 6185            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6186                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6187            }
 6188            _ => self.selections.newest::<Point>(cx).head(),
 6189        };
 6190        let Some((buffer, buffer_row)) = snapshot
 6191            .buffer_snapshot()
 6192            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6193            .and_then(|(buffer_snapshot, range)| {
 6194                self.buffer()
 6195                    .read(cx)
 6196                    .buffer(buffer_snapshot.remote_id())
 6197                    .map(|buffer| (buffer, range.start.row))
 6198            })
 6199        else {
 6200            return;
 6201        };
 6202        let buffer_id = buffer.read(cx).remote_id();
 6203        let tasks = self
 6204            .tasks
 6205            .get(&(buffer_id, buffer_row))
 6206            .map(|t| Arc::new(t.to_owned()));
 6207
 6208        if !self.focus_handle.is_focused(window) {
 6209            return;
 6210        }
 6211        let project = self.project.clone();
 6212
 6213        let code_actions_task = match deployed_from {
 6214            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6215            _ => self.code_actions(buffer_row, window, cx),
 6216        };
 6217
 6218        let runnable_task = match deployed_from {
 6219            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6220            _ => {
 6221                let mut task_context_task = Task::ready(None);
 6222                if let Some(tasks) = &tasks
 6223                    && let Some(project) = project
 6224                {
 6225                    task_context_task =
 6226                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6227                }
 6228
 6229                cx.spawn_in(window, {
 6230                    let buffer = buffer.clone();
 6231                    async move |editor, cx| {
 6232                        let task_context = task_context_task.await;
 6233
 6234                        let resolved_tasks =
 6235                            tasks
 6236                                .zip(task_context.clone())
 6237                                .map(|(tasks, task_context)| ResolvedTasks {
 6238                                    templates: tasks.resolve(&task_context).collect(),
 6239                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6240                                        multibuffer_point.row,
 6241                                        tasks.column,
 6242                                    )),
 6243                                });
 6244                        let debug_scenarios = editor
 6245                            .update(cx, |editor, cx| {
 6246                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6247                            })?
 6248                            .await;
 6249                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6250                    }
 6251                })
 6252            }
 6253        };
 6254
 6255        cx.spawn_in(window, async move |editor, cx| {
 6256            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6257            let code_actions = code_actions_task.await;
 6258            let spawn_straight_away = quick_launch
 6259                && resolved_tasks
 6260                    .as_ref()
 6261                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6262                && code_actions
 6263                    .as_ref()
 6264                    .is_none_or(|actions| actions.is_empty())
 6265                && debug_scenarios.is_empty();
 6266
 6267            editor.update_in(cx, |editor, window, cx| {
 6268                crate::hover_popover::hide_hover(editor, cx);
 6269                let actions = CodeActionContents::new(
 6270                    resolved_tasks,
 6271                    code_actions,
 6272                    debug_scenarios,
 6273                    task_context.unwrap_or_default(),
 6274                );
 6275
 6276                // Don't show the menu if there are no actions available
 6277                if actions.is_empty() {
 6278                    cx.notify();
 6279                    return Task::ready(Ok(()));
 6280                }
 6281
 6282                *editor.context_menu.borrow_mut() =
 6283                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6284                        buffer,
 6285                        actions,
 6286                        selected_item: Default::default(),
 6287                        scroll_handle: UniformListScrollHandle::default(),
 6288                        deployed_from,
 6289                    }));
 6290                cx.notify();
 6291                if spawn_straight_away
 6292                    && let Some(task) = editor.confirm_code_action(
 6293                        &ConfirmCodeAction { item_ix: Some(0) },
 6294                        window,
 6295                        cx,
 6296                    )
 6297                {
 6298                    return task;
 6299                }
 6300
 6301                Task::ready(Ok(()))
 6302            })
 6303        })
 6304        .detach_and_log_err(cx);
 6305    }
 6306
 6307    fn debug_scenarios(
 6308        &mut self,
 6309        resolved_tasks: &Option<ResolvedTasks>,
 6310        buffer: &Entity<Buffer>,
 6311        cx: &mut App,
 6312    ) -> Task<Vec<task::DebugScenario>> {
 6313        maybe!({
 6314            let project = self.project()?;
 6315            let dap_store = project.read(cx).dap_store();
 6316            let mut scenarios = vec![];
 6317            let resolved_tasks = resolved_tasks.as_ref()?;
 6318            let buffer = buffer.read(cx);
 6319            let language = buffer.language()?;
 6320            let file = buffer.file();
 6321            let debug_adapter = language_settings(language.name().into(), file, cx)
 6322                .debuggers
 6323                .first()
 6324                .map(SharedString::from)
 6325                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6326
 6327            dap_store.update(cx, |dap_store, cx| {
 6328                for (_, task) in &resolved_tasks.templates {
 6329                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6330                        task.original_task().clone(),
 6331                        debug_adapter.clone().into(),
 6332                        task.display_label().to_owned().into(),
 6333                        cx,
 6334                    );
 6335                    scenarios.push(maybe_scenario);
 6336                }
 6337            });
 6338            Some(cx.background_spawn(async move {
 6339                futures::future::join_all(scenarios)
 6340                    .await
 6341                    .into_iter()
 6342                    .flatten()
 6343                    .collect::<Vec<_>>()
 6344            }))
 6345        })
 6346        .unwrap_or_else(|| Task::ready(vec![]))
 6347    }
 6348
 6349    fn code_actions(
 6350        &mut self,
 6351        buffer_row: u32,
 6352        window: &mut Window,
 6353        cx: &mut Context<Self>,
 6354    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6355        let mut task = self.code_actions_task.take();
 6356        cx.spawn_in(window, async move |editor, cx| {
 6357            while let Some(prev_task) = task {
 6358                prev_task.await.log_err();
 6359                task = editor
 6360                    .update(cx, |this, _| this.code_actions_task.take())
 6361                    .ok()?;
 6362            }
 6363
 6364            editor
 6365                .update(cx, |editor, cx| {
 6366                    editor
 6367                        .available_code_actions
 6368                        .clone()
 6369                        .and_then(|(location, code_actions)| {
 6370                            let snapshot = location.buffer.read(cx).snapshot();
 6371                            let point_range = location.range.to_point(&snapshot);
 6372                            let point_range = point_range.start.row..=point_range.end.row;
 6373                            if point_range.contains(&buffer_row) {
 6374                                Some(code_actions)
 6375                            } else {
 6376                                None
 6377                            }
 6378                        })
 6379                })
 6380                .ok()
 6381                .flatten()
 6382        })
 6383    }
 6384
 6385    pub fn confirm_code_action(
 6386        &mut self,
 6387        action: &ConfirmCodeAction,
 6388        window: &mut Window,
 6389        cx: &mut Context<Self>,
 6390    ) -> Option<Task<Result<()>>> {
 6391        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6392
 6393        let actions_menu =
 6394            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6395                menu
 6396            } else {
 6397                return None;
 6398            };
 6399
 6400        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6401        let action = actions_menu.actions.get(action_ix)?;
 6402        let title = action.label();
 6403        let buffer = actions_menu.buffer;
 6404        let workspace = self.workspace()?;
 6405
 6406        match action {
 6407            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6408                workspace.update(cx, |workspace, cx| {
 6409                    workspace.schedule_resolved_task(
 6410                        task_source_kind,
 6411                        resolved_task,
 6412                        false,
 6413                        window,
 6414                        cx,
 6415                    );
 6416
 6417                    Some(Task::ready(Ok(())))
 6418                })
 6419            }
 6420            CodeActionsItem::CodeAction {
 6421                excerpt_id,
 6422                action,
 6423                provider,
 6424            } => {
 6425                let apply_code_action =
 6426                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6427                let workspace = workspace.downgrade();
 6428                Some(cx.spawn_in(window, async move |editor, cx| {
 6429                    let project_transaction = apply_code_action.await?;
 6430                    Self::open_project_transaction(
 6431                        &editor,
 6432                        workspace,
 6433                        project_transaction,
 6434                        title,
 6435                        cx,
 6436                    )
 6437                    .await
 6438                }))
 6439            }
 6440            CodeActionsItem::DebugScenario(scenario) => {
 6441                let context = actions_menu.actions.context;
 6442
 6443                workspace.update(cx, |workspace, cx| {
 6444                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6445                    workspace.start_debug_session(
 6446                        scenario,
 6447                        context,
 6448                        Some(buffer),
 6449                        None,
 6450                        window,
 6451                        cx,
 6452                    );
 6453                });
 6454                Some(Task::ready(Ok(())))
 6455            }
 6456        }
 6457    }
 6458
 6459    pub async fn open_project_transaction(
 6460        editor: &WeakEntity<Editor>,
 6461        workspace: WeakEntity<Workspace>,
 6462        transaction: ProjectTransaction,
 6463        title: String,
 6464        cx: &mut AsyncWindowContext,
 6465    ) -> Result<()> {
 6466        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6467        cx.update(|_, cx| {
 6468            entries.sort_unstable_by_key(|(buffer, _)| {
 6469                buffer.read(cx).file().map(|f| f.path().clone())
 6470            });
 6471        })?;
 6472        if entries.is_empty() {
 6473            return Ok(());
 6474        }
 6475
 6476        // If the project transaction's edits are all contained within this editor, then
 6477        // avoid opening a new editor to display them.
 6478
 6479        if let [(buffer, transaction)] = &*entries {
 6480            let excerpt = editor.update(cx, |editor, cx| {
 6481                editor
 6482                    .buffer()
 6483                    .read(cx)
 6484                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6485            })?;
 6486            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6487                && excerpted_buffer == *buffer
 6488            {
 6489                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6490                    let excerpt_range = excerpt_range.to_offset(buffer);
 6491                    buffer
 6492                        .edited_ranges_for_transaction::<usize>(transaction)
 6493                        .all(|range| {
 6494                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6495                        })
 6496                })?;
 6497
 6498                if all_edits_within_excerpt {
 6499                    return Ok(());
 6500                }
 6501            }
 6502        }
 6503
 6504        let mut ranges_to_highlight = Vec::new();
 6505        let excerpt_buffer = cx.new(|cx| {
 6506            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6507            for (buffer_handle, transaction) in &entries {
 6508                let edited_ranges = buffer_handle
 6509                    .read(cx)
 6510                    .edited_ranges_for_transaction::<Point>(transaction)
 6511                    .collect::<Vec<_>>();
 6512                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6513                    PathKey::for_buffer(buffer_handle, cx),
 6514                    buffer_handle.clone(),
 6515                    edited_ranges,
 6516                    multibuffer_context_lines(cx),
 6517                    cx,
 6518                );
 6519
 6520                ranges_to_highlight.extend(ranges);
 6521            }
 6522            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6523            multibuffer
 6524        })?;
 6525
 6526        workspace.update_in(cx, |workspace, window, cx| {
 6527            let project = workspace.project().clone();
 6528            let editor =
 6529                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6530            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6531            editor.update(cx, |editor, cx| {
 6532                editor.highlight_background::<Self>(
 6533                    &ranges_to_highlight,
 6534                    |theme| theme.colors().editor_highlighted_line_background,
 6535                    cx,
 6536                );
 6537            });
 6538        })?;
 6539
 6540        Ok(())
 6541    }
 6542
 6543    pub fn clear_code_action_providers(&mut self) {
 6544        self.code_action_providers.clear();
 6545        self.available_code_actions.take();
 6546    }
 6547
 6548    pub fn add_code_action_provider(
 6549        &mut self,
 6550        provider: Rc<dyn CodeActionProvider>,
 6551        window: &mut Window,
 6552        cx: &mut Context<Self>,
 6553    ) {
 6554        if self
 6555            .code_action_providers
 6556            .iter()
 6557            .any(|existing_provider| existing_provider.id() == provider.id())
 6558        {
 6559            return;
 6560        }
 6561
 6562        self.code_action_providers.push(provider);
 6563        self.refresh_code_actions(window, cx);
 6564    }
 6565
 6566    pub fn remove_code_action_provider(
 6567        &mut self,
 6568        id: Arc<str>,
 6569        window: &mut Window,
 6570        cx: &mut Context<Self>,
 6571    ) {
 6572        self.code_action_providers
 6573            .retain(|provider| provider.id() != id);
 6574        self.refresh_code_actions(window, cx);
 6575    }
 6576
 6577    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6578        !self.code_action_providers.is_empty()
 6579            && EditorSettings::get_global(cx).toolbar.code_actions
 6580    }
 6581
 6582    pub fn has_available_code_actions(&self) -> bool {
 6583        self.available_code_actions
 6584            .as_ref()
 6585            .is_some_and(|(_, actions)| !actions.is_empty())
 6586    }
 6587
 6588    fn render_inline_code_actions(
 6589        &self,
 6590        icon_size: ui::IconSize,
 6591        display_row: DisplayRow,
 6592        is_active: bool,
 6593        cx: &mut Context<Self>,
 6594    ) -> AnyElement {
 6595        let show_tooltip = !self.context_menu_visible();
 6596        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6597            .icon_size(icon_size)
 6598            .shape(ui::IconButtonShape::Square)
 6599            .icon_color(ui::Color::Hidden)
 6600            .toggle_state(is_active)
 6601            .when(show_tooltip, |this| {
 6602                this.tooltip({
 6603                    let focus_handle = self.focus_handle.clone();
 6604                    move |window, cx| {
 6605                        Tooltip::for_action_in(
 6606                            "Toggle Code Actions",
 6607                            &ToggleCodeActions {
 6608                                deployed_from: None,
 6609                                quick_launch: false,
 6610                            },
 6611                            &focus_handle,
 6612                            window,
 6613                            cx,
 6614                        )
 6615                    }
 6616                })
 6617            })
 6618            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6619                window.focus(&editor.focus_handle(cx));
 6620                editor.toggle_code_actions(
 6621                    &crate::actions::ToggleCodeActions {
 6622                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6623                            display_row,
 6624                        )),
 6625                        quick_launch: false,
 6626                    },
 6627                    window,
 6628                    cx,
 6629                );
 6630            }))
 6631            .into_any_element()
 6632    }
 6633
 6634    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6635        &self.context_menu
 6636    }
 6637
 6638    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6639        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6640            cx.background_executor()
 6641                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6642                .await;
 6643
 6644            let (start_buffer, start, _, end, newest_selection) = this
 6645                .update(cx, |this, cx| {
 6646                    let newest_selection = this.selections.newest_anchor().clone();
 6647                    if newest_selection.head().diff_base_anchor.is_some() {
 6648                        return None;
 6649                    }
 6650                    let newest_selection_adjusted = this.selections.newest_adjusted(cx);
 6651                    let buffer = this.buffer.read(cx);
 6652
 6653                    let (start_buffer, start) =
 6654                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6655                    let (end_buffer, end) =
 6656                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6657
 6658                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6659                })?
 6660                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6661                .context(
 6662                    "Expected selection to lie in a single buffer when refreshing code actions",
 6663                )?;
 6664            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6665                let providers = this.code_action_providers.clone();
 6666                let tasks = this
 6667                    .code_action_providers
 6668                    .iter()
 6669                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6670                    .collect::<Vec<_>>();
 6671                (providers, tasks)
 6672            })?;
 6673
 6674            let mut actions = Vec::new();
 6675            for (provider, provider_actions) in
 6676                providers.into_iter().zip(future::join_all(tasks).await)
 6677            {
 6678                if let Some(provider_actions) = provider_actions.log_err() {
 6679                    actions.extend(provider_actions.into_iter().map(|action| {
 6680                        AvailableCodeAction {
 6681                            excerpt_id: newest_selection.start.excerpt_id,
 6682                            action,
 6683                            provider: provider.clone(),
 6684                        }
 6685                    }));
 6686                }
 6687            }
 6688
 6689            this.update(cx, |this, cx| {
 6690                this.available_code_actions = if actions.is_empty() {
 6691                    None
 6692                } else {
 6693                    Some((
 6694                        Location {
 6695                            buffer: start_buffer,
 6696                            range: start..end,
 6697                        },
 6698                        actions.into(),
 6699                    ))
 6700                };
 6701                cx.notify();
 6702            })
 6703        }));
 6704    }
 6705
 6706    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6707        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6708            self.show_git_blame_inline = false;
 6709
 6710            self.show_git_blame_inline_delay_task =
 6711                Some(cx.spawn_in(window, async move |this, cx| {
 6712                    cx.background_executor().timer(delay).await;
 6713
 6714                    this.update(cx, |this, cx| {
 6715                        this.show_git_blame_inline = true;
 6716                        cx.notify();
 6717                    })
 6718                    .log_err();
 6719                }));
 6720        }
 6721    }
 6722
 6723    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6724        let snapshot = self.snapshot(window, cx);
 6725        let cursor = self.selections.newest::<Point>(cx).head();
 6726        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6727        else {
 6728            return;
 6729        };
 6730
 6731        let Some(blame) = self.blame.as_ref() else {
 6732            return;
 6733        };
 6734
 6735        let row_info = RowInfo {
 6736            buffer_id: Some(buffer.remote_id()),
 6737            buffer_row: Some(point.row),
 6738            ..Default::default()
 6739        };
 6740        let Some((buffer, blame_entry)) = blame
 6741            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6742            .flatten()
 6743        else {
 6744            return;
 6745        };
 6746
 6747        let anchor = self.selections.newest_anchor().head();
 6748        let position = self.to_pixel_point(anchor, &snapshot, window);
 6749        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6750            self.show_blame_popover(
 6751                buffer,
 6752                &blame_entry,
 6753                position + last_bounds.origin,
 6754                true,
 6755                cx,
 6756            );
 6757        };
 6758    }
 6759
 6760    fn show_blame_popover(
 6761        &mut self,
 6762        buffer: BufferId,
 6763        blame_entry: &BlameEntry,
 6764        position: gpui::Point<Pixels>,
 6765        ignore_timeout: bool,
 6766        cx: &mut Context<Self>,
 6767    ) {
 6768        if let Some(state) = &mut self.inline_blame_popover {
 6769            state.hide_task.take();
 6770        } else {
 6771            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6772            let blame_entry = blame_entry.clone();
 6773            let show_task = cx.spawn(async move |editor, cx| {
 6774                if !ignore_timeout {
 6775                    cx.background_executor()
 6776                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6777                        .await;
 6778                }
 6779                editor
 6780                    .update(cx, |editor, cx| {
 6781                        editor.inline_blame_popover_show_task.take();
 6782                        let Some(blame) = editor.blame.as_ref() else {
 6783                            return;
 6784                        };
 6785                        let blame = blame.read(cx);
 6786                        let details = blame.details_for_entry(buffer, &blame_entry);
 6787                        let markdown = cx.new(|cx| {
 6788                            Markdown::new(
 6789                                details
 6790                                    .as_ref()
 6791                                    .map(|message| message.message.clone())
 6792                                    .unwrap_or_default(),
 6793                                None,
 6794                                None,
 6795                                cx,
 6796                            )
 6797                        });
 6798                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6799                            position,
 6800                            hide_task: None,
 6801                            popover_bounds: None,
 6802                            popover_state: InlineBlamePopoverState {
 6803                                scroll_handle: ScrollHandle::new(),
 6804                                commit_message: details,
 6805                                markdown,
 6806                            },
 6807                            keyboard_grace: ignore_timeout,
 6808                        });
 6809                        cx.notify();
 6810                    })
 6811                    .ok();
 6812            });
 6813            self.inline_blame_popover_show_task = Some(show_task);
 6814        }
 6815    }
 6816
 6817    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6818        self.inline_blame_popover_show_task.take();
 6819        if let Some(state) = &mut self.inline_blame_popover {
 6820            let hide_task = cx.spawn(async move |editor, cx| {
 6821                cx.background_executor()
 6822                    .timer(std::time::Duration::from_millis(100))
 6823                    .await;
 6824                editor
 6825                    .update(cx, |editor, cx| {
 6826                        editor.inline_blame_popover.take();
 6827                        cx.notify();
 6828                    })
 6829                    .ok();
 6830            });
 6831            state.hide_task = Some(hide_task);
 6832        }
 6833    }
 6834
 6835    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6836        if self.pending_rename.is_some() {
 6837            return None;
 6838        }
 6839
 6840        let provider = self.semantics_provider.clone()?;
 6841        let buffer = self.buffer.read(cx);
 6842        let newest_selection = self.selections.newest_anchor().clone();
 6843        let cursor_position = newest_selection.head();
 6844        let (cursor_buffer, cursor_buffer_position) =
 6845            buffer.text_anchor_for_position(cursor_position, cx)?;
 6846        let (tail_buffer, tail_buffer_position) =
 6847            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6848        if cursor_buffer != tail_buffer {
 6849            return None;
 6850        }
 6851
 6852        let snapshot = cursor_buffer.read(cx).snapshot();
 6853        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6854        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6855        if start_word_range != end_word_range {
 6856            self.document_highlights_task.take();
 6857            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6858            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6859            return None;
 6860        }
 6861
 6862        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6863        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6864            cx.background_executor()
 6865                .timer(Duration::from_millis(debounce))
 6866                .await;
 6867
 6868            let highlights = if let Some(highlights) = cx
 6869                .update(|cx| {
 6870                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6871                })
 6872                .ok()
 6873                .flatten()
 6874            {
 6875                highlights.await.log_err()
 6876            } else {
 6877                None
 6878            };
 6879
 6880            if let Some(highlights) = highlights {
 6881                this.update(cx, |this, cx| {
 6882                    if this.pending_rename.is_some() {
 6883                        return;
 6884                    }
 6885
 6886                    let buffer = this.buffer.read(cx);
 6887                    if buffer
 6888                        .text_anchor_for_position(cursor_position, cx)
 6889                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6890                    {
 6891                        return;
 6892                    }
 6893
 6894                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6895                    let mut write_ranges = Vec::new();
 6896                    let mut read_ranges = Vec::new();
 6897                    for highlight in highlights {
 6898                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6899                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6900                        {
 6901                            let start = highlight
 6902                                .range
 6903                                .start
 6904                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6905                            let end = highlight
 6906                                .range
 6907                                .end
 6908                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6909                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6910                                continue;
 6911                            }
 6912
 6913                            let range = Anchor::range_in_buffer(excerpt_id, buffer_id, start..end);
 6914                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6915                                write_ranges.push(range);
 6916                            } else {
 6917                                read_ranges.push(range);
 6918                            }
 6919                        }
 6920                    }
 6921
 6922                    this.highlight_background::<DocumentHighlightRead>(
 6923                        &read_ranges,
 6924                        |theme| theme.colors().editor_document_highlight_read_background,
 6925                        cx,
 6926                    );
 6927                    this.highlight_background::<DocumentHighlightWrite>(
 6928                        &write_ranges,
 6929                        |theme| theme.colors().editor_document_highlight_write_background,
 6930                        cx,
 6931                    );
 6932                    cx.notify();
 6933                })
 6934                .log_err();
 6935            }
 6936        }));
 6937        None
 6938    }
 6939
 6940    fn prepare_highlight_query_from_selection(
 6941        &mut self,
 6942        cx: &mut Context<Editor>,
 6943    ) -> Option<(String, Range<Anchor>)> {
 6944        if matches!(self.mode, EditorMode::SingleLine) {
 6945            return None;
 6946        }
 6947        if !EditorSettings::get_global(cx).selection_highlight {
 6948            return None;
 6949        }
 6950        if self.selections.count() != 1 || self.selections.line_mode() {
 6951            return None;
 6952        }
 6953        let selection = self.selections.newest_anchor();
 6954        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6955        let selection_point_range = selection.start.to_point(&multi_buffer_snapshot)
 6956            ..selection.end.to_point(&multi_buffer_snapshot);
 6957        // If the selection spans multiple rows OR it is empty
 6958        if selection_point_range.start.row != selection_point_range.end.row
 6959            || selection_point_range.start.column == selection_point_range.end.column
 6960        {
 6961            return None;
 6962        }
 6963
 6964        let query = multi_buffer_snapshot
 6965            .text_for_range(selection.range())
 6966            .collect::<String>();
 6967        if query.trim().is_empty() {
 6968            return None;
 6969        }
 6970        Some((query, selection.range()))
 6971    }
 6972
 6973    fn update_selection_occurrence_highlights(
 6974        &mut self,
 6975        query_text: String,
 6976        query_range: Range<Anchor>,
 6977        multi_buffer_range_to_query: Range<Point>,
 6978        use_debounce: bool,
 6979        window: &mut Window,
 6980        cx: &mut Context<Editor>,
 6981    ) -> Task<()> {
 6982        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6983        cx.spawn_in(window, async move |editor, cx| {
 6984            if use_debounce {
 6985                cx.background_executor()
 6986                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6987                    .await;
 6988            }
 6989            let match_task = cx.background_spawn(async move {
 6990                let buffer_ranges = multi_buffer_snapshot
 6991                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6992                    .into_iter()
 6993                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6994                let mut match_ranges = Vec::new();
 6995                let Ok(regex) = project::search::SearchQuery::text(
 6996                    query_text.clone(),
 6997                    false,
 6998                    false,
 6999                    false,
 7000                    Default::default(),
 7001                    Default::default(),
 7002                    false,
 7003                    None,
 7004                ) else {
 7005                    return Vec::default();
 7006                };
 7007                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7008                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7009                    match_ranges.extend(
 7010                        regex
 7011                            .search(buffer_snapshot, Some(search_range.clone()))
 7012                            .await
 7013                            .into_iter()
 7014                            .filter_map(|match_range| {
 7015                                let match_start = buffer_snapshot
 7016                                    .anchor_after(search_range.start + match_range.start);
 7017                                let match_end = buffer_snapshot
 7018                                    .anchor_before(search_range.start + match_range.end);
 7019                                let match_anchor_range = Anchor::range_in_buffer(
 7020                                    excerpt_id,
 7021                                    buffer_snapshot.remote_id(),
 7022                                    match_start..match_end,
 7023                                );
 7024                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7025                            }),
 7026                    );
 7027                }
 7028                match_ranges
 7029            });
 7030            let match_ranges = match_task.await;
 7031            editor
 7032                .update_in(cx, |editor, _, cx| {
 7033                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7034                    if !match_ranges.is_empty() {
 7035                        editor.highlight_background::<SelectedTextHighlight>(
 7036                            &match_ranges,
 7037                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7038                            cx,
 7039                        )
 7040                    }
 7041                })
 7042                .log_err();
 7043        })
 7044    }
 7045
 7046    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7047        struct NewlineFold;
 7048        let type_id = std::any::TypeId::of::<NewlineFold>();
 7049        if !self.mode.is_single_line() {
 7050            return;
 7051        }
 7052        let snapshot = self.snapshot(window, cx);
 7053        if snapshot.buffer_snapshot().max_point().row == 0 {
 7054            return;
 7055        }
 7056        let task = cx.background_spawn(async move {
 7057            let new_newlines = snapshot
 7058                .buffer_chars_at(0)
 7059                .filter_map(|(c, i)| {
 7060                    if c == '\n' {
 7061                        Some(
 7062                            snapshot.buffer_snapshot().anchor_after(i)
 7063                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7064                        )
 7065                    } else {
 7066                        None
 7067                    }
 7068                })
 7069                .collect::<Vec<_>>();
 7070            let existing_newlines = snapshot
 7071                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7072                .filter_map(|fold| {
 7073                    if fold.placeholder.type_tag == Some(type_id) {
 7074                        Some(fold.range.start..fold.range.end)
 7075                    } else {
 7076                        None
 7077                    }
 7078                })
 7079                .collect::<Vec<_>>();
 7080
 7081            (new_newlines, existing_newlines)
 7082        });
 7083        self.folding_newlines = cx.spawn(async move |this, cx| {
 7084            let (new_newlines, existing_newlines) = task.await;
 7085            if new_newlines == existing_newlines {
 7086                return;
 7087            }
 7088            let placeholder = FoldPlaceholder {
 7089                render: Arc::new(move |_, _, cx| {
 7090                    div()
 7091                        .bg(cx.theme().status().hint_background)
 7092                        .border_b_1()
 7093                        .size_full()
 7094                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7095                        .border_color(cx.theme().status().hint)
 7096                        .child("\\n")
 7097                        .into_any()
 7098                }),
 7099                constrain_width: false,
 7100                merge_adjacent: false,
 7101                type_tag: Some(type_id),
 7102            };
 7103            let creases = new_newlines
 7104                .into_iter()
 7105                .map(|range| Crease::simple(range, placeholder.clone()))
 7106                .collect();
 7107            this.update(cx, |this, cx| {
 7108                this.display_map.update(cx, |display_map, cx| {
 7109                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7110                    display_map.fold(creases, cx);
 7111                });
 7112            })
 7113            .ok();
 7114        });
 7115    }
 7116
 7117    fn refresh_selected_text_highlights(
 7118        &mut self,
 7119        on_buffer_edit: bool,
 7120        window: &mut Window,
 7121        cx: &mut Context<Editor>,
 7122    ) {
 7123        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7124        else {
 7125            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7126            self.quick_selection_highlight_task.take();
 7127            self.debounced_selection_highlight_task.take();
 7128            return;
 7129        };
 7130        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7131        if on_buffer_edit
 7132            || self
 7133                .quick_selection_highlight_task
 7134                .as_ref()
 7135                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7136        {
 7137            let multi_buffer_visible_start = self
 7138                .scroll_manager
 7139                .anchor()
 7140                .anchor
 7141                .to_point(&multi_buffer_snapshot);
 7142            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7143                multi_buffer_visible_start
 7144                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7145                Bias::Left,
 7146            );
 7147            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7148            self.quick_selection_highlight_task = Some((
 7149                query_range.clone(),
 7150                self.update_selection_occurrence_highlights(
 7151                    query_text.clone(),
 7152                    query_range.clone(),
 7153                    multi_buffer_visible_range,
 7154                    false,
 7155                    window,
 7156                    cx,
 7157                ),
 7158            ));
 7159        }
 7160        if on_buffer_edit
 7161            || self
 7162                .debounced_selection_highlight_task
 7163                .as_ref()
 7164                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7165        {
 7166            let multi_buffer_start = multi_buffer_snapshot
 7167                .anchor_before(0)
 7168                .to_point(&multi_buffer_snapshot);
 7169            let multi_buffer_end = multi_buffer_snapshot
 7170                .anchor_after(multi_buffer_snapshot.len())
 7171                .to_point(&multi_buffer_snapshot);
 7172            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7173            self.debounced_selection_highlight_task = Some((
 7174                query_range.clone(),
 7175                self.update_selection_occurrence_highlights(
 7176                    query_text,
 7177                    query_range,
 7178                    multi_buffer_full_range,
 7179                    true,
 7180                    window,
 7181                    cx,
 7182                ),
 7183            ));
 7184        }
 7185    }
 7186
 7187    pub fn refresh_edit_prediction(
 7188        &mut self,
 7189        debounce: bool,
 7190        user_requested: bool,
 7191        window: &mut Window,
 7192        cx: &mut Context<Self>,
 7193    ) -> Option<()> {
 7194        if DisableAiSettings::get_global(cx).disable_ai {
 7195            return None;
 7196        }
 7197
 7198        let provider = self.edit_prediction_provider()?;
 7199        let cursor = self.selections.newest_anchor().head();
 7200        let (buffer, cursor_buffer_position) =
 7201            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7202
 7203        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7204            self.discard_edit_prediction(false, cx);
 7205            return None;
 7206        }
 7207
 7208        self.update_visible_edit_prediction(window, cx);
 7209
 7210        if !user_requested
 7211            && (!self.should_show_edit_predictions()
 7212                || !self.is_focused(window)
 7213                || buffer.read(cx).is_empty())
 7214        {
 7215            self.discard_edit_prediction(false, cx);
 7216            return None;
 7217        }
 7218
 7219        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7220        Some(())
 7221    }
 7222
 7223    fn show_edit_predictions_in_menu(&self) -> bool {
 7224        match self.edit_prediction_settings {
 7225            EditPredictionSettings::Disabled => false,
 7226            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7227        }
 7228    }
 7229
 7230    pub fn edit_predictions_enabled(&self) -> bool {
 7231        match self.edit_prediction_settings {
 7232            EditPredictionSettings::Disabled => false,
 7233            EditPredictionSettings::Enabled { .. } => true,
 7234        }
 7235    }
 7236
 7237    fn edit_prediction_requires_modifier(&self) -> bool {
 7238        match self.edit_prediction_settings {
 7239            EditPredictionSettings::Disabled => false,
 7240            EditPredictionSettings::Enabled {
 7241                preview_requires_modifier,
 7242                ..
 7243            } => preview_requires_modifier,
 7244        }
 7245    }
 7246
 7247    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7248        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7249            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7250            self.discard_edit_prediction(false, cx);
 7251        } else {
 7252            let selection = self.selections.newest_anchor();
 7253            let cursor = selection.head();
 7254
 7255            if let Some((buffer, cursor_buffer_position)) =
 7256                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7257            {
 7258                self.edit_prediction_settings =
 7259                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7260            }
 7261        }
 7262    }
 7263
 7264    fn edit_prediction_settings_at_position(
 7265        &self,
 7266        buffer: &Entity<Buffer>,
 7267        buffer_position: language::Anchor,
 7268        cx: &App,
 7269    ) -> EditPredictionSettings {
 7270        if !self.mode.is_full()
 7271            || !self.show_edit_predictions_override.unwrap_or(true)
 7272            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7273        {
 7274            return EditPredictionSettings::Disabled;
 7275        }
 7276
 7277        let buffer = buffer.read(cx);
 7278
 7279        let file = buffer.file();
 7280
 7281        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7282            return EditPredictionSettings::Disabled;
 7283        };
 7284
 7285        let by_provider = matches!(
 7286            self.menu_edit_predictions_policy,
 7287            MenuEditPredictionsPolicy::ByProvider
 7288        );
 7289
 7290        let show_in_menu = by_provider
 7291            && self
 7292                .edit_prediction_provider
 7293                .as_ref()
 7294                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7295
 7296        let preview_requires_modifier =
 7297            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7298
 7299        EditPredictionSettings::Enabled {
 7300            show_in_menu,
 7301            preview_requires_modifier,
 7302        }
 7303    }
 7304
 7305    fn should_show_edit_predictions(&self) -> bool {
 7306        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7307    }
 7308
 7309    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7310        matches!(
 7311            self.edit_prediction_preview,
 7312            EditPredictionPreview::Active { .. }
 7313        )
 7314    }
 7315
 7316    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7317        let cursor = self.selections.newest_anchor().head();
 7318        if let Some((buffer, cursor_position)) =
 7319            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7320        {
 7321            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7322        } else {
 7323            false
 7324        }
 7325    }
 7326
 7327    pub fn supports_minimap(&self, cx: &App) -> bool {
 7328        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7329    }
 7330
 7331    fn edit_predictions_enabled_in_buffer(
 7332        &self,
 7333        buffer: &Entity<Buffer>,
 7334        buffer_position: language::Anchor,
 7335        cx: &App,
 7336    ) -> bool {
 7337        maybe!({
 7338            if self.read_only(cx) {
 7339                return Some(false);
 7340            }
 7341            let provider = self.edit_prediction_provider()?;
 7342            if !provider.is_enabled(buffer, buffer_position, cx) {
 7343                return Some(false);
 7344            }
 7345            let buffer = buffer.read(cx);
 7346            let Some(file) = buffer.file() else {
 7347                return Some(true);
 7348            };
 7349            let settings = all_language_settings(Some(file), cx);
 7350            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7351        })
 7352        .unwrap_or(false)
 7353    }
 7354
 7355    fn cycle_edit_prediction(
 7356        &mut self,
 7357        direction: Direction,
 7358        window: &mut Window,
 7359        cx: &mut Context<Self>,
 7360    ) -> Option<()> {
 7361        let provider = self.edit_prediction_provider()?;
 7362        let cursor = self.selections.newest_anchor().head();
 7363        let (buffer, cursor_buffer_position) =
 7364            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7365        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7366            return None;
 7367        }
 7368
 7369        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7370        self.update_visible_edit_prediction(window, cx);
 7371
 7372        Some(())
 7373    }
 7374
 7375    pub fn show_edit_prediction(
 7376        &mut self,
 7377        _: &ShowEditPrediction,
 7378        window: &mut Window,
 7379        cx: &mut Context<Self>,
 7380    ) {
 7381        if !self.has_active_edit_prediction() {
 7382            self.refresh_edit_prediction(false, true, window, cx);
 7383            return;
 7384        }
 7385
 7386        self.update_visible_edit_prediction(window, cx);
 7387    }
 7388
 7389    pub fn display_cursor_names(
 7390        &mut self,
 7391        _: &DisplayCursorNames,
 7392        window: &mut Window,
 7393        cx: &mut Context<Self>,
 7394    ) {
 7395        self.show_cursor_names(window, cx);
 7396    }
 7397
 7398    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7399        self.show_cursor_names = true;
 7400        cx.notify();
 7401        cx.spawn_in(window, async move |this, cx| {
 7402            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7403            this.update(cx, |this, cx| {
 7404                this.show_cursor_names = false;
 7405                cx.notify()
 7406            })
 7407            .ok()
 7408        })
 7409        .detach();
 7410    }
 7411
 7412    pub fn next_edit_prediction(
 7413        &mut self,
 7414        _: &NextEditPrediction,
 7415        window: &mut Window,
 7416        cx: &mut Context<Self>,
 7417    ) {
 7418        if self.has_active_edit_prediction() {
 7419            self.cycle_edit_prediction(Direction::Next, window, cx);
 7420        } else {
 7421            let is_copilot_disabled = self
 7422                .refresh_edit_prediction(false, true, window, cx)
 7423                .is_none();
 7424            if is_copilot_disabled {
 7425                cx.propagate();
 7426            }
 7427        }
 7428    }
 7429
 7430    pub fn previous_edit_prediction(
 7431        &mut self,
 7432        _: &PreviousEditPrediction,
 7433        window: &mut Window,
 7434        cx: &mut Context<Self>,
 7435    ) {
 7436        if self.has_active_edit_prediction() {
 7437            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7438        } else {
 7439            let is_copilot_disabled = self
 7440                .refresh_edit_prediction(false, true, window, cx)
 7441                .is_none();
 7442            if is_copilot_disabled {
 7443                cx.propagate();
 7444            }
 7445        }
 7446    }
 7447
 7448    pub fn accept_edit_prediction(
 7449        &mut self,
 7450        _: &AcceptEditPrediction,
 7451        window: &mut Window,
 7452        cx: &mut Context<Self>,
 7453    ) {
 7454        if self.show_edit_predictions_in_menu() {
 7455            self.hide_context_menu(window, cx);
 7456        }
 7457
 7458        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7459            return;
 7460        };
 7461
 7462        match &active_edit_prediction.completion {
 7463            EditPrediction::MoveWithin { target, .. } => {
 7464                let target = *target;
 7465
 7466                if let Some(position_map) = &self.last_position_map {
 7467                    if position_map
 7468                        .visible_row_range
 7469                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7470                        || !self.edit_prediction_requires_modifier()
 7471                    {
 7472                        self.unfold_ranges(&[target..target], true, false, cx);
 7473                        // Note that this is also done in vim's handler of the Tab action.
 7474                        self.change_selections(
 7475                            SelectionEffects::scroll(Autoscroll::newest()),
 7476                            window,
 7477                            cx,
 7478                            |selections| {
 7479                                selections.select_anchor_ranges([target..target]);
 7480                            },
 7481                        );
 7482                        self.clear_row_highlights::<EditPredictionPreview>();
 7483
 7484                        self.edit_prediction_preview
 7485                            .set_previous_scroll_position(None);
 7486                    } else {
 7487                        self.edit_prediction_preview
 7488                            .set_previous_scroll_position(Some(
 7489                                position_map.snapshot.scroll_anchor,
 7490                            ));
 7491
 7492                        self.highlight_rows::<EditPredictionPreview>(
 7493                            target..target,
 7494                            cx.theme().colors().editor_highlighted_line_background,
 7495                            RowHighlightOptions {
 7496                                autoscroll: true,
 7497                                ..Default::default()
 7498                            },
 7499                            cx,
 7500                        );
 7501                        self.request_autoscroll(Autoscroll::fit(), cx);
 7502                    }
 7503                }
 7504            }
 7505            EditPrediction::MoveOutside { snapshot, target } => {
 7506                if let Some(workspace) = self.workspace() {
 7507                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7508                        .detach_and_log_err(cx);
 7509                }
 7510            }
 7511            EditPrediction::Edit { edits, .. } => {
 7512                self.report_edit_prediction_event(
 7513                    active_edit_prediction.completion_id.clone(),
 7514                    true,
 7515                    cx,
 7516                );
 7517
 7518                if let Some(provider) = self.edit_prediction_provider() {
 7519                    provider.accept(cx);
 7520                }
 7521
 7522                // Store the transaction ID and selections before applying the edit
 7523                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7524
 7525                let snapshot = self.buffer.read(cx).snapshot(cx);
 7526                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7527
 7528                self.buffer.update(cx, |buffer, cx| {
 7529                    buffer.edit(edits.iter().cloned(), None, cx)
 7530                });
 7531
 7532                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7533                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7534                });
 7535
 7536                let selections = self.selections.disjoint_anchors_arc();
 7537                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7538                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7539                    if has_new_transaction {
 7540                        self.selection_history
 7541                            .insert_transaction(transaction_id_now, selections);
 7542                    }
 7543                }
 7544
 7545                self.update_visible_edit_prediction(window, cx);
 7546                if self.active_edit_prediction.is_none() {
 7547                    self.refresh_edit_prediction(true, true, window, cx);
 7548                }
 7549
 7550                cx.notify();
 7551            }
 7552        }
 7553
 7554        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7555    }
 7556
 7557    pub fn accept_partial_edit_prediction(
 7558        &mut self,
 7559        _: &AcceptPartialEditPrediction,
 7560        window: &mut Window,
 7561        cx: &mut Context<Self>,
 7562    ) {
 7563        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7564            return;
 7565        };
 7566        if self.selections.count() != 1 {
 7567            return;
 7568        }
 7569
 7570        match &active_edit_prediction.completion {
 7571            EditPrediction::MoveWithin { target, .. } => {
 7572                let target = *target;
 7573                self.change_selections(
 7574                    SelectionEffects::scroll(Autoscroll::newest()),
 7575                    window,
 7576                    cx,
 7577                    |selections| {
 7578                        selections.select_anchor_ranges([target..target]);
 7579                    },
 7580                );
 7581            }
 7582            EditPrediction::MoveOutside { snapshot, target } => {
 7583                if let Some(workspace) = self.workspace() {
 7584                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7585                        .detach_and_log_err(cx);
 7586                }
 7587            }
 7588            EditPrediction::Edit { edits, .. } => {
 7589                self.report_edit_prediction_event(
 7590                    active_edit_prediction.completion_id.clone(),
 7591                    true,
 7592                    cx,
 7593                );
 7594
 7595                // Find an insertion that starts at the cursor position.
 7596                let snapshot = self.buffer.read(cx).snapshot(cx);
 7597                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7598                let insertion = edits.iter().find_map(|(range, text)| {
 7599                    let range = range.to_offset(&snapshot);
 7600                    if range.is_empty() && range.start == cursor_offset {
 7601                        Some(text)
 7602                    } else {
 7603                        None
 7604                    }
 7605                });
 7606
 7607                if let Some(text) = insertion {
 7608                    let mut partial_completion = text
 7609                        .chars()
 7610                        .by_ref()
 7611                        .take_while(|c| c.is_alphabetic())
 7612                        .collect::<String>();
 7613                    if partial_completion.is_empty() {
 7614                        partial_completion = text
 7615                            .chars()
 7616                            .by_ref()
 7617                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7618                            .collect::<String>();
 7619                    }
 7620
 7621                    cx.emit(EditorEvent::InputHandled {
 7622                        utf16_range_to_replace: None,
 7623                        text: partial_completion.clone().into(),
 7624                    });
 7625
 7626                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7627
 7628                    self.refresh_edit_prediction(true, true, window, cx);
 7629                    cx.notify();
 7630                } else {
 7631                    self.accept_edit_prediction(&Default::default(), window, cx);
 7632                }
 7633            }
 7634        }
 7635    }
 7636
 7637    fn discard_edit_prediction(
 7638        &mut self,
 7639        should_report_edit_prediction_event: bool,
 7640        cx: &mut Context<Self>,
 7641    ) -> bool {
 7642        if should_report_edit_prediction_event {
 7643            let completion_id = self
 7644                .active_edit_prediction
 7645                .as_ref()
 7646                .and_then(|active_completion| active_completion.completion_id.clone());
 7647
 7648            self.report_edit_prediction_event(completion_id, false, cx);
 7649        }
 7650
 7651        if let Some(provider) = self.edit_prediction_provider() {
 7652            provider.discard(cx);
 7653        }
 7654
 7655        self.take_active_edit_prediction(cx)
 7656    }
 7657
 7658    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7659        let Some(provider) = self.edit_prediction_provider() else {
 7660            return;
 7661        };
 7662
 7663        let Some((_, buffer, _)) = self
 7664            .buffer
 7665            .read(cx)
 7666            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7667        else {
 7668            return;
 7669        };
 7670
 7671        let extension = buffer
 7672            .read(cx)
 7673            .file()
 7674            .and_then(|file| Some(file.path().extension()?.to_string()));
 7675
 7676        let event_type = match accepted {
 7677            true => "Edit Prediction Accepted",
 7678            false => "Edit Prediction Discarded",
 7679        };
 7680        telemetry::event!(
 7681            event_type,
 7682            provider = provider.name(),
 7683            prediction_id = id,
 7684            suggestion_accepted = accepted,
 7685            file_extension = extension,
 7686        );
 7687    }
 7688
 7689    fn open_editor_at_anchor(
 7690        snapshot: &language::BufferSnapshot,
 7691        target: language::Anchor,
 7692        workspace: &Entity<Workspace>,
 7693        window: &mut Window,
 7694        cx: &mut App,
 7695    ) -> Task<Result<()>> {
 7696        workspace.update(cx, |workspace, cx| {
 7697            let path = snapshot.file().map(|file| file.full_path(cx));
 7698            let Some(path) =
 7699                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7700            else {
 7701                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7702            };
 7703            let target = text::ToPoint::to_point(&target, snapshot);
 7704            let item = workspace.open_path(path, None, true, window, cx);
 7705            window.spawn(cx, async move |cx| {
 7706                let Some(editor) = item.await?.downcast::<Editor>() else {
 7707                    return Ok(());
 7708                };
 7709                editor
 7710                    .update_in(cx, |editor, window, cx| {
 7711                        editor.go_to_singleton_buffer_point(target, window, cx);
 7712                    })
 7713                    .ok();
 7714                anyhow::Ok(())
 7715            })
 7716        })
 7717    }
 7718
 7719    pub fn has_active_edit_prediction(&self) -> bool {
 7720        self.active_edit_prediction.is_some()
 7721    }
 7722
 7723    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7724        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7725            return false;
 7726        };
 7727
 7728        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7729        self.clear_highlights::<EditPredictionHighlight>(cx);
 7730        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7731        true
 7732    }
 7733
 7734    /// Returns true when we're displaying the edit prediction popover below the cursor
 7735    /// like we are not previewing and the LSP autocomplete menu is visible
 7736    /// or we are in `when_holding_modifier` mode.
 7737    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7738        if self.edit_prediction_preview_is_active()
 7739            || !self.show_edit_predictions_in_menu()
 7740            || !self.edit_predictions_enabled()
 7741        {
 7742            return false;
 7743        }
 7744
 7745        if self.has_visible_completions_menu() {
 7746            return true;
 7747        }
 7748
 7749        has_completion && self.edit_prediction_requires_modifier()
 7750    }
 7751
 7752    fn handle_modifiers_changed(
 7753        &mut self,
 7754        modifiers: Modifiers,
 7755        position_map: &PositionMap,
 7756        window: &mut Window,
 7757        cx: &mut Context<Self>,
 7758    ) {
 7759        if self.show_edit_predictions_in_menu() {
 7760            self.update_edit_prediction_preview(&modifiers, window, cx);
 7761        }
 7762
 7763        self.update_selection_mode(&modifiers, position_map, window, cx);
 7764
 7765        let mouse_position = window.mouse_position();
 7766        if !position_map.text_hitbox.is_hovered(window) {
 7767            return;
 7768        }
 7769
 7770        self.update_hovered_link(
 7771            position_map.point_for_position(mouse_position),
 7772            &position_map.snapshot,
 7773            modifiers,
 7774            window,
 7775            cx,
 7776        )
 7777    }
 7778
 7779    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7780        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7781        if invert {
 7782            match multi_cursor_setting {
 7783                MultiCursorModifier::Alt => modifiers.alt,
 7784                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7785            }
 7786        } else {
 7787            match multi_cursor_setting {
 7788                MultiCursorModifier::Alt => modifiers.secondary(),
 7789                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7790            }
 7791        }
 7792    }
 7793
 7794    fn columnar_selection_mode(
 7795        modifiers: &Modifiers,
 7796        cx: &mut Context<Self>,
 7797    ) -> Option<ColumnarMode> {
 7798        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7799            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7800                Some(ColumnarMode::FromMouse)
 7801            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7802                Some(ColumnarMode::FromSelection)
 7803            } else {
 7804                None
 7805            }
 7806        } else {
 7807            None
 7808        }
 7809    }
 7810
 7811    fn update_selection_mode(
 7812        &mut self,
 7813        modifiers: &Modifiers,
 7814        position_map: &PositionMap,
 7815        window: &mut Window,
 7816        cx: &mut Context<Self>,
 7817    ) {
 7818        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7819            return;
 7820        };
 7821        if self.selections.pending_anchor().is_none() {
 7822            return;
 7823        }
 7824
 7825        let mouse_position = window.mouse_position();
 7826        let point_for_position = position_map.point_for_position(mouse_position);
 7827        let position = point_for_position.previous_valid;
 7828
 7829        self.select(
 7830            SelectPhase::BeginColumnar {
 7831                position,
 7832                reset: false,
 7833                mode,
 7834                goal_column: point_for_position.exact_unclipped.column(),
 7835            },
 7836            window,
 7837            cx,
 7838        );
 7839    }
 7840
 7841    fn update_edit_prediction_preview(
 7842        &mut self,
 7843        modifiers: &Modifiers,
 7844        window: &mut Window,
 7845        cx: &mut Context<Self>,
 7846    ) {
 7847        let mut modifiers_held = false;
 7848        if let Some(accept_keystroke) = self
 7849            .accept_edit_prediction_keybind(false, window, cx)
 7850            .keystroke()
 7851        {
 7852            modifiers_held = modifiers_held
 7853                || (accept_keystroke.modifiers() == modifiers
 7854                    && accept_keystroke.modifiers().modified());
 7855        };
 7856        if let Some(accept_partial_keystroke) = self
 7857            .accept_edit_prediction_keybind(true, window, cx)
 7858            .keystroke()
 7859        {
 7860            modifiers_held = modifiers_held
 7861                || (accept_partial_keystroke.modifiers() == modifiers
 7862                    && accept_partial_keystroke.modifiers().modified());
 7863        }
 7864
 7865        if modifiers_held {
 7866            if matches!(
 7867                self.edit_prediction_preview,
 7868                EditPredictionPreview::Inactive { .. }
 7869            ) {
 7870                self.edit_prediction_preview = EditPredictionPreview::Active {
 7871                    previous_scroll_position: None,
 7872                    since: Instant::now(),
 7873                };
 7874
 7875                self.update_visible_edit_prediction(window, cx);
 7876                cx.notify();
 7877            }
 7878        } else if let EditPredictionPreview::Active {
 7879            previous_scroll_position,
 7880            since,
 7881        } = self.edit_prediction_preview
 7882        {
 7883            if let (Some(previous_scroll_position), Some(position_map)) =
 7884                (previous_scroll_position, self.last_position_map.as_ref())
 7885            {
 7886                self.set_scroll_position(
 7887                    previous_scroll_position
 7888                        .scroll_position(&position_map.snapshot.display_snapshot),
 7889                    window,
 7890                    cx,
 7891                );
 7892            }
 7893
 7894            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7895                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7896            };
 7897            self.clear_row_highlights::<EditPredictionPreview>();
 7898            self.update_visible_edit_prediction(window, cx);
 7899            cx.notify();
 7900        }
 7901    }
 7902
 7903    fn update_visible_edit_prediction(
 7904        &mut self,
 7905        _window: &mut Window,
 7906        cx: &mut Context<Self>,
 7907    ) -> Option<()> {
 7908        if DisableAiSettings::get_global(cx).disable_ai {
 7909            return None;
 7910        }
 7911
 7912        if self.ime_transaction.is_some() {
 7913            self.discard_edit_prediction(false, cx);
 7914            return None;
 7915        }
 7916
 7917        let selection = self.selections.newest_anchor();
 7918        let cursor = selection.head();
 7919        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7920        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7921        let excerpt_id = cursor.excerpt_id;
 7922
 7923        let show_in_menu = self.show_edit_predictions_in_menu();
 7924        let completions_menu_has_precedence = !show_in_menu
 7925            && (self.context_menu.borrow().is_some()
 7926                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7927
 7928        if completions_menu_has_precedence
 7929            || !offset_selection.is_empty()
 7930            || self
 7931                .active_edit_prediction
 7932                .as_ref()
 7933                .is_some_and(|completion| {
 7934                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7935                        return false;
 7936                    };
 7937                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7938                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7939                    !invalidation_range.contains(&offset_selection.head())
 7940                })
 7941        {
 7942            self.discard_edit_prediction(false, cx);
 7943            return None;
 7944        }
 7945
 7946        self.take_active_edit_prediction(cx);
 7947        let Some(provider) = self.edit_prediction_provider() else {
 7948            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7949            return None;
 7950        };
 7951
 7952        let (buffer, cursor_buffer_position) =
 7953            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7954
 7955        self.edit_prediction_settings =
 7956            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7957
 7958        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7959
 7960        if self.edit_prediction_indent_conflict {
 7961            let cursor_point = cursor.to_point(&multibuffer);
 7962
 7963            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7964
 7965            if let Some((_, indent)) = indents.iter().next()
 7966                && indent.len == cursor_point.column
 7967            {
 7968                self.edit_prediction_indent_conflict = false;
 7969            }
 7970        }
 7971
 7972        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7973
 7974        let (completion_id, edits, edit_preview) = match edit_prediction {
 7975            edit_prediction::EditPrediction::Local {
 7976                id,
 7977                edits,
 7978                edit_preview,
 7979            } => (id, edits, edit_preview),
 7980            edit_prediction::EditPrediction::Jump {
 7981                id,
 7982                snapshot,
 7983                target,
 7984            } => {
 7985                self.stale_edit_prediction_in_menu = None;
 7986                self.active_edit_prediction = Some(EditPredictionState {
 7987                    inlay_ids: vec![],
 7988                    completion: EditPrediction::MoveOutside { snapshot, target },
 7989                    completion_id: id,
 7990                    invalidation_range: None,
 7991                });
 7992                cx.notify();
 7993                return Some(());
 7994            }
 7995        };
 7996
 7997        let edits = edits
 7998            .into_iter()
 7999            .flat_map(|(range, new_text)| {
 8000                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 8001                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 8002                Some((start..end, new_text))
 8003            })
 8004            .collect::<Vec<_>>();
 8005        if edits.is_empty() {
 8006            return None;
 8007        }
 8008
 8009        let first_edit_start = edits.first().unwrap().0.start;
 8010        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8011        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8012
 8013        let last_edit_end = edits.last().unwrap().0.end;
 8014        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8015        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8016
 8017        let cursor_row = cursor.to_point(&multibuffer).row;
 8018
 8019        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8020
 8021        let mut inlay_ids = Vec::new();
 8022        let invalidation_row_range;
 8023        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8024            Some(cursor_row..edit_end_row)
 8025        } else if cursor_row > edit_end_row {
 8026            Some(edit_start_row..cursor_row)
 8027        } else {
 8028            None
 8029        };
 8030        let supports_jump = self
 8031            .edit_prediction_provider
 8032            .as_ref()
 8033            .map(|provider| provider.provider.supports_jump_to_edit())
 8034            .unwrap_or(true);
 8035
 8036        let is_move = supports_jump
 8037            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8038        let completion = if is_move {
 8039            invalidation_row_range =
 8040                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8041            let target = first_edit_start;
 8042            EditPrediction::MoveWithin { target, snapshot }
 8043        } else {
 8044            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8045                && !self.edit_predictions_hidden_for_vim_mode;
 8046
 8047            if show_completions_in_buffer {
 8048                if edits
 8049                    .iter()
 8050                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8051                {
 8052                    let mut inlays = Vec::new();
 8053                    for (range, new_text) in &edits {
 8054                        let inlay = Inlay::edit_prediction(
 8055                            post_inc(&mut self.next_inlay_id),
 8056                            range.start,
 8057                            new_text.as_str(),
 8058                        );
 8059                        inlay_ids.push(inlay.id);
 8060                        inlays.push(inlay);
 8061                    }
 8062
 8063                    self.splice_inlays(&[], inlays, cx);
 8064                } else {
 8065                    let background_color = cx.theme().status().deleted_background;
 8066                    self.highlight_text::<EditPredictionHighlight>(
 8067                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8068                        HighlightStyle {
 8069                            background_color: Some(background_color),
 8070                            ..Default::default()
 8071                        },
 8072                        cx,
 8073                    );
 8074                }
 8075            }
 8076
 8077            invalidation_row_range = edit_start_row..edit_end_row;
 8078
 8079            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8080                if provider.show_tab_accept_marker() {
 8081                    EditDisplayMode::TabAccept
 8082                } else {
 8083                    EditDisplayMode::Inline
 8084                }
 8085            } else {
 8086                EditDisplayMode::DiffPopover
 8087            };
 8088
 8089            EditPrediction::Edit {
 8090                edits,
 8091                edit_preview,
 8092                display_mode,
 8093                snapshot,
 8094            }
 8095        };
 8096
 8097        let invalidation_range = multibuffer
 8098            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8099            ..multibuffer.anchor_after(Point::new(
 8100                invalidation_row_range.end,
 8101                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8102            ));
 8103
 8104        self.stale_edit_prediction_in_menu = None;
 8105        self.active_edit_prediction = Some(EditPredictionState {
 8106            inlay_ids,
 8107            completion,
 8108            completion_id,
 8109            invalidation_range: Some(invalidation_range),
 8110        });
 8111
 8112        cx.notify();
 8113
 8114        Some(())
 8115    }
 8116
 8117    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8118        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8119    }
 8120
 8121    fn clear_tasks(&mut self) {
 8122        self.tasks.clear()
 8123    }
 8124
 8125    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8126        if self.tasks.insert(key, value).is_some() {
 8127            // This case should hopefully be rare, but just in case...
 8128            log::error!(
 8129                "multiple different run targets found on a single line, only the last target will be rendered"
 8130            )
 8131        }
 8132    }
 8133
 8134    /// Get all display points of breakpoints that will be rendered within editor
 8135    ///
 8136    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8137    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8138    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8139    fn active_breakpoints(
 8140        &self,
 8141        range: Range<DisplayRow>,
 8142        window: &mut Window,
 8143        cx: &mut Context<Self>,
 8144    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8145        let mut breakpoint_display_points = HashMap::default();
 8146
 8147        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8148            return breakpoint_display_points;
 8149        };
 8150
 8151        let snapshot = self.snapshot(window, cx);
 8152
 8153        let multi_buffer_snapshot = snapshot.display_snapshot.buffer_snapshot();
 8154        let Some(project) = self.project() else {
 8155            return breakpoint_display_points;
 8156        };
 8157
 8158        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8159            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8160
 8161        for (buffer_snapshot, range, excerpt_id) in
 8162            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8163        {
 8164            let Some(buffer) = project
 8165                .read(cx)
 8166                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8167            else {
 8168                continue;
 8169            };
 8170            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8171                &buffer,
 8172                Some(
 8173                    buffer_snapshot.anchor_before(range.start)
 8174                        ..buffer_snapshot.anchor_after(range.end),
 8175                ),
 8176                buffer_snapshot,
 8177                cx,
 8178            );
 8179            for (breakpoint, state) in breakpoints {
 8180                let multi_buffer_anchor =
 8181                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8182                let position = multi_buffer_anchor
 8183                    .to_point(multi_buffer_snapshot)
 8184                    .to_display_point(&snapshot);
 8185
 8186                breakpoint_display_points.insert(
 8187                    position.row(),
 8188                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8189                );
 8190            }
 8191        }
 8192
 8193        breakpoint_display_points
 8194    }
 8195
 8196    fn breakpoint_context_menu(
 8197        &self,
 8198        anchor: Anchor,
 8199        window: &mut Window,
 8200        cx: &mut Context<Self>,
 8201    ) -> Entity<ui::ContextMenu> {
 8202        let weak_editor = cx.weak_entity();
 8203        let focus_handle = self.focus_handle(cx);
 8204
 8205        let row = self
 8206            .buffer
 8207            .read(cx)
 8208            .snapshot(cx)
 8209            .summary_for_anchor::<Point>(&anchor)
 8210            .row;
 8211
 8212        let breakpoint = self
 8213            .breakpoint_at_row(row, window, cx)
 8214            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8215
 8216        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8217            "Edit Log Breakpoint"
 8218        } else {
 8219            "Set Log Breakpoint"
 8220        };
 8221
 8222        let condition_breakpoint_msg = if breakpoint
 8223            .as_ref()
 8224            .is_some_and(|bp| bp.1.condition.is_some())
 8225        {
 8226            "Edit Condition Breakpoint"
 8227        } else {
 8228            "Set Condition Breakpoint"
 8229        };
 8230
 8231        let hit_condition_breakpoint_msg = if breakpoint
 8232            .as_ref()
 8233            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8234        {
 8235            "Edit Hit Condition Breakpoint"
 8236        } else {
 8237            "Set Hit Condition Breakpoint"
 8238        };
 8239
 8240        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8241            "Unset Breakpoint"
 8242        } else {
 8243            "Set Breakpoint"
 8244        };
 8245
 8246        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8247
 8248        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8249            BreakpointState::Enabled => Some("Disable"),
 8250            BreakpointState::Disabled => Some("Enable"),
 8251        });
 8252
 8253        let (anchor, breakpoint) =
 8254            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8255
 8256        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8257            menu.on_blur_subscription(Subscription::new(|| {}))
 8258                .context(focus_handle)
 8259                .when(run_to_cursor, |this| {
 8260                    let weak_editor = weak_editor.clone();
 8261                    this.entry("Run to cursor", None, move |window, cx| {
 8262                        weak_editor
 8263                            .update(cx, |editor, cx| {
 8264                                editor.change_selections(
 8265                                    SelectionEffects::no_scroll(),
 8266                                    window,
 8267                                    cx,
 8268                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8269                                );
 8270                            })
 8271                            .ok();
 8272
 8273                        window.dispatch_action(Box::new(RunToCursor), cx);
 8274                    })
 8275                    .separator()
 8276                })
 8277                .when_some(toggle_state_msg, |this, msg| {
 8278                    this.entry(msg, None, {
 8279                        let weak_editor = weak_editor.clone();
 8280                        let breakpoint = breakpoint.clone();
 8281                        move |_window, cx| {
 8282                            weak_editor
 8283                                .update(cx, |this, cx| {
 8284                                    this.edit_breakpoint_at_anchor(
 8285                                        anchor,
 8286                                        breakpoint.as_ref().clone(),
 8287                                        BreakpointEditAction::InvertState,
 8288                                        cx,
 8289                                    );
 8290                                })
 8291                                .log_err();
 8292                        }
 8293                    })
 8294                })
 8295                .entry(set_breakpoint_msg, None, {
 8296                    let weak_editor = weak_editor.clone();
 8297                    let breakpoint = breakpoint.clone();
 8298                    move |_window, cx| {
 8299                        weak_editor
 8300                            .update(cx, |this, cx| {
 8301                                this.edit_breakpoint_at_anchor(
 8302                                    anchor,
 8303                                    breakpoint.as_ref().clone(),
 8304                                    BreakpointEditAction::Toggle,
 8305                                    cx,
 8306                                );
 8307                            })
 8308                            .log_err();
 8309                    }
 8310                })
 8311                .entry(log_breakpoint_msg, None, {
 8312                    let breakpoint = breakpoint.clone();
 8313                    let weak_editor = weak_editor.clone();
 8314                    move |window, cx| {
 8315                        weak_editor
 8316                            .update(cx, |this, cx| {
 8317                                this.add_edit_breakpoint_block(
 8318                                    anchor,
 8319                                    breakpoint.as_ref(),
 8320                                    BreakpointPromptEditAction::Log,
 8321                                    window,
 8322                                    cx,
 8323                                );
 8324                            })
 8325                            .log_err();
 8326                    }
 8327                })
 8328                .entry(condition_breakpoint_msg, None, {
 8329                    let breakpoint = breakpoint.clone();
 8330                    let weak_editor = weak_editor.clone();
 8331                    move |window, cx| {
 8332                        weak_editor
 8333                            .update(cx, |this, cx| {
 8334                                this.add_edit_breakpoint_block(
 8335                                    anchor,
 8336                                    breakpoint.as_ref(),
 8337                                    BreakpointPromptEditAction::Condition,
 8338                                    window,
 8339                                    cx,
 8340                                );
 8341                            })
 8342                            .log_err();
 8343                    }
 8344                })
 8345                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8346                    weak_editor
 8347                        .update(cx, |this, cx| {
 8348                            this.add_edit_breakpoint_block(
 8349                                anchor,
 8350                                breakpoint.as_ref(),
 8351                                BreakpointPromptEditAction::HitCondition,
 8352                                window,
 8353                                cx,
 8354                            );
 8355                        })
 8356                        .log_err();
 8357                })
 8358        })
 8359    }
 8360
 8361    fn render_breakpoint(
 8362        &self,
 8363        position: Anchor,
 8364        row: DisplayRow,
 8365        breakpoint: &Breakpoint,
 8366        state: Option<BreakpointSessionState>,
 8367        cx: &mut Context<Self>,
 8368    ) -> IconButton {
 8369        let is_rejected = state.is_some_and(|s| !s.verified);
 8370        // Is it a breakpoint that shows up when hovering over gutter?
 8371        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8372            (false, false),
 8373            |PhantomBreakpointIndicator {
 8374                 is_active,
 8375                 display_row,
 8376                 collides_with_existing_breakpoint,
 8377             }| {
 8378                (
 8379                    is_active && display_row == row,
 8380                    collides_with_existing_breakpoint,
 8381                )
 8382            },
 8383        );
 8384
 8385        let (color, icon) = {
 8386            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8387                (false, false) => ui::IconName::DebugBreakpoint,
 8388                (true, false) => ui::IconName::DebugLogBreakpoint,
 8389                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8390                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8391            };
 8392
 8393            let color = if is_phantom {
 8394                Color::Hint
 8395            } else if is_rejected {
 8396                Color::Disabled
 8397            } else {
 8398                Color::Debugger
 8399            };
 8400
 8401            (color, icon)
 8402        };
 8403
 8404        let breakpoint = Arc::from(breakpoint.clone());
 8405
 8406        let alt_as_text = gpui::Keystroke {
 8407            modifiers: Modifiers::secondary_key(),
 8408            ..Default::default()
 8409        };
 8410        let primary_action_text = if breakpoint.is_disabled() {
 8411            "Enable breakpoint"
 8412        } else if is_phantom && !collides_with_existing {
 8413            "Set breakpoint"
 8414        } else {
 8415            "Unset breakpoint"
 8416        };
 8417        let focus_handle = self.focus_handle.clone();
 8418
 8419        let meta = if is_rejected {
 8420            SharedString::from("No executable code is associated with this line.")
 8421        } else if collides_with_existing && !breakpoint.is_disabled() {
 8422            SharedString::from(format!(
 8423                "{alt_as_text}-click to disable,\nright-click for more options."
 8424            ))
 8425        } else {
 8426            SharedString::from("Right-click for more options.")
 8427        };
 8428        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8429            .icon_size(IconSize::XSmall)
 8430            .size(ui::ButtonSize::None)
 8431            .when(is_rejected, |this| {
 8432                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8433            })
 8434            .icon_color(color)
 8435            .style(ButtonStyle::Transparent)
 8436            .on_click(cx.listener({
 8437                move |editor, event: &ClickEvent, window, cx| {
 8438                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8439                        BreakpointEditAction::InvertState
 8440                    } else {
 8441                        BreakpointEditAction::Toggle
 8442                    };
 8443
 8444                    window.focus(&editor.focus_handle(cx));
 8445                    editor.edit_breakpoint_at_anchor(
 8446                        position,
 8447                        breakpoint.as_ref().clone(),
 8448                        edit_action,
 8449                        cx,
 8450                    );
 8451                }
 8452            }))
 8453            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8454                editor.set_breakpoint_context_menu(
 8455                    row,
 8456                    Some(position),
 8457                    event.position(),
 8458                    window,
 8459                    cx,
 8460                );
 8461            }))
 8462            .tooltip(move |window, cx| {
 8463                Tooltip::with_meta_in(
 8464                    primary_action_text,
 8465                    Some(&ToggleBreakpoint),
 8466                    meta.clone(),
 8467                    &focus_handle,
 8468                    window,
 8469                    cx,
 8470                )
 8471            })
 8472    }
 8473
 8474    fn build_tasks_context(
 8475        project: &Entity<Project>,
 8476        buffer: &Entity<Buffer>,
 8477        buffer_row: u32,
 8478        tasks: &Arc<RunnableTasks>,
 8479        cx: &mut Context<Self>,
 8480    ) -> Task<Option<task::TaskContext>> {
 8481        let position = Point::new(buffer_row, tasks.column);
 8482        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8483        let location = Location {
 8484            buffer: buffer.clone(),
 8485            range: range_start..range_start,
 8486        };
 8487        // Fill in the environmental variables from the tree-sitter captures
 8488        let mut captured_task_variables = TaskVariables::default();
 8489        for (capture_name, value) in tasks.extra_variables.clone() {
 8490            captured_task_variables.insert(
 8491                task::VariableName::Custom(capture_name.into()),
 8492                value.clone(),
 8493            );
 8494        }
 8495        project.update(cx, |project, cx| {
 8496            project.task_store().update(cx, |task_store, cx| {
 8497                task_store.task_context_for_location(captured_task_variables, location, cx)
 8498            })
 8499        })
 8500    }
 8501
 8502    pub fn spawn_nearest_task(
 8503        &mut self,
 8504        action: &SpawnNearestTask,
 8505        window: &mut Window,
 8506        cx: &mut Context<Self>,
 8507    ) {
 8508        let Some((workspace, _)) = self.workspace.clone() else {
 8509            return;
 8510        };
 8511        let Some(project) = self.project.clone() else {
 8512            return;
 8513        };
 8514
 8515        // Try to find a closest, enclosing node using tree-sitter that has a task
 8516        let Some((buffer, buffer_row, tasks)) = self
 8517            .find_enclosing_node_task(cx)
 8518            // Or find the task that's closest in row-distance.
 8519            .or_else(|| self.find_closest_task(cx))
 8520        else {
 8521            return;
 8522        };
 8523
 8524        let reveal_strategy = action.reveal;
 8525        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8526        cx.spawn_in(window, async move |_, cx| {
 8527            let context = task_context.await?;
 8528            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8529
 8530            let resolved = &mut resolved_task.resolved;
 8531            resolved.reveal = reveal_strategy;
 8532
 8533            workspace
 8534                .update_in(cx, |workspace, window, cx| {
 8535                    workspace.schedule_resolved_task(
 8536                        task_source_kind,
 8537                        resolved_task,
 8538                        false,
 8539                        window,
 8540                        cx,
 8541                    );
 8542                })
 8543                .ok()
 8544        })
 8545        .detach();
 8546    }
 8547
 8548    fn find_closest_task(
 8549        &mut self,
 8550        cx: &mut Context<Self>,
 8551    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8552        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8553
 8554        let ((buffer_id, row), tasks) = self
 8555            .tasks
 8556            .iter()
 8557            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8558
 8559        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8560        let tasks = Arc::new(tasks.to_owned());
 8561        Some((buffer, *row, tasks))
 8562    }
 8563
 8564    fn find_enclosing_node_task(
 8565        &mut self,
 8566        cx: &mut Context<Self>,
 8567    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8568        let snapshot = self.buffer.read(cx).snapshot(cx);
 8569        let offset = self.selections.newest::<usize>(cx).head();
 8570        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8571        let buffer_id = excerpt.buffer().remote_id();
 8572
 8573        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8574        let mut cursor = layer.node().walk();
 8575
 8576        while cursor.goto_first_child_for_byte(offset).is_some() {
 8577            if cursor.node().end_byte() == offset {
 8578                cursor.goto_next_sibling();
 8579            }
 8580        }
 8581
 8582        // Ascend to the smallest ancestor that contains the range and has a task.
 8583        loop {
 8584            let node = cursor.node();
 8585            let node_range = node.byte_range();
 8586            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8587
 8588            // Check if this node contains our offset
 8589            if node_range.start <= offset && node_range.end >= offset {
 8590                // If it contains offset, check for task
 8591                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8592                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8593                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8594                }
 8595            }
 8596
 8597            if !cursor.goto_parent() {
 8598                break;
 8599            }
 8600        }
 8601        None
 8602    }
 8603
 8604    fn render_run_indicator(
 8605        &self,
 8606        _style: &EditorStyle,
 8607        is_active: bool,
 8608        row: DisplayRow,
 8609        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8610        cx: &mut Context<Self>,
 8611    ) -> IconButton {
 8612        let color = Color::Muted;
 8613        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8614
 8615        IconButton::new(
 8616            ("run_indicator", row.0 as usize),
 8617            ui::IconName::PlayOutlined,
 8618        )
 8619        .shape(ui::IconButtonShape::Square)
 8620        .icon_size(IconSize::XSmall)
 8621        .icon_color(color)
 8622        .toggle_state(is_active)
 8623        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8624            let quick_launch = match e {
 8625                ClickEvent::Keyboard(_) => true,
 8626                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8627            };
 8628
 8629            window.focus(&editor.focus_handle(cx));
 8630            editor.toggle_code_actions(
 8631                &ToggleCodeActions {
 8632                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8633                    quick_launch,
 8634                },
 8635                window,
 8636                cx,
 8637            );
 8638        }))
 8639        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8640            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8641        }))
 8642    }
 8643
 8644    pub fn context_menu_visible(&self) -> bool {
 8645        !self.edit_prediction_preview_is_active()
 8646            && self
 8647                .context_menu
 8648                .borrow()
 8649                .as_ref()
 8650                .is_some_and(|menu| menu.visible())
 8651    }
 8652
 8653    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8654        self.context_menu
 8655            .borrow()
 8656            .as_ref()
 8657            .map(|menu| menu.origin())
 8658    }
 8659
 8660    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8661        self.context_menu_options = Some(options);
 8662    }
 8663
 8664    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8665    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8666
 8667    fn render_edit_prediction_popover(
 8668        &mut self,
 8669        text_bounds: &Bounds<Pixels>,
 8670        content_origin: gpui::Point<Pixels>,
 8671        right_margin: Pixels,
 8672        editor_snapshot: &EditorSnapshot,
 8673        visible_row_range: Range<DisplayRow>,
 8674        scroll_top: ScrollOffset,
 8675        scroll_bottom: ScrollOffset,
 8676        line_layouts: &[LineWithInvisibles],
 8677        line_height: Pixels,
 8678        scroll_position: gpui::Point<ScrollOffset>,
 8679        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8680        newest_selection_head: Option<DisplayPoint>,
 8681        editor_width: Pixels,
 8682        style: &EditorStyle,
 8683        window: &mut Window,
 8684        cx: &mut App,
 8685    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8686        if self.mode().is_minimap() {
 8687            return None;
 8688        }
 8689        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8690
 8691        if self.edit_prediction_visible_in_cursor_popover(true) {
 8692            return None;
 8693        }
 8694
 8695        match &active_edit_prediction.completion {
 8696            EditPrediction::MoveWithin { target, .. } => {
 8697                let target_display_point = target.to_display_point(editor_snapshot);
 8698
 8699                if self.edit_prediction_requires_modifier() {
 8700                    if !self.edit_prediction_preview_is_active() {
 8701                        return None;
 8702                    }
 8703
 8704                    self.render_edit_prediction_modifier_jump_popover(
 8705                        text_bounds,
 8706                        content_origin,
 8707                        visible_row_range,
 8708                        line_layouts,
 8709                        line_height,
 8710                        scroll_pixel_position,
 8711                        newest_selection_head,
 8712                        target_display_point,
 8713                        window,
 8714                        cx,
 8715                    )
 8716                } else {
 8717                    self.render_edit_prediction_eager_jump_popover(
 8718                        text_bounds,
 8719                        content_origin,
 8720                        editor_snapshot,
 8721                        visible_row_range,
 8722                        scroll_top,
 8723                        scroll_bottom,
 8724                        line_height,
 8725                        scroll_pixel_position,
 8726                        target_display_point,
 8727                        editor_width,
 8728                        window,
 8729                        cx,
 8730                    )
 8731                }
 8732            }
 8733            EditPrediction::Edit {
 8734                display_mode: EditDisplayMode::Inline,
 8735                ..
 8736            } => None,
 8737            EditPrediction::Edit {
 8738                display_mode: EditDisplayMode::TabAccept,
 8739                edits,
 8740                ..
 8741            } => {
 8742                let range = &edits.first()?.0;
 8743                let target_display_point = range.end.to_display_point(editor_snapshot);
 8744
 8745                self.render_edit_prediction_end_of_line_popover(
 8746                    "Accept",
 8747                    editor_snapshot,
 8748                    visible_row_range,
 8749                    target_display_point,
 8750                    line_height,
 8751                    scroll_pixel_position,
 8752                    content_origin,
 8753                    editor_width,
 8754                    window,
 8755                    cx,
 8756                )
 8757            }
 8758            EditPrediction::Edit {
 8759                edits,
 8760                edit_preview,
 8761                display_mode: EditDisplayMode::DiffPopover,
 8762                snapshot,
 8763            } => self.render_edit_prediction_diff_popover(
 8764                text_bounds,
 8765                content_origin,
 8766                right_margin,
 8767                editor_snapshot,
 8768                visible_row_range,
 8769                line_layouts,
 8770                line_height,
 8771                scroll_position,
 8772                scroll_pixel_position,
 8773                newest_selection_head,
 8774                editor_width,
 8775                style,
 8776                edits,
 8777                edit_preview,
 8778                snapshot,
 8779                window,
 8780                cx,
 8781            ),
 8782            EditPrediction::MoveOutside { snapshot, .. } => {
 8783                let file_name = snapshot
 8784                    .file()
 8785                    .map(|file| file.file_name(cx))
 8786                    .unwrap_or("untitled");
 8787                let mut element = self
 8788                    .render_edit_prediction_line_popover(
 8789                        format!("Jump to {file_name}"),
 8790                        Some(IconName::ZedPredict),
 8791                        window,
 8792                        cx,
 8793                    )
 8794                    .into_any();
 8795
 8796                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8797                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8798                let origin_y = text_bounds.size.height - size.height - px(30.);
 8799                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8800                element.prepaint_at(origin, window, cx);
 8801
 8802                Some((element, origin))
 8803            }
 8804        }
 8805    }
 8806
 8807    fn render_edit_prediction_modifier_jump_popover(
 8808        &mut self,
 8809        text_bounds: &Bounds<Pixels>,
 8810        content_origin: gpui::Point<Pixels>,
 8811        visible_row_range: Range<DisplayRow>,
 8812        line_layouts: &[LineWithInvisibles],
 8813        line_height: Pixels,
 8814        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8815        newest_selection_head: Option<DisplayPoint>,
 8816        target_display_point: DisplayPoint,
 8817        window: &mut Window,
 8818        cx: &mut App,
 8819    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8820        let scrolled_content_origin =
 8821            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8822
 8823        const SCROLL_PADDING_Y: Pixels = px(12.);
 8824
 8825        if target_display_point.row() < visible_row_range.start {
 8826            return self.render_edit_prediction_scroll_popover(
 8827                |_| SCROLL_PADDING_Y,
 8828                IconName::ArrowUp,
 8829                visible_row_range,
 8830                line_layouts,
 8831                newest_selection_head,
 8832                scrolled_content_origin,
 8833                window,
 8834                cx,
 8835            );
 8836        } else if target_display_point.row() >= visible_row_range.end {
 8837            return self.render_edit_prediction_scroll_popover(
 8838                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8839                IconName::ArrowDown,
 8840                visible_row_range,
 8841                line_layouts,
 8842                newest_selection_head,
 8843                scrolled_content_origin,
 8844                window,
 8845                cx,
 8846            );
 8847        }
 8848
 8849        const POLE_WIDTH: Pixels = px(2.);
 8850
 8851        let line_layout =
 8852            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8853        let target_column = target_display_point.column() as usize;
 8854
 8855        let target_x = line_layout.x_for_index(target_column);
 8856        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8857            - scroll_pixel_position.y;
 8858
 8859        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8860
 8861        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8862        border_color.l += 0.001;
 8863
 8864        let mut element = v_flex()
 8865            .items_end()
 8866            .when(flag_on_right, |el| el.items_start())
 8867            .child(if flag_on_right {
 8868                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8869                    .rounded_bl(px(0.))
 8870                    .rounded_tl(px(0.))
 8871                    .border_l_2()
 8872                    .border_color(border_color)
 8873            } else {
 8874                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8875                    .rounded_br(px(0.))
 8876                    .rounded_tr(px(0.))
 8877                    .border_r_2()
 8878                    .border_color(border_color)
 8879            })
 8880            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8881            .into_any();
 8882
 8883        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8884
 8885        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8886            - point(
 8887                if flag_on_right {
 8888                    POLE_WIDTH
 8889                } else {
 8890                    size.width - POLE_WIDTH
 8891                },
 8892                size.height - line_height,
 8893            );
 8894
 8895        origin.x = origin.x.max(content_origin.x);
 8896
 8897        element.prepaint_at(origin, window, cx);
 8898
 8899        Some((element, origin))
 8900    }
 8901
 8902    fn render_edit_prediction_scroll_popover(
 8903        &mut self,
 8904        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8905        scroll_icon: IconName,
 8906        visible_row_range: Range<DisplayRow>,
 8907        line_layouts: &[LineWithInvisibles],
 8908        newest_selection_head: Option<DisplayPoint>,
 8909        scrolled_content_origin: gpui::Point<Pixels>,
 8910        window: &mut Window,
 8911        cx: &mut App,
 8912    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8913        let mut element = self
 8914            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8915            .into_any();
 8916
 8917        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8918
 8919        let cursor = newest_selection_head?;
 8920        let cursor_row_layout =
 8921            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8922        let cursor_column = cursor.column() as usize;
 8923
 8924        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8925
 8926        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8927
 8928        element.prepaint_at(origin, window, cx);
 8929        Some((element, origin))
 8930    }
 8931
 8932    fn render_edit_prediction_eager_jump_popover(
 8933        &mut self,
 8934        text_bounds: &Bounds<Pixels>,
 8935        content_origin: gpui::Point<Pixels>,
 8936        editor_snapshot: &EditorSnapshot,
 8937        visible_row_range: Range<DisplayRow>,
 8938        scroll_top: ScrollOffset,
 8939        scroll_bottom: ScrollOffset,
 8940        line_height: Pixels,
 8941        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8942        target_display_point: DisplayPoint,
 8943        editor_width: Pixels,
 8944        window: &mut Window,
 8945        cx: &mut App,
 8946    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8947        if target_display_point.row().as_f64() < scroll_top {
 8948            let mut element = self
 8949                .render_edit_prediction_line_popover(
 8950                    "Jump to Edit",
 8951                    Some(IconName::ArrowUp),
 8952                    window,
 8953                    cx,
 8954                )
 8955                .into_any();
 8956
 8957            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8958            let offset = point(
 8959                (text_bounds.size.width - size.width) / 2.,
 8960                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8961            );
 8962
 8963            let origin = text_bounds.origin + offset;
 8964            element.prepaint_at(origin, window, cx);
 8965            Some((element, origin))
 8966        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8967            let mut element = self
 8968                .render_edit_prediction_line_popover(
 8969                    "Jump to Edit",
 8970                    Some(IconName::ArrowDown),
 8971                    window,
 8972                    cx,
 8973                )
 8974                .into_any();
 8975
 8976            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8977            let offset = point(
 8978                (text_bounds.size.width - size.width) / 2.,
 8979                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8980            );
 8981
 8982            let origin = text_bounds.origin + offset;
 8983            element.prepaint_at(origin, window, cx);
 8984            Some((element, origin))
 8985        } else {
 8986            self.render_edit_prediction_end_of_line_popover(
 8987                "Jump to Edit",
 8988                editor_snapshot,
 8989                visible_row_range,
 8990                target_display_point,
 8991                line_height,
 8992                scroll_pixel_position,
 8993                content_origin,
 8994                editor_width,
 8995                window,
 8996                cx,
 8997            )
 8998        }
 8999    }
 9000
 9001    fn render_edit_prediction_end_of_line_popover(
 9002        self: &mut Editor,
 9003        label: &'static str,
 9004        editor_snapshot: &EditorSnapshot,
 9005        visible_row_range: Range<DisplayRow>,
 9006        target_display_point: DisplayPoint,
 9007        line_height: Pixels,
 9008        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9009        content_origin: gpui::Point<Pixels>,
 9010        editor_width: Pixels,
 9011        window: &mut Window,
 9012        cx: &mut App,
 9013    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9014        let target_line_end = DisplayPoint::new(
 9015            target_display_point.row(),
 9016            editor_snapshot.line_len(target_display_point.row()),
 9017        );
 9018
 9019        let mut element = self
 9020            .render_edit_prediction_line_popover(label, None, window, cx)
 9021            .into_any();
 9022
 9023        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9024
 9025        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9026
 9027        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9028        let mut origin = start_point
 9029            + line_origin
 9030            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9031        origin.x = origin.x.max(content_origin.x);
 9032
 9033        let max_x = content_origin.x + editor_width - size.width;
 9034
 9035        if origin.x > max_x {
 9036            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9037
 9038            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9039                origin.y += offset;
 9040                IconName::ArrowUp
 9041            } else {
 9042                origin.y -= offset;
 9043                IconName::ArrowDown
 9044            };
 9045
 9046            element = self
 9047                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9048                .into_any();
 9049
 9050            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9051
 9052            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9053        }
 9054
 9055        element.prepaint_at(origin, window, cx);
 9056        Some((element, origin))
 9057    }
 9058
 9059    fn render_edit_prediction_diff_popover(
 9060        self: &Editor,
 9061        text_bounds: &Bounds<Pixels>,
 9062        content_origin: gpui::Point<Pixels>,
 9063        right_margin: Pixels,
 9064        editor_snapshot: &EditorSnapshot,
 9065        visible_row_range: Range<DisplayRow>,
 9066        line_layouts: &[LineWithInvisibles],
 9067        line_height: Pixels,
 9068        scroll_position: gpui::Point<ScrollOffset>,
 9069        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9070        newest_selection_head: Option<DisplayPoint>,
 9071        editor_width: Pixels,
 9072        style: &EditorStyle,
 9073        edits: &Vec<(Range<Anchor>, String)>,
 9074        edit_preview: &Option<language::EditPreview>,
 9075        snapshot: &language::BufferSnapshot,
 9076        window: &mut Window,
 9077        cx: &mut App,
 9078    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9079        let edit_start = edits
 9080            .first()
 9081            .unwrap()
 9082            .0
 9083            .start
 9084            .to_display_point(editor_snapshot);
 9085        let edit_end = edits
 9086            .last()
 9087            .unwrap()
 9088            .0
 9089            .end
 9090            .to_display_point(editor_snapshot);
 9091
 9092        let is_visible = visible_row_range.contains(&edit_start.row())
 9093            || visible_row_range.contains(&edit_end.row());
 9094        if !is_visible {
 9095            return None;
 9096        }
 9097
 9098        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9099            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9100        } else {
 9101            // Fallback for providers without edit_preview
 9102            crate::edit_prediction_fallback_text(edits, cx)
 9103        };
 9104
 9105        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9106        let line_count = highlighted_edits.text.lines().count();
 9107
 9108        const BORDER_WIDTH: Pixels = px(1.);
 9109
 9110        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9111        let has_keybind = keybind.is_some();
 9112
 9113        let mut element = h_flex()
 9114            .items_start()
 9115            .child(
 9116                h_flex()
 9117                    .bg(cx.theme().colors().editor_background)
 9118                    .border(BORDER_WIDTH)
 9119                    .shadow_xs()
 9120                    .border_color(cx.theme().colors().border)
 9121                    .rounded_l_lg()
 9122                    .when(line_count > 1, |el| el.rounded_br_lg())
 9123                    .pr_1()
 9124                    .child(styled_text),
 9125            )
 9126            .child(
 9127                h_flex()
 9128                    .h(line_height + BORDER_WIDTH * 2.)
 9129                    .px_1p5()
 9130                    .gap_1()
 9131                    // Workaround: For some reason, there's a gap if we don't do this
 9132                    .ml(-BORDER_WIDTH)
 9133                    .shadow(vec![gpui::BoxShadow {
 9134                        color: gpui::black().opacity(0.05),
 9135                        offset: point(px(1.), px(1.)),
 9136                        blur_radius: px(2.),
 9137                        spread_radius: px(0.),
 9138                    }])
 9139                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9140                    .border(BORDER_WIDTH)
 9141                    .border_color(cx.theme().colors().border)
 9142                    .rounded_r_lg()
 9143                    .id("edit_prediction_diff_popover_keybind")
 9144                    .when(!has_keybind, |el| {
 9145                        let status_colors = cx.theme().status();
 9146
 9147                        el.bg(status_colors.error_background)
 9148                            .border_color(status_colors.error.opacity(0.6))
 9149                            .child(Icon::new(IconName::Info).color(Color::Error))
 9150                            .cursor_default()
 9151                            .hoverable_tooltip(move |_window, cx| {
 9152                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9153                            })
 9154                    })
 9155                    .children(keybind),
 9156            )
 9157            .into_any();
 9158
 9159        let longest_row =
 9160            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9161        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9162            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9163        } else {
 9164            layout_line(
 9165                longest_row,
 9166                editor_snapshot,
 9167                style,
 9168                editor_width,
 9169                |_| false,
 9170                window,
 9171                cx,
 9172            )
 9173            .width
 9174        };
 9175
 9176        let viewport_bounds =
 9177            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9178                right: -right_margin,
 9179                ..Default::default()
 9180            });
 9181
 9182        let x_after_longest = Pixels::from(
 9183            ScrollPixelOffset::from(
 9184                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9185            ) - scroll_pixel_position.x,
 9186        );
 9187
 9188        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9189
 9190        // Fully visible if it can be displayed within the window (allow overlapping other
 9191        // panes). However, this is only allowed if the popover starts within text_bounds.
 9192        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9193            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9194
 9195        let mut origin = if can_position_to_the_right {
 9196            point(
 9197                x_after_longest,
 9198                text_bounds.origin.y
 9199                    + Pixels::from(
 9200                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9201                            - scroll_pixel_position.y,
 9202                    ),
 9203            )
 9204        } else {
 9205            let cursor_row = newest_selection_head.map(|head| head.row());
 9206            let above_edit = edit_start
 9207                .row()
 9208                .0
 9209                .checked_sub(line_count as u32)
 9210                .map(DisplayRow);
 9211            let below_edit = Some(edit_end.row() + 1);
 9212            let above_cursor =
 9213                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9214            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9215
 9216            // Place the edit popover adjacent to the edit if there is a location
 9217            // available that is onscreen and does not obscure the cursor. Otherwise,
 9218            // place it adjacent to the cursor.
 9219            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9220                .into_iter()
 9221                .flatten()
 9222                .find(|&start_row| {
 9223                    let end_row = start_row + line_count as u32;
 9224                    visible_row_range.contains(&start_row)
 9225                        && visible_row_range.contains(&end_row)
 9226                        && cursor_row
 9227                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9228                })?;
 9229
 9230            content_origin
 9231                + point(
 9232                    Pixels::from(-scroll_pixel_position.x),
 9233                    Pixels::from(
 9234                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9235                    ),
 9236                )
 9237        };
 9238
 9239        origin.x -= BORDER_WIDTH;
 9240
 9241        window.defer_draw(element, origin, 1);
 9242
 9243        // Do not return an element, since it will already be drawn due to defer_draw.
 9244        None
 9245    }
 9246
 9247    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9248        px(30.)
 9249    }
 9250
 9251    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9252        if self.read_only(cx) {
 9253            cx.theme().players().read_only()
 9254        } else {
 9255            self.style.as_ref().unwrap().local_player
 9256        }
 9257    }
 9258
 9259    fn render_edit_prediction_accept_keybind(
 9260        &self,
 9261        window: &mut Window,
 9262        cx: &App,
 9263    ) -> Option<AnyElement> {
 9264        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9265        let accept_keystroke = accept_binding.keystroke()?;
 9266
 9267        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9268
 9269        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9270            Color::Accent
 9271        } else {
 9272            Color::Muted
 9273        };
 9274
 9275        h_flex()
 9276            .px_0p5()
 9277            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9278            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9279            .text_size(TextSize::XSmall.rems(cx))
 9280            .child(h_flex().children(ui::render_modifiers(
 9281                accept_keystroke.modifiers(),
 9282                PlatformStyle::platform(),
 9283                Some(modifiers_color),
 9284                Some(IconSize::XSmall.rems().into()),
 9285                true,
 9286            )))
 9287            .when(is_platform_style_mac, |parent| {
 9288                parent.child(accept_keystroke.key().to_string())
 9289            })
 9290            .when(!is_platform_style_mac, |parent| {
 9291                parent.child(
 9292                    Key::new(
 9293                        util::capitalize(accept_keystroke.key()),
 9294                        Some(Color::Default),
 9295                    )
 9296                    .size(Some(IconSize::XSmall.rems().into())),
 9297                )
 9298            })
 9299            .into_any()
 9300            .into()
 9301    }
 9302
 9303    fn render_edit_prediction_line_popover(
 9304        &self,
 9305        label: impl Into<SharedString>,
 9306        icon: Option<IconName>,
 9307        window: &mut Window,
 9308        cx: &App,
 9309    ) -> Stateful<Div> {
 9310        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9311
 9312        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9313        let has_keybind = keybind.is_some();
 9314
 9315        h_flex()
 9316            .id("ep-line-popover")
 9317            .py_0p5()
 9318            .pl_1()
 9319            .pr(padding_right)
 9320            .gap_1()
 9321            .rounded_md()
 9322            .border_1()
 9323            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9324            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9325            .shadow_xs()
 9326            .when(!has_keybind, |el| {
 9327                let status_colors = cx.theme().status();
 9328
 9329                el.bg(status_colors.error_background)
 9330                    .border_color(status_colors.error.opacity(0.6))
 9331                    .pl_2()
 9332                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9333                    .cursor_default()
 9334                    .hoverable_tooltip(move |_window, cx| {
 9335                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9336                    })
 9337            })
 9338            .children(keybind)
 9339            .child(
 9340                Label::new(label)
 9341                    .size(LabelSize::Small)
 9342                    .when(!has_keybind, |el| {
 9343                        el.color(cx.theme().status().error.into()).strikethrough()
 9344                    }),
 9345            )
 9346            .when(!has_keybind, |el| {
 9347                el.child(
 9348                    h_flex().ml_1().child(
 9349                        Icon::new(IconName::Info)
 9350                            .size(IconSize::Small)
 9351                            .color(cx.theme().status().error.into()),
 9352                    ),
 9353                )
 9354            })
 9355            .when_some(icon, |element, icon| {
 9356                element.child(
 9357                    div()
 9358                        .mt(px(1.5))
 9359                        .child(Icon::new(icon).size(IconSize::Small)),
 9360                )
 9361            })
 9362    }
 9363
 9364    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9365        let accent_color = cx.theme().colors().text_accent;
 9366        let editor_bg_color = cx.theme().colors().editor_background;
 9367        editor_bg_color.blend(accent_color.opacity(0.1))
 9368    }
 9369
 9370    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9371        let accent_color = cx.theme().colors().text_accent;
 9372        let editor_bg_color = cx.theme().colors().editor_background;
 9373        editor_bg_color.blend(accent_color.opacity(0.6))
 9374    }
 9375    fn get_prediction_provider_icon_name(
 9376        provider: &Option<RegisteredEditPredictionProvider>,
 9377    ) -> IconName {
 9378        match provider {
 9379            Some(provider) => match provider.provider.name() {
 9380                "copilot" => IconName::Copilot,
 9381                "supermaven" => IconName::Supermaven,
 9382                _ => IconName::ZedPredict,
 9383            },
 9384            None => IconName::ZedPredict,
 9385        }
 9386    }
 9387
 9388    fn render_edit_prediction_cursor_popover(
 9389        &self,
 9390        min_width: Pixels,
 9391        max_width: Pixels,
 9392        cursor_point: Point,
 9393        style: &EditorStyle,
 9394        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9395        _window: &Window,
 9396        cx: &mut Context<Editor>,
 9397    ) -> Option<AnyElement> {
 9398        let provider = self.edit_prediction_provider.as_ref()?;
 9399        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9400
 9401        let is_refreshing = provider.provider.is_refreshing(cx);
 9402
 9403        fn pending_completion_container(icon: IconName) -> Div {
 9404            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9405        }
 9406
 9407        let completion = match &self.active_edit_prediction {
 9408            Some(prediction) => {
 9409                if !self.has_visible_completions_menu() {
 9410                    const RADIUS: Pixels = px(6.);
 9411                    const BORDER_WIDTH: Pixels = px(1.);
 9412
 9413                    return Some(
 9414                        h_flex()
 9415                            .elevation_2(cx)
 9416                            .border(BORDER_WIDTH)
 9417                            .border_color(cx.theme().colors().border)
 9418                            .when(accept_keystroke.is_none(), |el| {
 9419                                el.border_color(cx.theme().status().error)
 9420                            })
 9421                            .rounded(RADIUS)
 9422                            .rounded_tl(px(0.))
 9423                            .overflow_hidden()
 9424                            .child(div().px_1p5().child(match &prediction.completion {
 9425                                EditPrediction::MoveWithin { target, snapshot } => {
 9426                                    use text::ToPoint as _;
 9427                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9428                                    {
 9429                                        Icon::new(IconName::ZedPredictDown)
 9430                                    } else {
 9431                                        Icon::new(IconName::ZedPredictUp)
 9432                                    }
 9433                                }
 9434                                EditPrediction::MoveOutside { .. } => {
 9435                                    // TODO [zeta2] custom icon for external jump?
 9436                                    Icon::new(provider_icon)
 9437                                }
 9438                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9439                            }))
 9440                            .child(
 9441                                h_flex()
 9442                                    .gap_1()
 9443                                    .py_1()
 9444                                    .px_2()
 9445                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9446                                    .border_l_1()
 9447                                    .border_color(cx.theme().colors().border)
 9448                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9449                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9450                                        el.child(
 9451                                            Label::new("Hold")
 9452                                                .size(LabelSize::Small)
 9453                                                .when(accept_keystroke.is_none(), |el| {
 9454                                                    el.strikethrough()
 9455                                                })
 9456                                                .line_height_style(LineHeightStyle::UiLabel),
 9457                                        )
 9458                                    })
 9459                                    .id("edit_prediction_cursor_popover_keybind")
 9460                                    .when(accept_keystroke.is_none(), |el| {
 9461                                        let status_colors = cx.theme().status();
 9462
 9463                                        el.bg(status_colors.error_background)
 9464                                            .border_color(status_colors.error.opacity(0.6))
 9465                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9466                                            .cursor_default()
 9467                                            .hoverable_tooltip(move |_window, cx| {
 9468                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9469                                                    .into()
 9470                                            })
 9471                                    })
 9472                                    .when_some(
 9473                                        accept_keystroke.as_ref(),
 9474                                        |el, accept_keystroke| {
 9475                                            el.child(h_flex().children(ui::render_modifiers(
 9476                                                accept_keystroke.modifiers(),
 9477                                                PlatformStyle::platform(),
 9478                                                Some(Color::Default),
 9479                                                Some(IconSize::XSmall.rems().into()),
 9480                                                false,
 9481                                            )))
 9482                                        },
 9483                                    ),
 9484                            )
 9485                            .into_any(),
 9486                    );
 9487                }
 9488
 9489                self.render_edit_prediction_cursor_popover_preview(
 9490                    prediction,
 9491                    cursor_point,
 9492                    style,
 9493                    cx,
 9494                )?
 9495            }
 9496
 9497            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9498                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9499                    stale_completion,
 9500                    cursor_point,
 9501                    style,
 9502                    cx,
 9503                )?,
 9504
 9505                None => pending_completion_container(provider_icon)
 9506                    .child(Label::new("...").size(LabelSize::Small)),
 9507            },
 9508
 9509            None => pending_completion_container(provider_icon)
 9510                .child(Label::new("...").size(LabelSize::Small)),
 9511        };
 9512
 9513        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9514            completion
 9515                .with_animation(
 9516                    "loading-completion",
 9517                    Animation::new(Duration::from_secs(2))
 9518                        .repeat()
 9519                        .with_easing(pulsating_between(0.4, 0.8)),
 9520                    |label, delta| label.opacity(delta),
 9521                )
 9522                .into_any_element()
 9523        } else {
 9524            completion.into_any_element()
 9525        };
 9526
 9527        let has_completion = self.active_edit_prediction.is_some();
 9528
 9529        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9530        Some(
 9531            h_flex()
 9532                .min_w(min_width)
 9533                .max_w(max_width)
 9534                .flex_1()
 9535                .elevation_2(cx)
 9536                .border_color(cx.theme().colors().border)
 9537                .child(
 9538                    div()
 9539                        .flex_1()
 9540                        .py_1()
 9541                        .px_2()
 9542                        .overflow_hidden()
 9543                        .child(completion),
 9544                )
 9545                .when_some(accept_keystroke, |el, accept_keystroke| {
 9546                    if !accept_keystroke.modifiers().modified() {
 9547                        return el;
 9548                    }
 9549
 9550                    el.child(
 9551                        h_flex()
 9552                            .h_full()
 9553                            .border_l_1()
 9554                            .rounded_r_lg()
 9555                            .border_color(cx.theme().colors().border)
 9556                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9557                            .gap_1()
 9558                            .py_1()
 9559                            .px_2()
 9560                            .child(
 9561                                h_flex()
 9562                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9563                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9564                                    .child(h_flex().children(ui::render_modifiers(
 9565                                        accept_keystroke.modifiers(),
 9566                                        PlatformStyle::platform(),
 9567                                        Some(if !has_completion {
 9568                                            Color::Muted
 9569                                        } else {
 9570                                            Color::Default
 9571                                        }),
 9572                                        None,
 9573                                        false,
 9574                                    ))),
 9575                            )
 9576                            .child(Label::new("Preview").into_any_element())
 9577                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9578                    )
 9579                })
 9580                .into_any(),
 9581        )
 9582    }
 9583
 9584    fn render_edit_prediction_cursor_popover_preview(
 9585        &self,
 9586        completion: &EditPredictionState,
 9587        cursor_point: Point,
 9588        style: &EditorStyle,
 9589        cx: &mut Context<Editor>,
 9590    ) -> Option<Div> {
 9591        use text::ToPoint as _;
 9592
 9593        fn render_relative_row_jump(
 9594            prefix: impl Into<String>,
 9595            current_row: u32,
 9596            target_row: u32,
 9597        ) -> Div {
 9598            let (row_diff, arrow) = if target_row < current_row {
 9599                (current_row - target_row, IconName::ArrowUp)
 9600            } else {
 9601                (target_row - current_row, IconName::ArrowDown)
 9602            };
 9603
 9604            h_flex()
 9605                .child(
 9606                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9607                        .color(Color::Muted)
 9608                        .size(LabelSize::Small),
 9609                )
 9610                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9611        }
 9612
 9613        let supports_jump = self
 9614            .edit_prediction_provider
 9615            .as_ref()
 9616            .map(|provider| provider.provider.supports_jump_to_edit())
 9617            .unwrap_or(true);
 9618
 9619        match &completion.completion {
 9620            EditPrediction::MoveWithin {
 9621                target, snapshot, ..
 9622            } => {
 9623                if !supports_jump {
 9624                    return None;
 9625                }
 9626
 9627                Some(
 9628                    h_flex()
 9629                        .px_2()
 9630                        .gap_2()
 9631                        .flex_1()
 9632                        .child(
 9633                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9634                                Icon::new(IconName::ZedPredictDown)
 9635                            } else {
 9636                                Icon::new(IconName::ZedPredictUp)
 9637                            },
 9638                        )
 9639                        .child(Label::new("Jump to Edit")),
 9640                )
 9641            }
 9642            EditPrediction::MoveOutside { snapshot, .. } => {
 9643                let file_name = snapshot
 9644                    .file()
 9645                    .map(|file| file.file_name(cx))
 9646                    .unwrap_or("untitled");
 9647                Some(
 9648                    h_flex()
 9649                        .px_2()
 9650                        .gap_2()
 9651                        .flex_1()
 9652                        .child(Icon::new(IconName::ZedPredict))
 9653                        .child(Label::new(format!("Jump to {file_name}"))),
 9654                )
 9655            }
 9656            EditPrediction::Edit {
 9657                edits,
 9658                edit_preview,
 9659                snapshot,
 9660                display_mode: _,
 9661            } => {
 9662                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9663
 9664                let (highlighted_edits, has_more_lines) =
 9665                    if let Some(edit_preview) = edit_preview.as_ref() {
 9666                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9667                            .first_line_preview()
 9668                    } else {
 9669                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9670                    };
 9671
 9672                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9673                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9674
 9675                let preview = h_flex()
 9676                    .gap_1()
 9677                    .min_w_16()
 9678                    .child(styled_text)
 9679                    .when(has_more_lines, |parent| parent.child(""));
 9680
 9681                let left = if supports_jump && first_edit_row != cursor_point.row {
 9682                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9683                        .into_any_element()
 9684                } else {
 9685                    let icon_name =
 9686                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9687                    Icon::new(icon_name).into_any_element()
 9688                };
 9689
 9690                Some(
 9691                    h_flex()
 9692                        .h_full()
 9693                        .flex_1()
 9694                        .gap_2()
 9695                        .pr_1()
 9696                        .overflow_x_hidden()
 9697                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9698                        .child(left)
 9699                        .child(preview),
 9700                )
 9701            }
 9702        }
 9703    }
 9704
 9705    pub fn render_context_menu(
 9706        &self,
 9707        style: &EditorStyle,
 9708        max_height_in_lines: u32,
 9709        window: &mut Window,
 9710        cx: &mut Context<Editor>,
 9711    ) -> Option<AnyElement> {
 9712        let menu = self.context_menu.borrow();
 9713        let menu = menu.as_ref()?;
 9714        if !menu.visible() {
 9715            return None;
 9716        };
 9717        Some(menu.render(style, max_height_in_lines, window, cx))
 9718    }
 9719
 9720    fn render_context_menu_aside(
 9721        &mut self,
 9722        max_size: Size<Pixels>,
 9723        window: &mut Window,
 9724        cx: &mut Context<Editor>,
 9725    ) -> Option<AnyElement> {
 9726        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9727            if menu.visible() {
 9728                menu.render_aside(max_size, window, cx)
 9729            } else {
 9730                None
 9731            }
 9732        })
 9733    }
 9734
 9735    fn hide_context_menu(
 9736        &mut self,
 9737        window: &mut Window,
 9738        cx: &mut Context<Self>,
 9739    ) -> Option<CodeContextMenu> {
 9740        cx.notify();
 9741        self.completion_tasks.clear();
 9742        let context_menu = self.context_menu.borrow_mut().take();
 9743        self.stale_edit_prediction_in_menu.take();
 9744        self.update_visible_edit_prediction(window, cx);
 9745        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9746            && let Some(completion_provider) = &self.completion_provider
 9747        {
 9748            completion_provider.selection_changed(None, window, cx);
 9749        }
 9750        context_menu
 9751    }
 9752
 9753    fn show_snippet_choices(
 9754        &mut self,
 9755        choices: &Vec<String>,
 9756        selection: Range<Anchor>,
 9757        cx: &mut Context<Self>,
 9758    ) {
 9759        let Some((_, buffer, _)) = self
 9760            .buffer()
 9761            .read(cx)
 9762            .excerpt_containing(selection.start, cx)
 9763        else {
 9764            return;
 9765        };
 9766        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9767        else {
 9768            return;
 9769        };
 9770        if buffer != end_buffer {
 9771            log::error!("expected anchor range to have matching buffer IDs");
 9772            return;
 9773        }
 9774
 9775        let id = post_inc(&mut self.next_completion_id);
 9776        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9777        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9778            CompletionsMenu::new_snippet_choices(
 9779                id,
 9780                true,
 9781                choices,
 9782                selection,
 9783                buffer,
 9784                snippet_sort_order,
 9785            ),
 9786        ));
 9787    }
 9788
 9789    pub fn insert_snippet(
 9790        &mut self,
 9791        insertion_ranges: &[Range<usize>],
 9792        snippet: Snippet,
 9793        window: &mut Window,
 9794        cx: &mut Context<Self>,
 9795    ) -> Result<()> {
 9796        struct Tabstop<T> {
 9797            is_end_tabstop: bool,
 9798            ranges: Vec<Range<T>>,
 9799            choices: Option<Vec<String>>,
 9800        }
 9801
 9802        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9803            let snippet_text: Arc<str> = snippet.text.clone().into();
 9804            let edits = insertion_ranges
 9805                .iter()
 9806                .cloned()
 9807                .map(|range| (range, snippet_text.clone()));
 9808            let autoindent_mode = AutoindentMode::Block {
 9809                original_indent_columns: Vec::new(),
 9810            };
 9811            buffer.edit(edits, Some(autoindent_mode), cx);
 9812
 9813            let snapshot = &*buffer.read(cx);
 9814            let snippet = &snippet;
 9815            snippet
 9816                .tabstops
 9817                .iter()
 9818                .map(|tabstop| {
 9819                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9820                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9821                    });
 9822                    let mut tabstop_ranges = tabstop
 9823                        .ranges
 9824                        .iter()
 9825                        .flat_map(|tabstop_range| {
 9826                            let mut delta = 0_isize;
 9827                            insertion_ranges.iter().map(move |insertion_range| {
 9828                                let insertion_start = insertion_range.start as isize + delta;
 9829                                delta +=
 9830                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9831
 9832                                let start = ((insertion_start + tabstop_range.start) as usize)
 9833                                    .min(snapshot.len());
 9834                                let end = ((insertion_start + tabstop_range.end) as usize)
 9835                                    .min(snapshot.len());
 9836                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9837                            })
 9838                        })
 9839                        .collect::<Vec<_>>();
 9840                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9841
 9842                    Tabstop {
 9843                        is_end_tabstop,
 9844                        ranges: tabstop_ranges,
 9845                        choices: tabstop.choices.clone(),
 9846                    }
 9847                })
 9848                .collect::<Vec<_>>()
 9849        });
 9850        if let Some(tabstop) = tabstops.first() {
 9851            self.change_selections(Default::default(), window, cx, |s| {
 9852                // Reverse order so that the first range is the newest created selection.
 9853                // Completions will use it and autoscroll will prioritize it.
 9854                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9855            });
 9856
 9857            if let Some(choices) = &tabstop.choices
 9858                && let Some(selection) = tabstop.ranges.first()
 9859            {
 9860                self.show_snippet_choices(choices, selection.clone(), cx)
 9861            }
 9862
 9863            // If we're already at the last tabstop and it's at the end of the snippet,
 9864            // we're done, we don't need to keep the state around.
 9865            if !tabstop.is_end_tabstop {
 9866                let choices = tabstops
 9867                    .iter()
 9868                    .map(|tabstop| tabstop.choices.clone())
 9869                    .collect();
 9870
 9871                let ranges = tabstops
 9872                    .into_iter()
 9873                    .map(|tabstop| tabstop.ranges)
 9874                    .collect::<Vec<_>>();
 9875
 9876                self.snippet_stack.push(SnippetState {
 9877                    active_index: 0,
 9878                    ranges,
 9879                    choices,
 9880                });
 9881            }
 9882
 9883            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9884            if self.autoclose_regions.is_empty() {
 9885                let snapshot = self.buffer.read(cx).snapshot(cx);
 9886                let mut all_selections = self.selections.all::<Point>(cx);
 9887                for selection in &mut all_selections {
 9888                    let selection_head = selection.head();
 9889                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9890                        continue;
 9891                    };
 9892
 9893                    let mut bracket_pair = None;
 9894                    let max_lookup_length = scope
 9895                        .brackets()
 9896                        .map(|(pair, _)| {
 9897                            pair.start
 9898                                .as_str()
 9899                                .chars()
 9900                                .count()
 9901                                .max(pair.end.as_str().chars().count())
 9902                        })
 9903                        .max();
 9904                    if let Some(max_lookup_length) = max_lookup_length {
 9905                        let next_text = snapshot
 9906                            .chars_at(selection_head)
 9907                            .take(max_lookup_length)
 9908                            .collect::<String>();
 9909                        let prev_text = snapshot
 9910                            .reversed_chars_at(selection_head)
 9911                            .take(max_lookup_length)
 9912                            .collect::<String>();
 9913
 9914                        for (pair, enabled) in scope.brackets() {
 9915                            if enabled
 9916                                && pair.close
 9917                                && prev_text.starts_with(pair.start.as_str())
 9918                                && next_text.starts_with(pair.end.as_str())
 9919                            {
 9920                                bracket_pair = Some(pair.clone());
 9921                                break;
 9922                            }
 9923                        }
 9924                    }
 9925
 9926                    if let Some(pair) = bracket_pair {
 9927                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9928                        let autoclose_enabled =
 9929                            self.use_autoclose && snapshot_settings.use_autoclose;
 9930                        if autoclose_enabled {
 9931                            let start = snapshot.anchor_after(selection_head);
 9932                            let end = snapshot.anchor_after(selection_head);
 9933                            self.autoclose_regions.push(AutocloseRegion {
 9934                                selection_id: selection.id,
 9935                                range: start..end,
 9936                                pair,
 9937                            });
 9938                        }
 9939                    }
 9940                }
 9941            }
 9942        }
 9943        Ok(())
 9944    }
 9945
 9946    pub fn move_to_next_snippet_tabstop(
 9947        &mut self,
 9948        window: &mut Window,
 9949        cx: &mut Context<Self>,
 9950    ) -> bool {
 9951        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9952    }
 9953
 9954    pub fn move_to_prev_snippet_tabstop(
 9955        &mut self,
 9956        window: &mut Window,
 9957        cx: &mut Context<Self>,
 9958    ) -> bool {
 9959        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9960    }
 9961
 9962    pub fn move_to_snippet_tabstop(
 9963        &mut self,
 9964        bias: Bias,
 9965        window: &mut Window,
 9966        cx: &mut Context<Self>,
 9967    ) -> bool {
 9968        if let Some(mut snippet) = self.snippet_stack.pop() {
 9969            match bias {
 9970                Bias::Left => {
 9971                    if snippet.active_index > 0 {
 9972                        snippet.active_index -= 1;
 9973                    } else {
 9974                        self.snippet_stack.push(snippet);
 9975                        return false;
 9976                    }
 9977                }
 9978                Bias::Right => {
 9979                    if snippet.active_index + 1 < snippet.ranges.len() {
 9980                        snippet.active_index += 1;
 9981                    } else {
 9982                        self.snippet_stack.push(snippet);
 9983                        return false;
 9984                    }
 9985                }
 9986            }
 9987            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9988                self.change_selections(Default::default(), window, cx, |s| {
 9989                    // Reverse order so that the first range is the newest created selection.
 9990                    // Completions will use it and autoscroll will prioritize it.
 9991                    s.select_ranges(current_ranges.iter().rev().cloned())
 9992                });
 9993
 9994                if let Some(choices) = &snippet.choices[snippet.active_index]
 9995                    && let Some(selection) = current_ranges.first()
 9996                {
 9997                    self.show_snippet_choices(choices, selection.clone(), cx);
 9998                }
 9999
10000                // If snippet state is not at the last tabstop, push it back on the stack
10001                if snippet.active_index + 1 < snippet.ranges.len() {
10002                    self.snippet_stack.push(snippet);
10003                }
10004                return true;
10005            }
10006        }
10007
10008        false
10009    }
10010
10011    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10012        self.transact(window, cx, |this, window, cx| {
10013            this.select_all(&SelectAll, window, cx);
10014            this.insert("", window, cx);
10015        });
10016    }
10017
10018    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10019        if self.read_only(cx) {
10020            return;
10021        }
10022        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10023        self.transact(window, cx, |this, window, cx| {
10024            this.select_autoclose_pair(window, cx);
10025            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10026            if !this.linked_edit_ranges.is_empty() {
10027                let selections = this.selections.all::<MultiBufferPoint>(cx);
10028                let snapshot = this.buffer.read(cx).snapshot(cx);
10029
10030                for selection in selections.iter() {
10031                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10032                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10033                    if selection_start.buffer_id != selection_end.buffer_id {
10034                        continue;
10035                    }
10036                    if let Some(ranges) =
10037                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10038                    {
10039                        for (buffer, entries) in ranges {
10040                            linked_ranges.entry(buffer).or_default().extend(entries);
10041                        }
10042                    }
10043                }
10044            }
10045
10046            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
10047            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10048            for selection in &mut selections {
10049                if selection.is_empty() {
10050                    let old_head = selection.head();
10051                    let mut new_head =
10052                        movement::left(&display_map, old_head.to_display_point(&display_map))
10053                            .to_point(&display_map);
10054                    if let Some((buffer, line_buffer_range)) = display_map
10055                        .buffer_snapshot()
10056                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10057                    {
10058                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10059                        let indent_len = match indent_size.kind {
10060                            IndentKind::Space => {
10061                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10062                            }
10063                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10064                        };
10065                        if old_head.column <= indent_size.len && old_head.column > 0 {
10066                            let indent_len = indent_len.get();
10067                            new_head = cmp::min(
10068                                new_head,
10069                                MultiBufferPoint::new(
10070                                    old_head.row,
10071                                    ((old_head.column - 1) / indent_len) * indent_len,
10072                                ),
10073                            );
10074                        }
10075                    }
10076
10077                    selection.set_head(new_head, SelectionGoal::None);
10078                }
10079            }
10080
10081            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10082            this.insert("", window, cx);
10083            let empty_str: Arc<str> = Arc::from("");
10084            for (buffer, edits) in linked_ranges {
10085                let snapshot = buffer.read(cx).snapshot();
10086                use text::ToPoint as TP;
10087
10088                let edits = edits
10089                    .into_iter()
10090                    .map(|range| {
10091                        let end_point = TP::to_point(&range.end, &snapshot);
10092                        let mut start_point = TP::to_point(&range.start, &snapshot);
10093
10094                        if end_point == start_point {
10095                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10096                                .saturating_sub(1);
10097                            start_point =
10098                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10099                        };
10100
10101                        (start_point..end_point, empty_str.clone())
10102                    })
10103                    .sorted_by_key(|(range, _)| range.start)
10104                    .collect::<Vec<_>>();
10105                buffer.update(cx, |this, cx| {
10106                    this.edit(edits, None, cx);
10107                })
10108            }
10109            this.refresh_edit_prediction(true, false, window, cx);
10110            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
10111        });
10112    }
10113
10114    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10115        if self.read_only(cx) {
10116            return;
10117        }
10118        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10119        self.transact(window, cx, |this, window, cx| {
10120            this.change_selections(Default::default(), window, cx, |s| {
10121                s.move_with(|map, selection| {
10122                    if selection.is_empty() {
10123                        let cursor = movement::right(map, selection.head());
10124                        selection.end = cursor;
10125                        selection.reversed = true;
10126                        selection.goal = SelectionGoal::None;
10127                    }
10128                })
10129            });
10130            this.insert("", window, cx);
10131            this.refresh_edit_prediction(true, false, window, cx);
10132        });
10133    }
10134
10135    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10136        if self.mode.is_single_line() {
10137            cx.propagate();
10138            return;
10139        }
10140
10141        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10142        if self.move_to_prev_snippet_tabstop(window, cx) {
10143            return;
10144        }
10145        self.outdent(&Outdent, window, cx);
10146    }
10147
10148    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10149        if self.mode.is_single_line() {
10150            cx.propagate();
10151            return;
10152        }
10153
10154        if self.move_to_next_snippet_tabstop(window, cx) {
10155            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10156            return;
10157        }
10158        if self.read_only(cx) {
10159            return;
10160        }
10161        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10162        let mut selections = self.selections.all_adjusted(cx);
10163        let buffer = self.buffer.read(cx);
10164        let snapshot = buffer.snapshot(cx);
10165        let rows_iter = selections.iter().map(|s| s.head().row);
10166        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10167
10168        let has_some_cursor_in_whitespace = selections
10169            .iter()
10170            .filter(|selection| selection.is_empty())
10171            .any(|selection| {
10172                let cursor = selection.head();
10173                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10174                cursor.column < current_indent.len
10175            });
10176
10177        let mut edits = Vec::new();
10178        let mut prev_edited_row = 0;
10179        let mut row_delta = 0;
10180        for selection in &mut selections {
10181            if selection.start.row != prev_edited_row {
10182                row_delta = 0;
10183            }
10184            prev_edited_row = selection.end.row;
10185
10186            // If the selection is non-empty, then increase the indentation of the selected lines.
10187            if !selection.is_empty() {
10188                row_delta =
10189                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10190                continue;
10191            }
10192
10193            let cursor = selection.head();
10194            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10195            if let Some(suggested_indent) =
10196                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10197            {
10198                // Don't do anything if already at suggested indent
10199                // and there is any other cursor which is not
10200                if has_some_cursor_in_whitespace
10201                    && cursor.column == current_indent.len
10202                    && current_indent.len == suggested_indent.len
10203                {
10204                    continue;
10205                }
10206
10207                // Adjust line and move cursor to suggested indent
10208                // if cursor is not at suggested indent
10209                if cursor.column < suggested_indent.len
10210                    && cursor.column <= current_indent.len
10211                    && current_indent.len <= suggested_indent.len
10212                {
10213                    selection.start = Point::new(cursor.row, suggested_indent.len);
10214                    selection.end = selection.start;
10215                    if row_delta == 0 {
10216                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10217                            cursor.row,
10218                            current_indent,
10219                            suggested_indent,
10220                        ));
10221                        row_delta = suggested_indent.len - current_indent.len;
10222                    }
10223                    continue;
10224                }
10225
10226                // If current indent is more than suggested indent
10227                // only move cursor to current indent and skip indent
10228                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10229                    selection.start = Point::new(cursor.row, current_indent.len);
10230                    selection.end = selection.start;
10231                    continue;
10232                }
10233            }
10234
10235            // Otherwise, insert a hard or soft tab.
10236            let settings = buffer.language_settings_at(cursor, cx);
10237            let tab_size = if settings.hard_tabs {
10238                IndentSize::tab()
10239            } else {
10240                let tab_size = settings.tab_size.get();
10241                let indent_remainder = snapshot
10242                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10243                    .flat_map(str::chars)
10244                    .fold(row_delta % tab_size, |counter: u32, c| {
10245                        if c == '\t' {
10246                            0
10247                        } else {
10248                            (counter + 1) % tab_size
10249                        }
10250                    });
10251
10252                let chars_to_next_tab_stop = tab_size - indent_remainder;
10253                IndentSize::spaces(chars_to_next_tab_stop)
10254            };
10255            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10256            selection.end = selection.start;
10257            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10258            row_delta += tab_size.len;
10259        }
10260
10261        self.transact(window, cx, |this, window, cx| {
10262            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10263            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10264            this.refresh_edit_prediction(true, false, window, cx);
10265        });
10266    }
10267
10268    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10269        if self.read_only(cx) {
10270            return;
10271        }
10272        if self.mode.is_single_line() {
10273            cx.propagate();
10274            return;
10275        }
10276
10277        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10278        let mut selections = self.selections.all::<Point>(cx);
10279        let mut prev_edited_row = 0;
10280        let mut row_delta = 0;
10281        let mut edits = Vec::new();
10282        let buffer = self.buffer.read(cx);
10283        let snapshot = buffer.snapshot(cx);
10284        for selection in &mut selections {
10285            if selection.start.row != prev_edited_row {
10286                row_delta = 0;
10287            }
10288            prev_edited_row = selection.end.row;
10289
10290            row_delta =
10291                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10292        }
10293
10294        self.transact(window, cx, |this, window, cx| {
10295            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10296            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10297        });
10298    }
10299
10300    fn indent_selection(
10301        buffer: &MultiBuffer,
10302        snapshot: &MultiBufferSnapshot,
10303        selection: &mut Selection<Point>,
10304        edits: &mut Vec<(Range<Point>, String)>,
10305        delta_for_start_row: u32,
10306        cx: &App,
10307    ) -> u32 {
10308        let settings = buffer.language_settings_at(selection.start, cx);
10309        let tab_size = settings.tab_size.get();
10310        let indent_kind = if settings.hard_tabs {
10311            IndentKind::Tab
10312        } else {
10313            IndentKind::Space
10314        };
10315        let mut start_row = selection.start.row;
10316        let mut end_row = selection.end.row + 1;
10317
10318        // If a selection ends at the beginning of a line, don't indent
10319        // that last line.
10320        if selection.end.column == 0 && selection.end.row > selection.start.row {
10321            end_row -= 1;
10322        }
10323
10324        // Avoid re-indenting a row that has already been indented by a
10325        // previous selection, but still update this selection's column
10326        // to reflect that indentation.
10327        if delta_for_start_row > 0 {
10328            start_row += 1;
10329            selection.start.column += delta_for_start_row;
10330            if selection.end.row == selection.start.row {
10331                selection.end.column += delta_for_start_row;
10332            }
10333        }
10334
10335        let mut delta_for_end_row = 0;
10336        let has_multiple_rows = start_row + 1 != end_row;
10337        for row in start_row..end_row {
10338            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10339            let indent_delta = match (current_indent.kind, indent_kind) {
10340                (IndentKind::Space, IndentKind::Space) => {
10341                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10342                    IndentSize::spaces(columns_to_next_tab_stop)
10343                }
10344                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10345                (_, IndentKind::Tab) => IndentSize::tab(),
10346            };
10347
10348            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10349                0
10350            } else {
10351                selection.start.column
10352            };
10353            let row_start = Point::new(row, start);
10354            edits.push((
10355                row_start..row_start,
10356                indent_delta.chars().collect::<String>(),
10357            ));
10358
10359            // Update this selection's endpoints to reflect the indentation.
10360            if row == selection.start.row {
10361                selection.start.column += indent_delta.len;
10362            }
10363            if row == selection.end.row {
10364                selection.end.column += indent_delta.len;
10365                delta_for_end_row = indent_delta.len;
10366            }
10367        }
10368
10369        if selection.start.row == selection.end.row {
10370            delta_for_start_row + delta_for_end_row
10371        } else {
10372            delta_for_end_row
10373        }
10374    }
10375
10376    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10377        if self.read_only(cx) {
10378            return;
10379        }
10380        if self.mode.is_single_line() {
10381            cx.propagate();
10382            return;
10383        }
10384
10385        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10386        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10387        let selections = self.selections.all::<Point>(cx);
10388        let mut deletion_ranges = Vec::new();
10389        let mut last_outdent = None;
10390        {
10391            let buffer = self.buffer.read(cx);
10392            let snapshot = buffer.snapshot(cx);
10393            for selection in &selections {
10394                let settings = buffer.language_settings_at(selection.start, cx);
10395                let tab_size = settings.tab_size.get();
10396                let mut rows = selection.spanned_rows(false, &display_map);
10397
10398                // Avoid re-outdenting a row that has already been outdented by a
10399                // previous selection.
10400                if let Some(last_row) = last_outdent
10401                    && last_row == rows.start
10402                {
10403                    rows.start = rows.start.next_row();
10404                }
10405                let has_multiple_rows = rows.len() > 1;
10406                for row in rows.iter_rows() {
10407                    let indent_size = snapshot.indent_size_for_line(row);
10408                    if indent_size.len > 0 {
10409                        let deletion_len = match indent_size.kind {
10410                            IndentKind::Space => {
10411                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10412                                if columns_to_prev_tab_stop == 0 {
10413                                    tab_size
10414                                } else {
10415                                    columns_to_prev_tab_stop
10416                                }
10417                            }
10418                            IndentKind::Tab => 1,
10419                        };
10420                        let start = if has_multiple_rows
10421                            || deletion_len > selection.start.column
10422                            || indent_size.len < selection.start.column
10423                        {
10424                            0
10425                        } else {
10426                            selection.start.column - deletion_len
10427                        };
10428                        deletion_ranges.push(
10429                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10430                        );
10431                        last_outdent = Some(row);
10432                    }
10433                }
10434            }
10435        }
10436
10437        self.transact(window, cx, |this, window, cx| {
10438            this.buffer.update(cx, |buffer, cx| {
10439                let empty_str: Arc<str> = Arc::default();
10440                buffer.edit(
10441                    deletion_ranges
10442                        .into_iter()
10443                        .map(|range| (range, empty_str.clone())),
10444                    None,
10445                    cx,
10446                );
10447            });
10448            let selections = this.selections.all::<usize>(cx);
10449            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10450        });
10451    }
10452
10453    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10454        if self.read_only(cx) {
10455            return;
10456        }
10457        if self.mode.is_single_line() {
10458            cx.propagate();
10459            return;
10460        }
10461
10462        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10463        let selections = self
10464            .selections
10465            .all::<usize>(cx)
10466            .into_iter()
10467            .map(|s| s.range());
10468
10469        self.transact(window, cx, |this, window, cx| {
10470            this.buffer.update(cx, |buffer, cx| {
10471                buffer.autoindent_ranges(selections, cx);
10472            });
10473            let selections = this.selections.all::<usize>(cx);
10474            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10475        });
10476    }
10477
10478    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10479        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10480        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10481        let selections = self.selections.all::<Point>(cx);
10482
10483        let mut new_cursors = Vec::new();
10484        let mut edit_ranges = Vec::new();
10485        let mut selections = selections.iter().peekable();
10486        while let Some(selection) = selections.next() {
10487            let mut rows = selection.spanned_rows(false, &display_map);
10488
10489            // Accumulate contiguous regions of rows that we want to delete.
10490            while let Some(next_selection) = selections.peek() {
10491                let next_rows = next_selection.spanned_rows(false, &display_map);
10492                if next_rows.start <= rows.end {
10493                    rows.end = next_rows.end;
10494                    selections.next().unwrap();
10495                } else {
10496                    break;
10497                }
10498            }
10499
10500            let buffer = display_map.buffer_snapshot();
10501            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10502            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10503                // If there's a line after the range, delete the \n from the end of the row range
10504                (
10505                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10506                    rows.end,
10507                )
10508            } else {
10509                // If there isn't a line after the range, delete the \n from the line before the
10510                // start of the row range
10511                edit_start = edit_start.saturating_sub(1);
10512                (buffer.len(), rows.start.previous_row())
10513            };
10514
10515            let text_layout_details = self.text_layout_details(window);
10516            let x = display_map.x_for_display_point(
10517                selection.head().to_display_point(&display_map),
10518                &text_layout_details,
10519            );
10520            let row = Point::new(target_row.0, 0)
10521                .to_display_point(&display_map)
10522                .row();
10523            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10524
10525            new_cursors.push((
10526                selection.id,
10527                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10528                SelectionGoal::None,
10529            ));
10530            edit_ranges.push(edit_start..edit_end);
10531        }
10532
10533        self.transact(window, cx, |this, window, cx| {
10534            let buffer = this.buffer.update(cx, |buffer, cx| {
10535                let empty_str: Arc<str> = Arc::default();
10536                buffer.edit(
10537                    edit_ranges
10538                        .into_iter()
10539                        .map(|range| (range, empty_str.clone())),
10540                    None,
10541                    cx,
10542                );
10543                buffer.snapshot(cx)
10544            });
10545            let new_selections = new_cursors
10546                .into_iter()
10547                .map(|(id, cursor, goal)| {
10548                    let cursor = cursor.to_point(&buffer);
10549                    Selection {
10550                        id,
10551                        start: cursor,
10552                        end: cursor,
10553                        reversed: false,
10554                        goal,
10555                    }
10556                })
10557                .collect();
10558
10559            this.change_selections(Default::default(), window, cx, |s| {
10560                s.select(new_selections);
10561            });
10562        });
10563    }
10564
10565    pub fn join_lines_impl(
10566        &mut self,
10567        insert_whitespace: bool,
10568        window: &mut Window,
10569        cx: &mut Context<Self>,
10570    ) {
10571        if self.read_only(cx) {
10572            return;
10573        }
10574        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10575        for selection in self.selections.all::<Point>(cx) {
10576            let start = MultiBufferRow(selection.start.row);
10577            // Treat single line selections as if they include the next line. Otherwise this action
10578            // would do nothing for single line selections individual cursors.
10579            let end = if selection.start.row == selection.end.row {
10580                MultiBufferRow(selection.start.row + 1)
10581            } else {
10582                MultiBufferRow(selection.end.row)
10583            };
10584
10585            if let Some(last_row_range) = row_ranges.last_mut()
10586                && start <= last_row_range.end
10587            {
10588                last_row_range.end = end;
10589                continue;
10590            }
10591            row_ranges.push(start..end);
10592        }
10593
10594        let snapshot = self.buffer.read(cx).snapshot(cx);
10595        let mut cursor_positions = Vec::new();
10596        for row_range in &row_ranges {
10597            let anchor = snapshot.anchor_before(Point::new(
10598                row_range.end.previous_row().0,
10599                snapshot.line_len(row_range.end.previous_row()),
10600            ));
10601            cursor_positions.push(anchor..anchor);
10602        }
10603
10604        self.transact(window, cx, |this, window, cx| {
10605            for row_range in row_ranges.into_iter().rev() {
10606                for row in row_range.iter_rows().rev() {
10607                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10608                    let next_line_row = row.next_row();
10609                    let indent = snapshot.indent_size_for_line(next_line_row);
10610                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10611
10612                    let replace =
10613                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10614                            " "
10615                        } else {
10616                            ""
10617                        };
10618
10619                    this.buffer.update(cx, |buffer, cx| {
10620                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10621                    });
10622                }
10623            }
10624
10625            this.change_selections(Default::default(), window, cx, |s| {
10626                s.select_anchor_ranges(cursor_positions)
10627            });
10628        });
10629    }
10630
10631    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10632        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10633        self.join_lines_impl(true, window, cx);
10634    }
10635
10636    pub fn sort_lines_case_sensitive(
10637        &mut self,
10638        _: &SortLinesCaseSensitive,
10639        window: &mut Window,
10640        cx: &mut Context<Self>,
10641    ) {
10642        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10643    }
10644
10645    pub fn sort_lines_by_length(
10646        &mut self,
10647        _: &SortLinesByLength,
10648        window: &mut Window,
10649        cx: &mut Context<Self>,
10650    ) {
10651        self.manipulate_immutable_lines(window, cx, |lines| {
10652            lines.sort_by_key(|&line| line.chars().count())
10653        })
10654    }
10655
10656    pub fn sort_lines_case_insensitive(
10657        &mut self,
10658        _: &SortLinesCaseInsensitive,
10659        window: &mut Window,
10660        cx: &mut Context<Self>,
10661    ) {
10662        self.manipulate_immutable_lines(window, cx, |lines| {
10663            lines.sort_by_key(|line| line.to_lowercase())
10664        })
10665    }
10666
10667    pub fn unique_lines_case_insensitive(
10668        &mut self,
10669        _: &UniqueLinesCaseInsensitive,
10670        window: &mut Window,
10671        cx: &mut Context<Self>,
10672    ) {
10673        self.manipulate_immutable_lines(window, cx, |lines| {
10674            let mut seen = HashSet::default();
10675            lines.retain(|line| seen.insert(line.to_lowercase()));
10676        })
10677    }
10678
10679    pub fn unique_lines_case_sensitive(
10680        &mut self,
10681        _: &UniqueLinesCaseSensitive,
10682        window: &mut Window,
10683        cx: &mut Context<Self>,
10684    ) {
10685        self.manipulate_immutable_lines(window, cx, |lines| {
10686            let mut seen = HashSet::default();
10687            lines.retain(|line| seen.insert(*line));
10688        })
10689    }
10690
10691    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10692        let snapshot = self.buffer.read(cx).snapshot(cx);
10693        for selection in self.selections.disjoint_anchors_arc().iter() {
10694            if snapshot
10695                .language_at(selection.start)
10696                .and_then(|lang| lang.config().wrap_characters.as_ref())
10697                .is_some()
10698            {
10699                return true;
10700            }
10701        }
10702        false
10703    }
10704
10705    fn wrap_selections_in_tag(
10706        &mut self,
10707        _: &WrapSelectionsInTag,
10708        window: &mut Window,
10709        cx: &mut Context<Self>,
10710    ) {
10711        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10712
10713        let snapshot = self.buffer.read(cx).snapshot(cx);
10714
10715        let mut edits = Vec::new();
10716        let mut boundaries = Vec::new();
10717
10718        for selection in self.selections.all::<Point>(cx).iter() {
10719            let Some(wrap_config) = snapshot
10720                .language_at(selection.start)
10721                .and_then(|lang| lang.config().wrap_characters.clone())
10722            else {
10723                continue;
10724            };
10725
10726            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10727            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10728
10729            let start_before = snapshot.anchor_before(selection.start);
10730            let end_after = snapshot.anchor_after(selection.end);
10731
10732            edits.push((start_before..start_before, open_tag));
10733            edits.push((end_after..end_after, close_tag));
10734
10735            boundaries.push((
10736                start_before,
10737                end_after,
10738                wrap_config.start_prefix.len(),
10739                wrap_config.end_suffix.len(),
10740            ));
10741        }
10742
10743        if edits.is_empty() {
10744            return;
10745        }
10746
10747        self.transact(window, cx, |this, window, cx| {
10748            let buffer = this.buffer.update(cx, |buffer, cx| {
10749                buffer.edit(edits, None, cx);
10750                buffer.snapshot(cx)
10751            });
10752
10753            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10754            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10755                boundaries.into_iter()
10756            {
10757                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10758                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10759                new_selections.push(open_offset..open_offset);
10760                new_selections.push(close_offset..close_offset);
10761            }
10762
10763            this.change_selections(Default::default(), window, cx, |s| {
10764                s.select_ranges(new_selections);
10765            });
10766
10767            this.request_autoscroll(Autoscroll::fit(), cx);
10768        });
10769    }
10770
10771    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10772        let Some(project) = self.project.clone() else {
10773            return;
10774        };
10775        self.reload(project, window, cx)
10776            .detach_and_notify_err(window, cx);
10777    }
10778
10779    pub fn restore_file(
10780        &mut self,
10781        _: &::git::RestoreFile,
10782        window: &mut Window,
10783        cx: &mut Context<Self>,
10784    ) {
10785        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10786        let mut buffer_ids = HashSet::default();
10787        let snapshot = self.buffer().read(cx).snapshot(cx);
10788        for selection in self.selections.all::<usize>(cx) {
10789            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10790        }
10791
10792        let buffer = self.buffer().read(cx);
10793        let ranges = buffer_ids
10794            .into_iter()
10795            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10796            .collect::<Vec<_>>();
10797
10798        self.restore_hunks_in_ranges(ranges, window, cx);
10799    }
10800
10801    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10802        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10803        let selections = self
10804            .selections
10805            .all(cx)
10806            .into_iter()
10807            .map(|s| s.range())
10808            .collect();
10809        self.restore_hunks_in_ranges(selections, window, cx);
10810    }
10811
10812    pub fn restore_hunks_in_ranges(
10813        &mut self,
10814        ranges: Vec<Range<Point>>,
10815        window: &mut Window,
10816        cx: &mut Context<Editor>,
10817    ) {
10818        let mut revert_changes = HashMap::default();
10819        let chunk_by = self
10820            .snapshot(window, cx)
10821            .hunks_for_ranges(ranges)
10822            .into_iter()
10823            .chunk_by(|hunk| hunk.buffer_id);
10824        for (buffer_id, hunks) in &chunk_by {
10825            let hunks = hunks.collect::<Vec<_>>();
10826            for hunk in &hunks {
10827                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10828            }
10829            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10830        }
10831        drop(chunk_by);
10832        if !revert_changes.is_empty() {
10833            self.transact(window, cx, |editor, window, cx| {
10834                editor.restore(revert_changes, window, cx);
10835            });
10836        }
10837    }
10838
10839    pub fn open_active_item_in_terminal(
10840        &mut self,
10841        _: &OpenInTerminal,
10842        window: &mut Window,
10843        cx: &mut Context<Self>,
10844    ) {
10845        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10846            let project_path = buffer.read(cx).project_path(cx)?;
10847            let project = self.project()?.read(cx);
10848            let entry = project.entry_for_path(&project_path, cx)?;
10849            let parent = match &entry.canonical_path {
10850                Some(canonical_path) => canonical_path.to_path_buf(),
10851                None => project.absolute_path(&project_path, cx)?,
10852            }
10853            .parent()?
10854            .to_path_buf();
10855            Some(parent)
10856        }) {
10857            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10858        }
10859    }
10860
10861    fn set_breakpoint_context_menu(
10862        &mut self,
10863        display_row: DisplayRow,
10864        position: Option<Anchor>,
10865        clicked_point: gpui::Point<Pixels>,
10866        window: &mut Window,
10867        cx: &mut Context<Self>,
10868    ) {
10869        let source = self
10870            .buffer
10871            .read(cx)
10872            .snapshot(cx)
10873            .anchor_before(Point::new(display_row.0, 0u32));
10874
10875        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10876
10877        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10878            self,
10879            source,
10880            clicked_point,
10881            context_menu,
10882            window,
10883            cx,
10884        );
10885    }
10886
10887    fn add_edit_breakpoint_block(
10888        &mut self,
10889        anchor: Anchor,
10890        breakpoint: &Breakpoint,
10891        edit_action: BreakpointPromptEditAction,
10892        window: &mut Window,
10893        cx: &mut Context<Self>,
10894    ) {
10895        let weak_editor = cx.weak_entity();
10896        let bp_prompt = cx.new(|cx| {
10897            BreakpointPromptEditor::new(
10898                weak_editor,
10899                anchor,
10900                breakpoint.clone(),
10901                edit_action,
10902                window,
10903                cx,
10904            )
10905        });
10906
10907        let height = bp_prompt.update(cx, |this, cx| {
10908            this.prompt
10909                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10910        });
10911        let cloned_prompt = bp_prompt.clone();
10912        let blocks = vec![BlockProperties {
10913            style: BlockStyle::Sticky,
10914            placement: BlockPlacement::Above(anchor),
10915            height: Some(height),
10916            render: Arc::new(move |cx| {
10917                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10918                cloned_prompt.clone().into_any_element()
10919            }),
10920            priority: 0,
10921        }];
10922
10923        let focus_handle = bp_prompt.focus_handle(cx);
10924        window.focus(&focus_handle);
10925
10926        let block_ids = self.insert_blocks(blocks, None, cx);
10927        bp_prompt.update(cx, |prompt, _| {
10928            prompt.add_block_ids(block_ids);
10929        });
10930    }
10931
10932    pub(crate) fn breakpoint_at_row(
10933        &self,
10934        row: u32,
10935        window: &mut Window,
10936        cx: &mut Context<Self>,
10937    ) -> Option<(Anchor, Breakpoint)> {
10938        let snapshot = self.snapshot(window, cx);
10939        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10940
10941        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10942    }
10943
10944    pub(crate) fn breakpoint_at_anchor(
10945        &self,
10946        breakpoint_position: Anchor,
10947        snapshot: &EditorSnapshot,
10948        cx: &mut Context<Self>,
10949    ) -> Option<(Anchor, Breakpoint)> {
10950        let buffer = self
10951            .buffer
10952            .read(cx)
10953            .buffer_for_anchor(breakpoint_position, cx)?;
10954
10955        let enclosing_excerpt = breakpoint_position.excerpt_id;
10956        let buffer_snapshot = buffer.read(cx).snapshot();
10957
10958        let row = buffer_snapshot
10959            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10960            .row;
10961
10962        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10963        let anchor_end = snapshot
10964            .buffer_snapshot()
10965            .anchor_after(Point::new(row, line_len));
10966
10967        self.breakpoint_store
10968            .as_ref()?
10969            .read_with(cx, |breakpoint_store, cx| {
10970                breakpoint_store
10971                    .breakpoints(
10972                        &buffer,
10973                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10974                        &buffer_snapshot,
10975                        cx,
10976                    )
10977                    .next()
10978                    .and_then(|(bp, _)| {
10979                        let breakpoint_row = buffer_snapshot
10980                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10981                            .row;
10982
10983                        if breakpoint_row == row {
10984                            snapshot
10985                                .buffer_snapshot()
10986                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10987                                .map(|position| (position, bp.bp.clone()))
10988                        } else {
10989                            None
10990                        }
10991                    })
10992            })
10993    }
10994
10995    pub fn edit_log_breakpoint(
10996        &mut self,
10997        _: &EditLogBreakpoint,
10998        window: &mut Window,
10999        cx: &mut Context<Self>,
11000    ) {
11001        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11002            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11003                message: None,
11004                state: BreakpointState::Enabled,
11005                condition: None,
11006                hit_condition: None,
11007            });
11008
11009            self.add_edit_breakpoint_block(
11010                anchor,
11011                &breakpoint,
11012                BreakpointPromptEditAction::Log,
11013                window,
11014                cx,
11015            );
11016        }
11017    }
11018
11019    fn breakpoints_at_cursors(
11020        &self,
11021        window: &mut Window,
11022        cx: &mut Context<Self>,
11023    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11024        let snapshot = self.snapshot(window, cx);
11025        let cursors = self
11026            .selections
11027            .disjoint_anchors_arc()
11028            .iter()
11029            .map(|selection| {
11030                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11031
11032                let breakpoint_position = self
11033                    .breakpoint_at_row(cursor_position.row, window, cx)
11034                    .map(|bp| bp.0)
11035                    .unwrap_or_else(|| {
11036                        snapshot
11037                            .display_snapshot
11038                            .buffer_snapshot()
11039                            .anchor_after(Point::new(cursor_position.row, 0))
11040                    });
11041
11042                let breakpoint = self
11043                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11044                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11045
11046                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11047            })
11048            // 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.
11049            .collect::<HashMap<Anchor, _>>();
11050
11051        cursors.into_iter().collect()
11052    }
11053
11054    pub fn enable_breakpoint(
11055        &mut self,
11056        _: &crate::actions::EnableBreakpoint,
11057        window: &mut Window,
11058        cx: &mut Context<Self>,
11059    ) {
11060        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11061            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11062                continue;
11063            };
11064            self.edit_breakpoint_at_anchor(
11065                anchor,
11066                breakpoint,
11067                BreakpointEditAction::InvertState,
11068                cx,
11069            );
11070        }
11071    }
11072
11073    pub fn disable_breakpoint(
11074        &mut self,
11075        _: &crate::actions::DisableBreakpoint,
11076        window: &mut Window,
11077        cx: &mut Context<Self>,
11078    ) {
11079        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11080            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11081                continue;
11082            };
11083            self.edit_breakpoint_at_anchor(
11084                anchor,
11085                breakpoint,
11086                BreakpointEditAction::InvertState,
11087                cx,
11088            );
11089        }
11090    }
11091
11092    pub fn toggle_breakpoint(
11093        &mut self,
11094        _: &crate::actions::ToggleBreakpoint,
11095        window: &mut Window,
11096        cx: &mut Context<Self>,
11097    ) {
11098        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11099            if let Some(breakpoint) = breakpoint {
11100                self.edit_breakpoint_at_anchor(
11101                    anchor,
11102                    breakpoint,
11103                    BreakpointEditAction::Toggle,
11104                    cx,
11105                );
11106            } else {
11107                self.edit_breakpoint_at_anchor(
11108                    anchor,
11109                    Breakpoint::new_standard(),
11110                    BreakpointEditAction::Toggle,
11111                    cx,
11112                );
11113            }
11114        }
11115    }
11116
11117    pub fn edit_breakpoint_at_anchor(
11118        &mut self,
11119        breakpoint_position: Anchor,
11120        breakpoint: Breakpoint,
11121        edit_action: BreakpointEditAction,
11122        cx: &mut Context<Self>,
11123    ) {
11124        let Some(breakpoint_store) = &self.breakpoint_store else {
11125            return;
11126        };
11127
11128        let Some(buffer) = self
11129            .buffer
11130            .read(cx)
11131            .buffer_for_anchor(breakpoint_position, cx)
11132        else {
11133            return;
11134        };
11135
11136        breakpoint_store.update(cx, |breakpoint_store, cx| {
11137            breakpoint_store.toggle_breakpoint(
11138                buffer,
11139                BreakpointWithPosition {
11140                    position: breakpoint_position.text_anchor,
11141                    bp: breakpoint,
11142                },
11143                edit_action,
11144                cx,
11145            );
11146        });
11147
11148        cx.notify();
11149    }
11150
11151    #[cfg(any(test, feature = "test-support"))]
11152    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11153        self.breakpoint_store.clone()
11154    }
11155
11156    pub fn prepare_restore_change(
11157        &self,
11158        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11159        hunk: &MultiBufferDiffHunk,
11160        cx: &mut App,
11161    ) -> Option<()> {
11162        if hunk.is_created_file() {
11163            return None;
11164        }
11165        let buffer = self.buffer.read(cx);
11166        let diff = buffer.diff_for(hunk.buffer_id)?;
11167        let buffer = buffer.buffer(hunk.buffer_id)?;
11168        let buffer = buffer.read(cx);
11169        let original_text = diff
11170            .read(cx)
11171            .base_text()
11172            .as_rope()
11173            .slice(hunk.diff_base_byte_range.clone());
11174        let buffer_snapshot = buffer.snapshot();
11175        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11176        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11177            probe
11178                .0
11179                .start
11180                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11181                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11182        }) {
11183            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11184            Some(())
11185        } else {
11186            None
11187        }
11188    }
11189
11190    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11191        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11192    }
11193
11194    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11195        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11196    }
11197
11198    fn manipulate_lines<M>(
11199        &mut self,
11200        window: &mut Window,
11201        cx: &mut Context<Self>,
11202        mut manipulate: M,
11203    ) where
11204        M: FnMut(&str) -> LineManipulationResult,
11205    {
11206        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11207
11208        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11209        let buffer = self.buffer.read(cx).snapshot(cx);
11210
11211        let mut edits = Vec::new();
11212
11213        let selections = self.selections.all::<Point>(cx);
11214        let mut selections = selections.iter().peekable();
11215        let mut contiguous_row_selections = Vec::new();
11216        let mut new_selections = Vec::new();
11217        let mut added_lines = 0;
11218        let mut removed_lines = 0;
11219
11220        while let Some(selection) = selections.next() {
11221            let (start_row, end_row) = consume_contiguous_rows(
11222                &mut contiguous_row_selections,
11223                selection,
11224                &display_map,
11225                &mut selections,
11226            );
11227
11228            let start_point = Point::new(start_row.0, 0);
11229            let end_point = Point::new(
11230                end_row.previous_row().0,
11231                buffer.line_len(end_row.previous_row()),
11232            );
11233            let text = buffer
11234                .text_for_range(start_point..end_point)
11235                .collect::<String>();
11236
11237            let LineManipulationResult {
11238                new_text,
11239                line_count_before,
11240                line_count_after,
11241            } = manipulate(&text);
11242
11243            edits.push((start_point..end_point, new_text));
11244
11245            // Selections must change based on added and removed line count
11246            let start_row =
11247                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11248            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11249            new_selections.push(Selection {
11250                id: selection.id,
11251                start: start_row,
11252                end: end_row,
11253                goal: SelectionGoal::None,
11254                reversed: selection.reversed,
11255            });
11256
11257            if line_count_after > line_count_before {
11258                added_lines += line_count_after - line_count_before;
11259            } else if line_count_before > line_count_after {
11260                removed_lines += line_count_before - line_count_after;
11261            }
11262        }
11263
11264        self.transact(window, cx, |this, window, cx| {
11265            let buffer = this.buffer.update(cx, |buffer, cx| {
11266                buffer.edit(edits, None, cx);
11267                buffer.snapshot(cx)
11268            });
11269
11270            // Recalculate offsets on newly edited buffer
11271            let new_selections = new_selections
11272                .iter()
11273                .map(|s| {
11274                    let start_point = Point::new(s.start.0, 0);
11275                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11276                    Selection {
11277                        id: s.id,
11278                        start: buffer.point_to_offset(start_point),
11279                        end: buffer.point_to_offset(end_point),
11280                        goal: s.goal,
11281                        reversed: s.reversed,
11282                    }
11283                })
11284                .collect();
11285
11286            this.change_selections(Default::default(), window, cx, |s| {
11287                s.select(new_selections);
11288            });
11289
11290            this.request_autoscroll(Autoscroll::fit(), cx);
11291        });
11292    }
11293
11294    fn manipulate_immutable_lines<Fn>(
11295        &mut self,
11296        window: &mut Window,
11297        cx: &mut Context<Self>,
11298        mut callback: Fn,
11299    ) where
11300        Fn: FnMut(&mut Vec<&str>),
11301    {
11302        self.manipulate_lines(window, cx, |text| {
11303            let mut lines: Vec<&str> = text.split('\n').collect();
11304            let line_count_before = lines.len();
11305
11306            callback(&mut lines);
11307
11308            LineManipulationResult {
11309                new_text: lines.join("\n"),
11310                line_count_before,
11311                line_count_after: lines.len(),
11312            }
11313        });
11314    }
11315
11316    fn manipulate_mutable_lines<Fn>(
11317        &mut self,
11318        window: &mut Window,
11319        cx: &mut Context<Self>,
11320        mut callback: Fn,
11321    ) where
11322        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11323    {
11324        self.manipulate_lines(window, cx, |text| {
11325            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11326            let line_count_before = lines.len();
11327
11328            callback(&mut lines);
11329
11330            LineManipulationResult {
11331                new_text: lines.join("\n"),
11332                line_count_before,
11333                line_count_after: lines.len(),
11334            }
11335        });
11336    }
11337
11338    pub fn convert_indentation_to_spaces(
11339        &mut self,
11340        _: &ConvertIndentationToSpaces,
11341        window: &mut Window,
11342        cx: &mut Context<Self>,
11343    ) {
11344        let settings = self.buffer.read(cx).language_settings(cx);
11345        let tab_size = settings.tab_size.get() as usize;
11346
11347        self.manipulate_mutable_lines(window, cx, |lines| {
11348            // Allocates a reasonably sized scratch buffer once for the whole loop
11349            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11350            // Avoids recomputing spaces that could be inserted many times
11351            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11352                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11353                .collect();
11354
11355            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11356                let mut chars = line.as_ref().chars();
11357                let mut col = 0;
11358                let mut changed = false;
11359
11360                for ch in chars.by_ref() {
11361                    match ch {
11362                        ' ' => {
11363                            reindented_line.push(' ');
11364                            col += 1;
11365                        }
11366                        '\t' => {
11367                            // \t are converted to spaces depending on the current column
11368                            let spaces_len = tab_size - (col % tab_size);
11369                            reindented_line.extend(&space_cache[spaces_len - 1]);
11370                            col += spaces_len;
11371                            changed = true;
11372                        }
11373                        _ => {
11374                            // If we dont append before break, the character is consumed
11375                            reindented_line.push(ch);
11376                            break;
11377                        }
11378                    }
11379                }
11380
11381                if !changed {
11382                    reindented_line.clear();
11383                    continue;
11384                }
11385                // Append the rest of the line and replace old reference with new one
11386                reindented_line.extend(chars);
11387                *line = Cow::Owned(reindented_line.clone());
11388                reindented_line.clear();
11389            }
11390        });
11391    }
11392
11393    pub fn convert_indentation_to_tabs(
11394        &mut self,
11395        _: &ConvertIndentationToTabs,
11396        window: &mut Window,
11397        cx: &mut Context<Self>,
11398    ) {
11399        let settings = self.buffer.read(cx).language_settings(cx);
11400        let tab_size = settings.tab_size.get() as usize;
11401
11402        self.manipulate_mutable_lines(window, cx, |lines| {
11403            // Allocates a reasonably sized buffer once for the whole loop
11404            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11405            // Avoids recomputing spaces that could be inserted many times
11406            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11407                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11408                .collect();
11409
11410            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11411                let mut chars = line.chars();
11412                let mut spaces_count = 0;
11413                let mut first_non_indent_char = None;
11414                let mut changed = false;
11415
11416                for ch in chars.by_ref() {
11417                    match ch {
11418                        ' ' => {
11419                            // Keep track of spaces. Append \t when we reach tab_size
11420                            spaces_count += 1;
11421                            changed = true;
11422                            if spaces_count == tab_size {
11423                                reindented_line.push('\t');
11424                                spaces_count = 0;
11425                            }
11426                        }
11427                        '\t' => {
11428                            reindented_line.push('\t');
11429                            spaces_count = 0;
11430                        }
11431                        _ => {
11432                            // Dont append it yet, we might have remaining spaces
11433                            first_non_indent_char = Some(ch);
11434                            break;
11435                        }
11436                    }
11437                }
11438
11439                if !changed {
11440                    reindented_line.clear();
11441                    continue;
11442                }
11443                // Remaining spaces that didn't make a full tab stop
11444                if spaces_count > 0 {
11445                    reindented_line.extend(&space_cache[spaces_count - 1]);
11446                }
11447                // If we consume an extra character that was not indentation, add it back
11448                if let Some(extra_char) = first_non_indent_char {
11449                    reindented_line.push(extra_char);
11450                }
11451                // Append the rest of the line and replace old reference with new one
11452                reindented_line.extend(chars);
11453                *line = Cow::Owned(reindented_line.clone());
11454                reindented_line.clear();
11455            }
11456        });
11457    }
11458
11459    pub fn convert_to_upper_case(
11460        &mut self,
11461        _: &ConvertToUpperCase,
11462        window: &mut Window,
11463        cx: &mut Context<Self>,
11464    ) {
11465        self.manipulate_text(window, cx, |text| text.to_uppercase())
11466    }
11467
11468    pub fn convert_to_lower_case(
11469        &mut self,
11470        _: &ConvertToLowerCase,
11471        window: &mut Window,
11472        cx: &mut Context<Self>,
11473    ) {
11474        self.manipulate_text(window, cx, |text| text.to_lowercase())
11475    }
11476
11477    pub fn convert_to_title_case(
11478        &mut self,
11479        _: &ConvertToTitleCase,
11480        window: &mut Window,
11481        cx: &mut Context<Self>,
11482    ) {
11483        self.manipulate_text(window, cx, |text| {
11484            text.split('\n')
11485                .map(|line| line.to_case(Case::Title))
11486                .join("\n")
11487        })
11488    }
11489
11490    pub fn convert_to_snake_case(
11491        &mut self,
11492        _: &ConvertToSnakeCase,
11493        window: &mut Window,
11494        cx: &mut Context<Self>,
11495    ) {
11496        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11497    }
11498
11499    pub fn convert_to_kebab_case(
11500        &mut self,
11501        _: &ConvertToKebabCase,
11502        window: &mut Window,
11503        cx: &mut Context<Self>,
11504    ) {
11505        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11506    }
11507
11508    pub fn convert_to_upper_camel_case(
11509        &mut self,
11510        _: &ConvertToUpperCamelCase,
11511        window: &mut Window,
11512        cx: &mut Context<Self>,
11513    ) {
11514        self.manipulate_text(window, cx, |text| {
11515            text.split('\n')
11516                .map(|line| line.to_case(Case::UpperCamel))
11517                .join("\n")
11518        })
11519    }
11520
11521    pub fn convert_to_lower_camel_case(
11522        &mut self,
11523        _: &ConvertToLowerCamelCase,
11524        window: &mut Window,
11525        cx: &mut Context<Self>,
11526    ) {
11527        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11528    }
11529
11530    pub fn convert_to_opposite_case(
11531        &mut self,
11532        _: &ConvertToOppositeCase,
11533        window: &mut Window,
11534        cx: &mut Context<Self>,
11535    ) {
11536        self.manipulate_text(window, cx, |text| {
11537            text.chars()
11538                .fold(String::with_capacity(text.len()), |mut t, c| {
11539                    if c.is_uppercase() {
11540                        t.extend(c.to_lowercase());
11541                    } else {
11542                        t.extend(c.to_uppercase());
11543                    }
11544                    t
11545                })
11546        })
11547    }
11548
11549    pub fn convert_to_sentence_case(
11550        &mut self,
11551        _: &ConvertToSentenceCase,
11552        window: &mut Window,
11553        cx: &mut Context<Self>,
11554    ) {
11555        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11556    }
11557
11558    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11559        self.manipulate_text(window, cx, |text| {
11560            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11561            if has_upper_case_characters {
11562                text.to_lowercase()
11563            } else {
11564                text.to_uppercase()
11565            }
11566        })
11567    }
11568
11569    pub fn convert_to_rot13(
11570        &mut self,
11571        _: &ConvertToRot13,
11572        window: &mut Window,
11573        cx: &mut Context<Self>,
11574    ) {
11575        self.manipulate_text(window, cx, |text| {
11576            text.chars()
11577                .map(|c| match c {
11578                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11579                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11580                    _ => c,
11581                })
11582                .collect()
11583        })
11584    }
11585
11586    pub fn convert_to_rot47(
11587        &mut self,
11588        _: &ConvertToRot47,
11589        window: &mut Window,
11590        cx: &mut Context<Self>,
11591    ) {
11592        self.manipulate_text(window, cx, |text| {
11593            text.chars()
11594                .map(|c| {
11595                    let code_point = c as u32;
11596                    if code_point >= 33 && code_point <= 126 {
11597                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11598                    }
11599                    c
11600                })
11601                .collect()
11602        })
11603    }
11604
11605    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11606    where
11607        Fn: FnMut(&str) -> String,
11608    {
11609        let buffer = self.buffer.read(cx).snapshot(cx);
11610
11611        let mut new_selections = Vec::new();
11612        let mut edits = Vec::new();
11613        let mut selection_adjustment = 0i32;
11614
11615        for selection in self.selections.all_adjusted(cx) {
11616            let selection_is_empty = selection.is_empty();
11617
11618            let (start, end) = if selection_is_empty {
11619                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11620                (word_range.start, word_range.end)
11621            } else {
11622                (
11623                    buffer.point_to_offset(selection.start),
11624                    buffer.point_to_offset(selection.end),
11625                )
11626            };
11627
11628            let text = buffer.text_for_range(start..end).collect::<String>();
11629            let old_length = text.len() as i32;
11630            let text = callback(&text);
11631
11632            new_selections.push(Selection {
11633                start: (start as i32 - selection_adjustment) as usize,
11634                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11635                goal: SelectionGoal::None,
11636                id: selection.id,
11637                reversed: selection.reversed,
11638            });
11639
11640            selection_adjustment += old_length - text.len() as i32;
11641
11642            edits.push((start..end, text));
11643        }
11644
11645        self.transact(window, cx, |this, window, cx| {
11646            this.buffer.update(cx, |buffer, cx| {
11647                buffer.edit(edits, None, cx);
11648            });
11649
11650            this.change_selections(Default::default(), window, cx, |s| {
11651                s.select(new_selections);
11652            });
11653
11654            this.request_autoscroll(Autoscroll::fit(), cx);
11655        });
11656    }
11657
11658    pub fn move_selection_on_drop(
11659        &mut self,
11660        selection: &Selection<Anchor>,
11661        target: DisplayPoint,
11662        is_cut: bool,
11663        window: &mut Window,
11664        cx: &mut Context<Self>,
11665    ) {
11666        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11667        let buffer = display_map.buffer_snapshot();
11668        let mut edits = Vec::new();
11669        let insert_point = display_map
11670            .clip_point(target, Bias::Left)
11671            .to_point(&display_map);
11672        let text = buffer
11673            .text_for_range(selection.start..selection.end)
11674            .collect::<String>();
11675        if is_cut {
11676            edits.push(((selection.start..selection.end), String::new()));
11677        }
11678        let insert_anchor = buffer.anchor_before(insert_point);
11679        edits.push(((insert_anchor..insert_anchor), text));
11680        let last_edit_start = insert_anchor.bias_left(buffer);
11681        let last_edit_end = insert_anchor.bias_right(buffer);
11682        self.transact(window, cx, |this, window, cx| {
11683            this.buffer.update(cx, |buffer, cx| {
11684                buffer.edit(edits, None, cx);
11685            });
11686            this.change_selections(Default::default(), window, cx, |s| {
11687                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11688            });
11689        });
11690    }
11691
11692    pub fn clear_selection_drag_state(&mut self) {
11693        self.selection_drag_state = SelectionDragState::None;
11694    }
11695
11696    pub fn duplicate(
11697        &mut self,
11698        upwards: bool,
11699        whole_lines: bool,
11700        window: &mut Window,
11701        cx: &mut Context<Self>,
11702    ) {
11703        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11704
11705        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11706        let buffer = display_map.buffer_snapshot();
11707        let selections = self.selections.all::<Point>(cx);
11708
11709        let mut edits = Vec::new();
11710        let mut selections_iter = selections.iter().peekable();
11711        while let Some(selection) = selections_iter.next() {
11712            let mut rows = selection.spanned_rows(false, &display_map);
11713            // duplicate line-wise
11714            if whole_lines || selection.start == selection.end {
11715                // Avoid duplicating the same lines twice.
11716                while let Some(next_selection) = selections_iter.peek() {
11717                    let next_rows = next_selection.spanned_rows(false, &display_map);
11718                    if next_rows.start < rows.end {
11719                        rows.end = next_rows.end;
11720                        selections_iter.next().unwrap();
11721                    } else {
11722                        break;
11723                    }
11724                }
11725
11726                // Copy the text from the selected row region and splice it either at the start
11727                // or end of the region.
11728                let start = Point::new(rows.start.0, 0);
11729                let end = Point::new(
11730                    rows.end.previous_row().0,
11731                    buffer.line_len(rows.end.previous_row()),
11732                );
11733
11734                let mut text = buffer.text_for_range(start..end).collect::<String>();
11735
11736                let insert_location = if upwards {
11737                    // When duplicating upward, we need to insert before the current line.
11738                    // If we're on the last line and it doesn't end with a newline,
11739                    // we need to add a newline before the duplicated content.
11740                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11741                        && buffer.max_point().column > 0
11742                        && !text.ends_with('\n');
11743
11744                    if needs_leading_newline {
11745                        text.insert(0, '\n');
11746                        end
11747                    } else {
11748                        text.push('\n');
11749                        Point::new(rows.end.0, 0)
11750                    }
11751                } else {
11752                    text.push('\n');
11753                    start
11754                };
11755                edits.push((insert_location..insert_location, text));
11756            } else {
11757                // duplicate character-wise
11758                let start = selection.start;
11759                let end = selection.end;
11760                let text = buffer.text_for_range(start..end).collect::<String>();
11761                edits.push((selection.end..selection.end, text));
11762            }
11763        }
11764
11765        self.transact(window, cx, |this, _, cx| {
11766            this.buffer.update(cx, |buffer, cx| {
11767                buffer.edit(edits, None, cx);
11768            });
11769
11770            this.request_autoscroll(Autoscroll::fit(), cx);
11771        });
11772    }
11773
11774    pub fn duplicate_line_up(
11775        &mut self,
11776        _: &DuplicateLineUp,
11777        window: &mut Window,
11778        cx: &mut Context<Self>,
11779    ) {
11780        self.duplicate(true, true, window, cx);
11781    }
11782
11783    pub fn duplicate_line_down(
11784        &mut self,
11785        _: &DuplicateLineDown,
11786        window: &mut Window,
11787        cx: &mut Context<Self>,
11788    ) {
11789        self.duplicate(false, true, window, cx);
11790    }
11791
11792    pub fn duplicate_selection(
11793        &mut self,
11794        _: &DuplicateSelection,
11795        window: &mut Window,
11796        cx: &mut Context<Self>,
11797    ) {
11798        self.duplicate(false, false, window, cx);
11799    }
11800
11801    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11802        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11803        if self.mode.is_single_line() {
11804            cx.propagate();
11805            return;
11806        }
11807
11808        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11809        let buffer = self.buffer.read(cx).snapshot(cx);
11810
11811        let mut edits = Vec::new();
11812        let mut unfold_ranges = Vec::new();
11813        let mut refold_creases = Vec::new();
11814
11815        let selections = self.selections.all::<Point>(cx);
11816        let mut selections = selections.iter().peekable();
11817        let mut contiguous_row_selections = Vec::new();
11818        let mut new_selections = Vec::new();
11819
11820        while let Some(selection) = selections.next() {
11821            // Find all the selections that span a contiguous row range
11822            let (start_row, end_row) = consume_contiguous_rows(
11823                &mut contiguous_row_selections,
11824                selection,
11825                &display_map,
11826                &mut selections,
11827            );
11828
11829            // Move the text spanned by the row range to be before the line preceding the row range
11830            if start_row.0 > 0 {
11831                let range_to_move = Point::new(
11832                    start_row.previous_row().0,
11833                    buffer.line_len(start_row.previous_row()),
11834                )
11835                    ..Point::new(
11836                        end_row.previous_row().0,
11837                        buffer.line_len(end_row.previous_row()),
11838                    );
11839                let insertion_point = display_map
11840                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11841                    .0;
11842
11843                // Don't move lines across excerpts
11844                if buffer
11845                    .excerpt_containing(insertion_point..range_to_move.end)
11846                    .is_some()
11847                {
11848                    let text = buffer
11849                        .text_for_range(range_to_move.clone())
11850                        .flat_map(|s| s.chars())
11851                        .skip(1)
11852                        .chain(['\n'])
11853                        .collect::<String>();
11854
11855                    edits.push((
11856                        buffer.anchor_after(range_to_move.start)
11857                            ..buffer.anchor_before(range_to_move.end),
11858                        String::new(),
11859                    ));
11860                    let insertion_anchor = buffer.anchor_after(insertion_point);
11861                    edits.push((insertion_anchor..insertion_anchor, text));
11862
11863                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11864
11865                    // Move selections up
11866                    new_selections.extend(contiguous_row_selections.drain(..).map(
11867                        |mut selection| {
11868                            selection.start.row -= row_delta;
11869                            selection.end.row -= row_delta;
11870                            selection
11871                        },
11872                    ));
11873
11874                    // Move folds up
11875                    unfold_ranges.push(range_to_move.clone());
11876                    for fold in display_map.folds_in_range(
11877                        buffer.anchor_before(range_to_move.start)
11878                            ..buffer.anchor_after(range_to_move.end),
11879                    ) {
11880                        let mut start = fold.range.start.to_point(&buffer);
11881                        let mut end = fold.range.end.to_point(&buffer);
11882                        start.row -= row_delta;
11883                        end.row -= row_delta;
11884                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11885                    }
11886                }
11887            }
11888
11889            // If we didn't move line(s), preserve the existing selections
11890            new_selections.append(&mut contiguous_row_selections);
11891        }
11892
11893        self.transact(window, cx, |this, window, cx| {
11894            this.unfold_ranges(&unfold_ranges, true, true, cx);
11895            this.buffer.update(cx, |buffer, cx| {
11896                for (range, text) in edits {
11897                    buffer.edit([(range, text)], None, cx);
11898                }
11899            });
11900            this.fold_creases(refold_creases, true, window, cx);
11901            this.change_selections(Default::default(), window, cx, |s| {
11902                s.select(new_selections);
11903            })
11904        });
11905    }
11906
11907    pub fn move_line_down(
11908        &mut self,
11909        _: &MoveLineDown,
11910        window: &mut Window,
11911        cx: &mut Context<Self>,
11912    ) {
11913        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11914        if self.mode.is_single_line() {
11915            cx.propagate();
11916            return;
11917        }
11918
11919        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11920        let buffer = self.buffer.read(cx).snapshot(cx);
11921
11922        let mut edits = Vec::new();
11923        let mut unfold_ranges = Vec::new();
11924        let mut refold_creases = Vec::new();
11925
11926        let selections = self.selections.all::<Point>(cx);
11927        let mut selections = selections.iter().peekable();
11928        let mut contiguous_row_selections = Vec::new();
11929        let mut new_selections = Vec::new();
11930
11931        while let Some(selection) = selections.next() {
11932            // Find all the selections that span a contiguous row range
11933            let (start_row, end_row) = consume_contiguous_rows(
11934                &mut contiguous_row_selections,
11935                selection,
11936                &display_map,
11937                &mut selections,
11938            );
11939
11940            // Move the text spanned by the row range to be after the last line of the row range
11941            if end_row.0 <= buffer.max_point().row {
11942                let range_to_move =
11943                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11944                let insertion_point = display_map
11945                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11946                    .0;
11947
11948                // Don't move lines across excerpt boundaries
11949                if buffer
11950                    .excerpt_containing(range_to_move.start..insertion_point)
11951                    .is_some()
11952                {
11953                    let mut text = String::from("\n");
11954                    text.extend(buffer.text_for_range(range_to_move.clone()));
11955                    text.pop(); // Drop trailing newline
11956                    edits.push((
11957                        buffer.anchor_after(range_to_move.start)
11958                            ..buffer.anchor_before(range_to_move.end),
11959                        String::new(),
11960                    ));
11961                    let insertion_anchor = buffer.anchor_after(insertion_point);
11962                    edits.push((insertion_anchor..insertion_anchor, text));
11963
11964                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11965
11966                    // Move selections down
11967                    new_selections.extend(contiguous_row_selections.drain(..).map(
11968                        |mut selection| {
11969                            selection.start.row += row_delta;
11970                            selection.end.row += row_delta;
11971                            selection
11972                        },
11973                    ));
11974
11975                    // Move folds down
11976                    unfold_ranges.push(range_to_move.clone());
11977                    for fold in display_map.folds_in_range(
11978                        buffer.anchor_before(range_to_move.start)
11979                            ..buffer.anchor_after(range_to_move.end),
11980                    ) {
11981                        let mut start = fold.range.start.to_point(&buffer);
11982                        let mut end = fold.range.end.to_point(&buffer);
11983                        start.row += row_delta;
11984                        end.row += row_delta;
11985                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11986                    }
11987                }
11988            }
11989
11990            // If we didn't move line(s), preserve the existing selections
11991            new_selections.append(&mut contiguous_row_selections);
11992        }
11993
11994        self.transact(window, cx, |this, window, cx| {
11995            this.unfold_ranges(&unfold_ranges, true, true, cx);
11996            this.buffer.update(cx, |buffer, cx| {
11997                for (range, text) in edits {
11998                    buffer.edit([(range, text)], None, cx);
11999                }
12000            });
12001            this.fold_creases(refold_creases, true, window, cx);
12002            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12003        });
12004    }
12005
12006    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12007        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12008        let text_layout_details = &self.text_layout_details(window);
12009        self.transact(window, cx, |this, window, cx| {
12010            let edits = this.change_selections(Default::default(), window, cx, |s| {
12011                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12012                s.move_with(|display_map, selection| {
12013                    if !selection.is_empty() {
12014                        return;
12015                    }
12016
12017                    let mut head = selection.head();
12018                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12019                    if head.column() == display_map.line_len(head.row()) {
12020                        transpose_offset = display_map
12021                            .buffer_snapshot()
12022                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12023                    }
12024
12025                    if transpose_offset == 0 {
12026                        return;
12027                    }
12028
12029                    *head.column_mut() += 1;
12030                    head = display_map.clip_point(head, Bias::Right);
12031                    let goal = SelectionGoal::HorizontalPosition(
12032                        display_map
12033                            .x_for_display_point(head, text_layout_details)
12034                            .into(),
12035                    );
12036                    selection.collapse_to(head, goal);
12037
12038                    let transpose_start = display_map
12039                        .buffer_snapshot()
12040                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12041                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12042                        let transpose_end = display_map
12043                            .buffer_snapshot()
12044                            .clip_offset(transpose_offset + 1, Bias::Right);
12045                        if let Some(ch) = display_map
12046                            .buffer_snapshot()
12047                            .chars_at(transpose_start)
12048                            .next()
12049                        {
12050                            edits.push((transpose_start..transpose_offset, String::new()));
12051                            edits.push((transpose_end..transpose_end, ch.to_string()));
12052                        }
12053                    }
12054                });
12055                edits
12056            });
12057            this.buffer
12058                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12059            let selections = this.selections.all::<usize>(cx);
12060            this.change_selections(Default::default(), window, cx, |s| {
12061                s.select(selections);
12062            });
12063        });
12064    }
12065
12066    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12067        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12068        if self.mode.is_single_line() {
12069            cx.propagate();
12070            return;
12071        }
12072
12073        self.rewrap_impl(RewrapOptions::default(), cx)
12074    }
12075
12076    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12077        let buffer = self.buffer.read(cx).snapshot(cx);
12078        let selections = self.selections.all::<Point>(cx);
12079
12080        #[derive(Clone, Debug, PartialEq)]
12081        enum CommentFormat {
12082            /// single line comment, with prefix for line
12083            Line(String),
12084            /// single line within a block comment, with prefix for line
12085            BlockLine(String),
12086            /// a single line of a block comment that includes the initial delimiter
12087            BlockCommentWithStart(BlockCommentConfig),
12088            /// a single line of a block comment that includes the ending delimiter
12089            BlockCommentWithEnd(BlockCommentConfig),
12090        }
12091
12092        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12093        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12094            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12095                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12096                .peekable();
12097
12098            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12099                row
12100            } else {
12101                return Vec::new();
12102            };
12103
12104            let language_settings = buffer.language_settings_at(selection.head(), cx);
12105            let language_scope = buffer.language_scope_at(selection.head());
12106
12107            let indent_and_prefix_for_row =
12108                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12109                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12110                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12111                        &language_scope
12112                    {
12113                        let indent_end = Point::new(row, indent.len);
12114                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12115                        let line_text_after_indent = buffer
12116                            .text_for_range(indent_end..line_end)
12117                            .collect::<String>();
12118
12119                        let is_within_comment_override = buffer
12120                            .language_scope_at(indent_end)
12121                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12122                        let comment_delimiters = if is_within_comment_override {
12123                            // we are within a comment syntax node, but we don't
12124                            // yet know what kind of comment: block, doc or line
12125                            match (
12126                                language_scope.documentation_comment(),
12127                                language_scope.block_comment(),
12128                            ) {
12129                                (Some(config), _) | (_, Some(config))
12130                                    if buffer.contains_str_at(indent_end, &config.start) =>
12131                                {
12132                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12133                                }
12134                                (Some(config), _) | (_, Some(config))
12135                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12136                                {
12137                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12138                                }
12139                                (Some(config), _) | (_, Some(config))
12140                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12141                                {
12142                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12143                                }
12144                                (_, _) => language_scope
12145                                    .line_comment_prefixes()
12146                                    .iter()
12147                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12148                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12149                            }
12150                        } else {
12151                            // we not in an overridden comment node, but we may
12152                            // be within a non-overridden line comment node
12153                            language_scope
12154                                .line_comment_prefixes()
12155                                .iter()
12156                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12157                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12158                        };
12159
12160                        let rewrap_prefix = language_scope
12161                            .rewrap_prefixes()
12162                            .iter()
12163                            .find_map(|prefix_regex| {
12164                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12165                                    if mat.start() == 0 {
12166                                        Some(mat.as_str().to_string())
12167                                    } else {
12168                                        None
12169                                    }
12170                                })
12171                            })
12172                            .flatten();
12173                        (comment_delimiters, rewrap_prefix)
12174                    } else {
12175                        (None, None)
12176                    };
12177                    (indent, comment_prefix, rewrap_prefix)
12178                };
12179
12180            let mut ranges = Vec::new();
12181            let from_empty_selection = selection.is_empty();
12182
12183            let mut current_range_start = first_row;
12184            let mut prev_row = first_row;
12185            let (
12186                mut current_range_indent,
12187                mut current_range_comment_delimiters,
12188                mut current_range_rewrap_prefix,
12189            ) = indent_and_prefix_for_row(first_row);
12190
12191            for row in non_blank_rows_iter.skip(1) {
12192                let has_paragraph_break = row > prev_row + 1;
12193
12194                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12195                    indent_and_prefix_for_row(row);
12196
12197                let has_indent_change = row_indent != current_range_indent;
12198                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12199
12200                let has_boundary_change = has_comment_change
12201                    || row_rewrap_prefix.is_some()
12202                    || (has_indent_change && current_range_comment_delimiters.is_some());
12203
12204                if has_paragraph_break || has_boundary_change {
12205                    ranges.push((
12206                        language_settings.clone(),
12207                        Point::new(current_range_start, 0)
12208                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12209                        current_range_indent,
12210                        current_range_comment_delimiters.clone(),
12211                        current_range_rewrap_prefix.clone(),
12212                        from_empty_selection,
12213                    ));
12214                    current_range_start = row;
12215                    current_range_indent = row_indent;
12216                    current_range_comment_delimiters = row_comment_delimiters;
12217                    current_range_rewrap_prefix = row_rewrap_prefix;
12218                }
12219                prev_row = row;
12220            }
12221
12222            ranges.push((
12223                language_settings.clone(),
12224                Point::new(current_range_start, 0)
12225                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12226                current_range_indent,
12227                current_range_comment_delimiters,
12228                current_range_rewrap_prefix,
12229                from_empty_selection,
12230            ));
12231
12232            ranges
12233        });
12234
12235        let mut edits = Vec::new();
12236        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12237
12238        for (
12239            language_settings,
12240            wrap_range,
12241            mut indent_size,
12242            comment_prefix,
12243            rewrap_prefix,
12244            from_empty_selection,
12245        ) in wrap_ranges
12246        {
12247            let mut start_row = wrap_range.start.row;
12248            let mut end_row = wrap_range.end.row;
12249
12250            // Skip selections that overlap with a range that has already been rewrapped.
12251            let selection_range = start_row..end_row;
12252            if rewrapped_row_ranges
12253                .iter()
12254                .any(|range| range.overlaps(&selection_range))
12255            {
12256                continue;
12257            }
12258
12259            let tab_size = language_settings.tab_size;
12260
12261            let (line_prefix, inside_comment) = match &comment_prefix {
12262                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12263                    (Some(prefix.as_str()), true)
12264                }
12265                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12266                    (Some(prefix.as_ref()), true)
12267                }
12268                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12269                    start: _,
12270                    end: _,
12271                    prefix,
12272                    tab_size,
12273                })) => {
12274                    indent_size.len += tab_size;
12275                    (Some(prefix.as_ref()), true)
12276                }
12277                None => (None, false),
12278            };
12279            let indent_prefix = indent_size.chars().collect::<String>();
12280            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12281
12282            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12283                RewrapBehavior::InComments => inside_comment,
12284                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12285                RewrapBehavior::Anywhere => true,
12286            };
12287
12288            let should_rewrap = options.override_language_settings
12289                || allow_rewrap_based_on_language
12290                || self.hard_wrap.is_some();
12291            if !should_rewrap {
12292                continue;
12293            }
12294
12295            if from_empty_selection {
12296                'expand_upwards: while start_row > 0 {
12297                    let prev_row = start_row - 1;
12298                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12299                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12300                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12301                    {
12302                        start_row = prev_row;
12303                    } else {
12304                        break 'expand_upwards;
12305                    }
12306                }
12307
12308                'expand_downwards: while end_row < buffer.max_point().row {
12309                    let next_row = end_row + 1;
12310                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12311                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12312                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12313                    {
12314                        end_row = next_row;
12315                    } else {
12316                        break 'expand_downwards;
12317                    }
12318                }
12319            }
12320
12321            let start = Point::new(start_row, 0);
12322            let start_offset = ToOffset::to_offset(&start, &buffer);
12323            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12324            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12325            let mut first_line_delimiter = None;
12326            let mut last_line_delimiter = None;
12327            let Some(lines_without_prefixes) = selection_text
12328                .lines()
12329                .enumerate()
12330                .map(|(ix, line)| {
12331                    let line_trimmed = line.trim_start();
12332                    if rewrap_prefix.is_some() && ix > 0 {
12333                        Ok(line_trimmed)
12334                    } else if let Some(
12335                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12336                            start,
12337                            prefix,
12338                            end,
12339                            tab_size,
12340                        })
12341                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12342                            start,
12343                            prefix,
12344                            end,
12345                            tab_size,
12346                        }),
12347                    ) = &comment_prefix
12348                    {
12349                        let line_trimmed = line_trimmed
12350                            .strip_prefix(start.as_ref())
12351                            .map(|s| {
12352                                let mut indent_size = indent_size;
12353                                indent_size.len -= tab_size;
12354                                let indent_prefix: String = indent_size.chars().collect();
12355                                first_line_delimiter = Some((indent_prefix, start));
12356                                s.trim_start()
12357                            })
12358                            .unwrap_or(line_trimmed);
12359                        let line_trimmed = line_trimmed
12360                            .strip_suffix(end.as_ref())
12361                            .map(|s| {
12362                                last_line_delimiter = Some(end);
12363                                s.trim_end()
12364                            })
12365                            .unwrap_or(line_trimmed);
12366                        let line_trimmed = line_trimmed
12367                            .strip_prefix(prefix.as_ref())
12368                            .unwrap_or(line_trimmed);
12369                        Ok(line_trimmed)
12370                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12371                        line_trimmed.strip_prefix(prefix).with_context(|| {
12372                            format!("line did not start with prefix {prefix:?}: {line:?}")
12373                        })
12374                    } else {
12375                        line_trimmed
12376                            .strip_prefix(&line_prefix.trim_start())
12377                            .with_context(|| {
12378                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12379                            })
12380                    }
12381                })
12382                .collect::<Result<Vec<_>, _>>()
12383                .log_err()
12384            else {
12385                continue;
12386            };
12387
12388            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12389                buffer
12390                    .language_settings_at(Point::new(start_row, 0), cx)
12391                    .preferred_line_length as usize
12392            });
12393
12394            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12395                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12396            } else {
12397                line_prefix.clone()
12398            };
12399
12400            let wrapped_text = {
12401                let mut wrapped_text = wrap_with_prefix(
12402                    line_prefix,
12403                    subsequent_lines_prefix,
12404                    lines_without_prefixes.join("\n"),
12405                    wrap_column,
12406                    tab_size,
12407                    options.preserve_existing_whitespace,
12408                );
12409
12410                if let Some((indent, delimiter)) = first_line_delimiter {
12411                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12412                }
12413                if let Some(last_line) = last_line_delimiter {
12414                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12415                }
12416
12417                wrapped_text
12418            };
12419
12420            // TODO: should always use char-based diff while still supporting cursor behavior that
12421            // matches vim.
12422            let mut diff_options = DiffOptions::default();
12423            if options.override_language_settings {
12424                diff_options.max_word_diff_len = 0;
12425                diff_options.max_word_diff_line_count = 0;
12426            } else {
12427                diff_options.max_word_diff_len = usize::MAX;
12428                diff_options.max_word_diff_line_count = usize::MAX;
12429            }
12430
12431            for (old_range, new_text) in
12432                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12433            {
12434                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12435                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12436                edits.push((edit_start..edit_end, new_text));
12437            }
12438
12439            rewrapped_row_ranges.push(start_row..=end_row);
12440        }
12441
12442        self.buffer
12443            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12444    }
12445
12446    pub fn cut_common(
12447        &mut self,
12448        cut_no_selection_line: bool,
12449        window: &mut Window,
12450        cx: &mut Context<Self>,
12451    ) -> ClipboardItem {
12452        let mut text = String::new();
12453        let buffer = self.buffer.read(cx).snapshot(cx);
12454        let mut selections = self.selections.all::<Point>(cx);
12455        let mut clipboard_selections = Vec::with_capacity(selections.len());
12456        {
12457            let max_point = buffer.max_point();
12458            let mut is_first = true;
12459            for selection in &mut selections {
12460                let is_entire_line =
12461                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12462                if is_entire_line {
12463                    selection.start = Point::new(selection.start.row, 0);
12464                    if !selection.is_empty() && selection.end.column == 0 {
12465                        selection.end = cmp::min(max_point, selection.end);
12466                    } else {
12467                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12468                    }
12469                    selection.goal = SelectionGoal::None;
12470                }
12471                if is_first {
12472                    is_first = false;
12473                } else {
12474                    text += "\n";
12475                }
12476                let mut len = 0;
12477                for chunk in buffer.text_for_range(selection.start..selection.end) {
12478                    text.push_str(chunk);
12479                    len += chunk.len();
12480                }
12481                clipboard_selections.push(ClipboardSelection {
12482                    len,
12483                    is_entire_line,
12484                    first_line_indent: buffer
12485                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12486                        .len,
12487                });
12488            }
12489        }
12490
12491        self.transact(window, cx, |this, window, cx| {
12492            this.change_selections(Default::default(), window, cx, |s| {
12493                s.select(selections);
12494            });
12495            this.insert("", window, cx);
12496        });
12497        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12498    }
12499
12500    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12501        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12502        let item = self.cut_common(true, window, cx);
12503        cx.write_to_clipboard(item);
12504    }
12505
12506    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12507        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12508        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12509            s.move_with(|snapshot, sel| {
12510                if sel.is_empty() {
12511                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12512                }
12513                if sel.is_empty() {
12514                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12515                }
12516            });
12517        });
12518        let item = self.cut_common(false, window, cx);
12519        cx.set_global(KillRing(item))
12520    }
12521
12522    pub fn kill_ring_yank(
12523        &mut self,
12524        _: &KillRingYank,
12525        window: &mut Window,
12526        cx: &mut Context<Self>,
12527    ) {
12528        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12529        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12530            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12531                (kill_ring.text().to_string(), kill_ring.metadata_json())
12532            } else {
12533                return;
12534            }
12535        } else {
12536            return;
12537        };
12538        self.do_paste(&text, metadata, false, window, cx);
12539    }
12540
12541    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12542        self.do_copy(true, cx);
12543    }
12544
12545    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12546        self.do_copy(false, cx);
12547    }
12548
12549    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12550        let selections = self.selections.all::<Point>(cx);
12551        let buffer = self.buffer.read(cx).read(cx);
12552        let mut text = String::new();
12553
12554        let mut clipboard_selections = Vec::with_capacity(selections.len());
12555        {
12556            let max_point = buffer.max_point();
12557            let mut is_first = true;
12558            for selection in &selections {
12559                let mut start = selection.start;
12560                let mut end = selection.end;
12561                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12562                let mut add_trailing_newline = false;
12563                if is_entire_line {
12564                    start = Point::new(start.row, 0);
12565                    let next_line_start = Point::new(end.row + 1, 0);
12566                    if next_line_start <= max_point {
12567                        end = next_line_start;
12568                    } else {
12569                        // We're on the last line without a trailing newline.
12570                        // Copy to the end of the line and add a newline afterwards.
12571                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12572                        add_trailing_newline = true;
12573                    }
12574                }
12575
12576                let mut trimmed_selections = Vec::new();
12577                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12578                    let row = MultiBufferRow(start.row);
12579                    let first_indent = buffer.indent_size_for_line(row);
12580                    if first_indent.len == 0 || start.column > first_indent.len {
12581                        trimmed_selections.push(start..end);
12582                    } else {
12583                        trimmed_selections.push(
12584                            Point::new(row.0, first_indent.len)
12585                                ..Point::new(row.0, buffer.line_len(row)),
12586                        );
12587                        for row in start.row + 1..=end.row {
12588                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12589                            if row == end.row {
12590                                line_len = end.column;
12591                            }
12592                            if line_len == 0 {
12593                                trimmed_selections
12594                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12595                                continue;
12596                            }
12597                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12598                            if row_indent_size.len >= first_indent.len {
12599                                trimmed_selections.push(
12600                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12601                                );
12602                            } else {
12603                                trimmed_selections.clear();
12604                                trimmed_selections.push(start..end);
12605                                break;
12606                            }
12607                        }
12608                    }
12609                } else {
12610                    trimmed_selections.push(start..end);
12611                }
12612
12613                for trimmed_range in trimmed_selections {
12614                    if is_first {
12615                        is_first = false;
12616                    } else {
12617                        text += "\n";
12618                    }
12619                    let mut len = 0;
12620                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12621                        text.push_str(chunk);
12622                        len += chunk.len();
12623                    }
12624                    if add_trailing_newline {
12625                        text.push('\n');
12626                        len += 1;
12627                    }
12628                    clipboard_selections.push(ClipboardSelection {
12629                        len,
12630                        is_entire_line,
12631                        first_line_indent: buffer
12632                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12633                            .len,
12634                    });
12635                }
12636            }
12637        }
12638
12639        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12640            text,
12641            clipboard_selections,
12642        ));
12643    }
12644
12645    pub fn do_paste(
12646        &mut self,
12647        text: &String,
12648        clipboard_selections: Option<Vec<ClipboardSelection>>,
12649        handle_entire_lines: bool,
12650        window: &mut Window,
12651        cx: &mut Context<Self>,
12652    ) {
12653        if self.read_only(cx) {
12654            return;
12655        }
12656
12657        let clipboard_text = Cow::Borrowed(text.as_str());
12658
12659        self.transact(window, cx, |this, window, cx| {
12660            let had_active_edit_prediction = this.has_active_edit_prediction();
12661            let old_selections = this.selections.all::<usize>(cx);
12662            let cursor_offset = this.selections.last::<usize>(cx).head();
12663
12664            if let Some(mut clipboard_selections) = clipboard_selections {
12665                let all_selections_were_entire_line =
12666                    clipboard_selections.iter().all(|s| s.is_entire_line);
12667                let first_selection_indent_column =
12668                    clipboard_selections.first().map(|s| s.first_line_indent);
12669                if clipboard_selections.len() != old_selections.len() {
12670                    clipboard_selections.drain(..);
12671                }
12672                let mut auto_indent_on_paste = true;
12673
12674                this.buffer.update(cx, |buffer, cx| {
12675                    let snapshot = buffer.read(cx);
12676                    auto_indent_on_paste = snapshot
12677                        .language_settings_at(cursor_offset, cx)
12678                        .auto_indent_on_paste;
12679
12680                    let mut start_offset = 0;
12681                    let mut edits = Vec::new();
12682                    let mut original_indent_columns = Vec::new();
12683                    for (ix, selection) in old_selections.iter().enumerate() {
12684                        let to_insert;
12685                        let entire_line;
12686                        let original_indent_column;
12687                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12688                            let end_offset = start_offset + clipboard_selection.len;
12689                            to_insert = &clipboard_text[start_offset..end_offset];
12690                            entire_line = clipboard_selection.is_entire_line;
12691                            start_offset = end_offset + 1;
12692                            original_indent_column = Some(clipboard_selection.first_line_indent);
12693                        } else {
12694                            to_insert = &*clipboard_text;
12695                            entire_line = all_selections_were_entire_line;
12696                            original_indent_column = first_selection_indent_column
12697                        }
12698
12699                        let (range, to_insert) =
12700                            if selection.is_empty() && handle_entire_lines && entire_line {
12701                                // If the corresponding selection was empty when this slice of the
12702                                // clipboard text was written, then the entire line containing the
12703                                // selection was copied. If this selection is also currently empty,
12704                                // then paste the line before the current line of the buffer.
12705                                let column = selection.start.to_point(&snapshot).column as usize;
12706                                let line_start = selection.start - column;
12707                                (line_start..line_start, Cow::Borrowed(to_insert))
12708                            } else {
12709                                let language = snapshot.language_at(selection.head());
12710                                let range = selection.range();
12711                                if let Some(language) = language
12712                                    && language.name() == "Markdown".into()
12713                                {
12714                                    edit_for_markdown_paste(
12715                                        &snapshot,
12716                                        range,
12717                                        to_insert,
12718                                        url::Url::parse(to_insert).ok(),
12719                                    )
12720                                } else {
12721                                    (range, Cow::Borrowed(to_insert))
12722                                }
12723                            };
12724
12725                        edits.push((range, to_insert));
12726                        original_indent_columns.push(original_indent_column);
12727                    }
12728                    drop(snapshot);
12729
12730                    buffer.edit(
12731                        edits,
12732                        if auto_indent_on_paste {
12733                            Some(AutoindentMode::Block {
12734                                original_indent_columns,
12735                            })
12736                        } else {
12737                            None
12738                        },
12739                        cx,
12740                    );
12741                });
12742
12743                let selections = this.selections.all::<usize>(cx);
12744                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12745            } else {
12746                let url = url::Url::parse(&clipboard_text).ok();
12747
12748                let auto_indent_mode = if !clipboard_text.is_empty() {
12749                    Some(AutoindentMode::Block {
12750                        original_indent_columns: Vec::new(),
12751                    })
12752                } else {
12753                    None
12754                };
12755
12756                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12757                    let snapshot = buffer.snapshot(cx);
12758
12759                    let anchors = old_selections
12760                        .iter()
12761                        .map(|s| {
12762                            let anchor = snapshot.anchor_after(s.head());
12763                            s.map(|_| anchor)
12764                        })
12765                        .collect::<Vec<_>>();
12766
12767                    let mut edits = Vec::new();
12768
12769                    for selection in old_selections.iter() {
12770                        let language = snapshot.language_at(selection.head());
12771                        let range = selection.range();
12772
12773                        let (edit_range, edit_text) = if let Some(language) = language
12774                            && language.name() == "Markdown".into()
12775                        {
12776                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12777                        } else {
12778                            (range, clipboard_text.clone())
12779                        };
12780
12781                        edits.push((edit_range, edit_text));
12782                    }
12783
12784                    drop(snapshot);
12785                    buffer.edit(edits, auto_indent_mode, cx);
12786
12787                    anchors
12788                });
12789
12790                this.change_selections(Default::default(), window, cx, |s| {
12791                    s.select_anchors(selection_anchors);
12792                });
12793            }
12794
12795            let trigger_in_words =
12796                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12797
12798            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12799        });
12800    }
12801
12802    pub fn diff_clipboard_with_selection(
12803        &mut self,
12804        _: &DiffClipboardWithSelection,
12805        window: &mut Window,
12806        cx: &mut Context<Self>,
12807    ) {
12808        let selections = self.selections.all::<usize>(cx);
12809
12810        if selections.is_empty() {
12811            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12812            return;
12813        };
12814
12815        let clipboard_text = match cx.read_from_clipboard() {
12816            Some(item) => match item.entries().first() {
12817                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12818                _ => None,
12819            },
12820            None => None,
12821        };
12822
12823        let Some(clipboard_text) = clipboard_text else {
12824            log::warn!("Clipboard doesn't contain text.");
12825            return;
12826        };
12827
12828        window.dispatch_action(
12829            Box::new(DiffClipboardWithSelectionData {
12830                clipboard_text,
12831                editor: cx.entity(),
12832            }),
12833            cx,
12834        );
12835    }
12836
12837    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12838        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12839        if let Some(item) = cx.read_from_clipboard() {
12840            let entries = item.entries();
12841
12842            match entries.first() {
12843                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12844                // of all the pasted entries.
12845                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12846                    .do_paste(
12847                        clipboard_string.text(),
12848                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12849                        true,
12850                        window,
12851                        cx,
12852                    ),
12853                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12854            }
12855        }
12856    }
12857
12858    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12859        if self.read_only(cx) {
12860            return;
12861        }
12862
12863        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12864
12865        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12866            if let Some((selections, _)) =
12867                self.selection_history.transaction(transaction_id).cloned()
12868            {
12869                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12870                    s.select_anchors(selections.to_vec());
12871                });
12872            } else {
12873                log::error!(
12874                    "No entry in selection_history found for undo. \
12875                     This may correspond to a bug where undo does not update the selection. \
12876                     If this is occurring, please add details to \
12877                     https://github.com/zed-industries/zed/issues/22692"
12878                );
12879            }
12880            self.request_autoscroll(Autoscroll::fit(), cx);
12881            self.unmark_text(window, cx);
12882            self.refresh_edit_prediction(true, false, window, cx);
12883            cx.emit(EditorEvent::Edited { transaction_id });
12884            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12885        }
12886    }
12887
12888    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12889        if self.read_only(cx) {
12890            return;
12891        }
12892
12893        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12894
12895        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12896            if let Some((_, Some(selections))) =
12897                self.selection_history.transaction(transaction_id).cloned()
12898            {
12899                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12900                    s.select_anchors(selections.to_vec());
12901                });
12902            } else {
12903                log::error!(
12904                    "No entry in selection_history found for redo. \
12905                     This may correspond to a bug where undo does not update the selection. \
12906                     If this is occurring, please add details to \
12907                     https://github.com/zed-industries/zed/issues/22692"
12908                );
12909            }
12910            self.request_autoscroll(Autoscroll::fit(), cx);
12911            self.unmark_text(window, cx);
12912            self.refresh_edit_prediction(true, false, window, cx);
12913            cx.emit(EditorEvent::Edited { transaction_id });
12914        }
12915    }
12916
12917    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12918        self.buffer
12919            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12920    }
12921
12922    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12923        self.buffer
12924            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12925    }
12926
12927    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12928        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12929        self.change_selections(Default::default(), window, cx, |s| {
12930            s.move_with(|map, selection| {
12931                let cursor = if selection.is_empty() {
12932                    movement::left(map, selection.start)
12933                } else {
12934                    selection.start
12935                };
12936                selection.collapse_to(cursor, SelectionGoal::None);
12937            });
12938        })
12939    }
12940
12941    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12942        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12943        self.change_selections(Default::default(), window, cx, |s| {
12944            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12945        })
12946    }
12947
12948    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12949        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12950        self.change_selections(Default::default(), window, cx, |s| {
12951            s.move_with(|map, selection| {
12952                let cursor = if selection.is_empty() {
12953                    movement::right(map, selection.end)
12954                } else {
12955                    selection.end
12956                };
12957                selection.collapse_to(cursor, SelectionGoal::None)
12958            });
12959        })
12960    }
12961
12962    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12963        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12964        self.change_selections(Default::default(), window, cx, |s| {
12965            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12966        });
12967    }
12968
12969    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12970        if self.take_rename(true, window, cx).is_some() {
12971            return;
12972        }
12973
12974        if self.mode.is_single_line() {
12975            cx.propagate();
12976            return;
12977        }
12978
12979        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12980
12981        let text_layout_details = &self.text_layout_details(window);
12982        let selection_count = self.selections.count();
12983        let first_selection = self.selections.first_anchor();
12984
12985        self.change_selections(Default::default(), window, cx, |s| {
12986            s.move_with(|map, selection| {
12987                if !selection.is_empty() {
12988                    selection.goal = SelectionGoal::None;
12989                }
12990                let (cursor, goal) = movement::up(
12991                    map,
12992                    selection.start,
12993                    selection.goal,
12994                    false,
12995                    text_layout_details,
12996                );
12997                selection.collapse_to(cursor, goal);
12998            });
12999        });
13000
13001        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13002        {
13003            cx.propagate();
13004        }
13005    }
13006
13007    pub fn move_up_by_lines(
13008        &mut self,
13009        action: &MoveUpByLines,
13010        window: &mut Window,
13011        cx: &mut Context<Self>,
13012    ) {
13013        if self.take_rename(true, window, cx).is_some() {
13014            return;
13015        }
13016
13017        if self.mode.is_single_line() {
13018            cx.propagate();
13019            return;
13020        }
13021
13022        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13023
13024        let text_layout_details = &self.text_layout_details(window);
13025
13026        self.change_selections(Default::default(), window, cx, |s| {
13027            s.move_with(|map, selection| {
13028                if !selection.is_empty() {
13029                    selection.goal = SelectionGoal::None;
13030                }
13031                let (cursor, goal) = movement::up_by_rows(
13032                    map,
13033                    selection.start,
13034                    action.lines,
13035                    selection.goal,
13036                    false,
13037                    text_layout_details,
13038                );
13039                selection.collapse_to(cursor, goal);
13040            });
13041        })
13042    }
13043
13044    pub fn move_down_by_lines(
13045        &mut self,
13046        action: &MoveDownByLines,
13047        window: &mut Window,
13048        cx: &mut Context<Self>,
13049    ) {
13050        if self.take_rename(true, window, cx).is_some() {
13051            return;
13052        }
13053
13054        if self.mode.is_single_line() {
13055            cx.propagate();
13056            return;
13057        }
13058
13059        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13060
13061        let text_layout_details = &self.text_layout_details(window);
13062
13063        self.change_selections(Default::default(), window, cx, |s| {
13064            s.move_with(|map, selection| {
13065                if !selection.is_empty() {
13066                    selection.goal = SelectionGoal::None;
13067                }
13068                let (cursor, goal) = movement::down_by_rows(
13069                    map,
13070                    selection.start,
13071                    action.lines,
13072                    selection.goal,
13073                    false,
13074                    text_layout_details,
13075                );
13076                selection.collapse_to(cursor, goal);
13077            });
13078        })
13079    }
13080
13081    pub fn select_down_by_lines(
13082        &mut self,
13083        action: &SelectDownByLines,
13084        window: &mut Window,
13085        cx: &mut Context<Self>,
13086    ) {
13087        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13088        let text_layout_details = &self.text_layout_details(window);
13089        self.change_selections(Default::default(), window, cx, |s| {
13090            s.move_heads_with(|map, head, goal| {
13091                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13092            })
13093        })
13094    }
13095
13096    pub fn select_up_by_lines(
13097        &mut self,
13098        action: &SelectUpByLines,
13099        window: &mut Window,
13100        cx: &mut Context<Self>,
13101    ) {
13102        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13103        let text_layout_details = &self.text_layout_details(window);
13104        self.change_selections(Default::default(), window, cx, |s| {
13105            s.move_heads_with(|map, head, goal| {
13106                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13107            })
13108        })
13109    }
13110
13111    pub fn select_page_up(
13112        &mut self,
13113        _: &SelectPageUp,
13114        window: &mut Window,
13115        cx: &mut Context<Self>,
13116    ) {
13117        let Some(row_count) = self.visible_row_count() else {
13118            return;
13119        };
13120
13121        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13122
13123        let text_layout_details = &self.text_layout_details(window);
13124
13125        self.change_selections(Default::default(), window, cx, |s| {
13126            s.move_heads_with(|map, head, goal| {
13127                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13128            })
13129        })
13130    }
13131
13132    pub fn move_page_up(
13133        &mut self,
13134        action: &MovePageUp,
13135        window: &mut Window,
13136        cx: &mut Context<Self>,
13137    ) {
13138        if self.take_rename(true, window, cx).is_some() {
13139            return;
13140        }
13141
13142        if self
13143            .context_menu
13144            .borrow_mut()
13145            .as_mut()
13146            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13147            .unwrap_or(false)
13148        {
13149            return;
13150        }
13151
13152        if matches!(self.mode, EditorMode::SingleLine) {
13153            cx.propagate();
13154            return;
13155        }
13156
13157        let Some(row_count) = self.visible_row_count() else {
13158            return;
13159        };
13160
13161        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13162
13163        let effects = if action.center_cursor {
13164            SelectionEffects::scroll(Autoscroll::center())
13165        } else {
13166            SelectionEffects::default()
13167        };
13168
13169        let text_layout_details = &self.text_layout_details(window);
13170
13171        self.change_selections(effects, window, cx, |s| {
13172            s.move_with(|map, selection| {
13173                if !selection.is_empty() {
13174                    selection.goal = SelectionGoal::None;
13175                }
13176                let (cursor, goal) = movement::up_by_rows(
13177                    map,
13178                    selection.end,
13179                    row_count,
13180                    selection.goal,
13181                    false,
13182                    text_layout_details,
13183                );
13184                selection.collapse_to(cursor, goal);
13185            });
13186        });
13187    }
13188
13189    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13190        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13191        let text_layout_details = &self.text_layout_details(window);
13192        self.change_selections(Default::default(), window, cx, |s| {
13193            s.move_heads_with(|map, head, goal| {
13194                movement::up(map, head, goal, false, text_layout_details)
13195            })
13196        })
13197    }
13198
13199    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13200        self.take_rename(true, window, cx);
13201
13202        if self.mode.is_single_line() {
13203            cx.propagate();
13204            return;
13205        }
13206
13207        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13208
13209        let text_layout_details = &self.text_layout_details(window);
13210        let selection_count = self.selections.count();
13211        let first_selection = self.selections.first_anchor();
13212
13213        self.change_selections(Default::default(), window, cx, |s| {
13214            s.move_with(|map, selection| {
13215                if !selection.is_empty() {
13216                    selection.goal = SelectionGoal::None;
13217                }
13218                let (cursor, goal) = movement::down(
13219                    map,
13220                    selection.end,
13221                    selection.goal,
13222                    false,
13223                    text_layout_details,
13224                );
13225                selection.collapse_to(cursor, goal);
13226            });
13227        });
13228
13229        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13230        {
13231            cx.propagate();
13232        }
13233    }
13234
13235    pub fn select_page_down(
13236        &mut self,
13237        _: &SelectPageDown,
13238        window: &mut Window,
13239        cx: &mut Context<Self>,
13240    ) {
13241        let Some(row_count) = self.visible_row_count() else {
13242            return;
13243        };
13244
13245        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13246
13247        let text_layout_details = &self.text_layout_details(window);
13248
13249        self.change_selections(Default::default(), window, cx, |s| {
13250            s.move_heads_with(|map, head, goal| {
13251                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13252            })
13253        })
13254    }
13255
13256    pub fn move_page_down(
13257        &mut self,
13258        action: &MovePageDown,
13259        window: &mut Window,
13260        cx: &mut Context<Self>,
13261    ) {
13262        if self.take_rename(true, window, cx).is_some() {
13263            return;
13264        }
13265
13266        if self
13267            .context_menu
13268            .borrow_mut()
13269            .as_mut()
13270            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13271            .unwrap_or(false)
13272        {
13273            return;
13274        }
13275
13276        if matches!(self.mode, EditorMode::SingleLine) {
13277            cx.propagate();
13278            return;
13279        }
13280
13281        let Some(row_count) = self.visible_row_count() else {
13282            return;
13283        };
13284
13285        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13286
13287        let effects = if action.center_cursor {
13288            SelectionEffects::scroll(Autoscroll::center())
13289        } else {
13290            SelectionEffects::default()
13291        };
13292
13293        let text_layout_details = &self.text_layout_details(window);
13294        self.change_selections(effects, window, cx, |s| {
13295            s.move_with(|map, selection| {
13296                if !selection.is_empty() {
13297                    selection.goal = SelectionGoal::None;
13298                }
13299                let (cursor, goal) = movement::down_by_rows(
13300                    map,
13301                    selection.end,
13302                    row_count,
13303                    selection.goal,
13304                    false,
13305                    text_layout_details,
13306                );
13307                selection.collapse_to(cursor, goal);
13308            });
13309        });
13310    }
13311
13312    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13313        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13314        let text_layout_details = &self.text_layout_details(window);
13315        self.change_selections(Default::default(), window, cx, |s| {
13316            s.move_heads_with(|map, head, goal| {
13317                movement::down(map, head, goal, false, text_layout_details)
13318            })
13319        });
13320    }
13321
13322    pub fn context_menu_first(
13323        &mut self,
13324        _: &ContextMenuFirst,
13325        window: &mut Window,
13326        cx: &mut Context<Self>,
13327    ) {
13328        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13329            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13330        }
13331    }
13332
13333    pub fn context_menu_prev(
13334        &mut self,
13335        _: &ContextMenuPrevious,
13336        window: &mut Window,
13337        cx: &mut Context<Self>,
13338    ) {
13339        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13340            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13341        }
13342    }
13343
13344    pub fn context_menu_next(
13345        &mut self,
13346        _: &ContextMenuNext,
13347        window: &mut Window,
13348        cx: &mut Context<Self>,
13349    ) {
13350        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13351            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13352        }
13353    }
13354
13355    pub fn context_menu_last(
13356        &mut self,
13357        _: &ContextMenuLast,
13358        window: &mut Window,
13359        cx: &mut Context<Self>,
13360    ) {
13361        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13362            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13363        }
13364    }
13365
13366    pub fn signature_help_prev(
13367        &mut self,
13368        _: &SignatureHelpPrevious,
13369        _: &mut Window,
13370        cx: &mut Context<Self>,
13371    ) {
13372        if let Some(popover) = self.signature_help_state.popover_mut() {
13373            if popover.current_signature == 0 {
13374                popover.current_signature = popover.signatures.len() - 1;
13375            } else {
13376                popover.current_signature -= 1;
13377            }
13378            cx.notify();
13379        }
13380    }
13381
13382    pub fn signature_help_next(
13383        &mut self,
13384        _: &SignatureHelpNext,
13385        _: &mut Window,
13386        cx: &mut Context<Self>,
13387    ) {
13388        if let Some(popover) = self.signature_help_state.popover_mut() {
13389            if popover.current_signature + 1 == popover.signatures.len() {
13390                popover.current_signature = 0;
13391            } else {
13392                popover.current_signature += 1;
13393            }
13394            cx.notify();
13395        }
13396    }
13397
13398    pub fn move_to_previous_word_start(
13399        &mut self,
13400        _: &MoveToPreviousWordStart,
13401        window: &mut Window,
13402        cx: &mut Context<Self>,
13403    ) {
13404        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13405        self.change_selections(Default::default(), window, cx, |s| {
13406            s.move_cursors_with(|map, head, _| {
13407                (
13408                    movement::previous_word_start(map, head),
13409                    SelectionGoal::None,
13410                )
13411            });
13412        })
13413    }
13414
13415    pub fn move_to_previous_subword_start(
13416        &mut self,
13417        _: &MoveToPreviousSubwordStart,
13418        window: &mut Window,
13419        cx: &mut Context<Self>,
13420    ) {
13421        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13422        self.change_selections(Default::default(), window, cx, |s| {
13423            s.move_cursors_with(|map, head, _| {
13424                (
13425                    movement::previous_subword_start(map, head),
13426                    SelectionGoal::None,
13427                )
13428            });
13429        })
13430    }
13431
13432    pub fn select_to_previous_word_start(
13433        &mut self,
13434        _: &SelectToPreviousWordStart,
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                (
13442                    movement::previous_word_start(map, head),
13443                    SelectionGoal::None,
13444                )
13445            });
13446        })
13447    }
13448
13449    pub fn select_to_previous_subword_start(
13450        &mut self,
13451        _: &SelectToPreviousSubwordStart,
13452        window: &mut Window,
13453        cx: &mut Context<Self>,
13454    ) {
13455        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13456        self.change_selections(Default::default(), window, cx, |s| {
13457            s.move_heads_with(|map, head, _| {
13458                (
13459                    movement::previous_subword_start(map, head),
13460                    SelectionGoal::None,
13461                )
13462            });
13463        })
13464    }
13465
13466    pub fn delete_to_previous_word_start(
13467        &mut self,
13468        action: &DeleteToPreviousWordStart,
13469        window: &mut Window,
13470        cx: &mut Context<Self>,
13471    ) {
13472        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13473        self.transact(window, cx, |this, window, cx| {
13474            this.select_autoclose_pair(window, cx);
13475            this.change_selections(Default::default(), window, cx, |s| {
13476                s.move_with(|map, selection| {
13477                    if selection.is_empty() {
13478                        let mut cursor = if action.ignore_newlines {
13479                            movement::previous_word_start(map, selection.head())
13480                        } else {
13481                            movement::previous_word_start_or_newline(map, selection.head())
13482                        };
13483                        cursor = movement::adjust_greedy_deletion(
13484                            map,
13485                            selection.head(),
13486                            cursor,
13487                            action.ignore_brackets,
13488                        );
13489                        selection.set_head(cursor, SelectionGoal::None);
13490                    }
13491                });
13492            });
13493            this.insert("", window, cx);
13494        });
13495    }
13496
13497    pub fn delete_to_previous_subword_start(
13498        &mut self,
13499        _: &DeleteToPreviousSubwordStart,
13500        window: &mut Window,
13501        cx: &mut Context<Self>,
13502    ) {
13503        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13504        self.transact(window, cx, |this, window, cx| {
13505            this.select_autoclose_pair(window, cx);
13506            this.change_selections(Default::default(), window, cx, |s| {
13507                s.move_with(|map, selection| {
13508                    if selection.is_empty() {
13509                        let mut cursor = movement::previous_subword_start(map, selection.head());
13510                        cursor =
13511                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13512                        selection.set_head(cursor, SelectionGoal::None);
13513                    }
13514                });
13515            });
13516            this.insert("", window, cx);
13517        });
13518    }
13519
13520    pub fn move_to_next_word_end(
13521        &mut self,
13522        _: &MoveToNextWordEnd,
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_cursors_with(|map, head, _| {
13529                (movement::next_word_end(map, head), SelectionGoal::None)
13530            });
13531        })
13532    }
13533
13534    pub fn move_to_next_subword_end(
13535        &mut self,
13536        _: &MoveToNextSubwordEnd,
13537        window: &mut Window,
13538        cx: &mut Context<Self>,
13539    ) {
13540        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13541        self.change_selections(Default::default(), window, cx, |s| {
13542            s.move_cursors_with(|map, head, _| {
13543                (movement::next_subword_end(map, head), SelectionGoal::None)
13544            });
13545        })
13546    }
13547
13548    pub fn select_to_next_word_end(
13549        &mut self,
13550        _: &SelectToNextWordEnd,
13551        window: &mut Window,
13552        cx: &mut Context<Self>,
13553    ) {
13554        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13555        self.change_selections(Default::default(), window, cx, |s| {
13556            s.move_heads_with(|map, head, _| {
13557                (movement::next_word_end(map, head), SelectionGoal::None)
13558            });
13559        })
13560    }
13561
13562    pub fn select_to_next_subword_end(
13563        &mut self,
13564        _: &SelectToNextSubwordEnd,
13565        window: &mut Window,
13566        cx: &mut Context<Self>,
13567    ) {
13568        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13569        self.change_selections(Default::default(), window, cx, |s| {
13570            s.move_heads_with(|map, head, _| {
13571                (movement::next_subword_end(map, head), SelectionGoal::None)
13572            });
13573        })
13574    }
13575
13576    pub fn delete_to_next_word_end(
13577        &mut self,
13578        action: &DeleteToNextWordEnd,
13579        window: &mut Window,
13580        cx: &mut Context<Self>,
13581    ) {
13582        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13583        self.transact(window, cx, |this, window, cx| {
13584            this.change_selections(Default::default(), window, cx, |s| {
13585                s.move_with(|map, selection| {
13586                    if selection.is_empty() {
13587                        let mut cursor = if action.ignore_newlines {
13588                            movement::next_word_end(map, selection.head())
13589                        } else {
13590                            movement::next_word_end_or_newline(map, selection.head())
13591                        };
13592                        cursor = movement::adjust_greedy_deletion(
13593                            map,
13594                            selection.head(),
13595                            cursor,
13596                            action.ignore_brackets,
13597                        );
13598                        selection.set_head(cursor, SelectionGoal::None);
13599                    }
13600                });
13601            });
13602            this.insert("", window, cx);
13603        });
13604    }
13605
13606    pub fn delete_to_next_subword_end(
13607        &mut self,
13608        _: &DeleteToNextSubwordEnd,
13609        window: &mut Window,
13610        cx: &mut Context<Self>,
13611    ) {
13612        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13613        self.transact(window, cx, |this, window, cx| {
13614            this.change_selections(Default::default(), window, cx, |s| {
13615                s.move_with(|map, selection| {
13616                    if selection.is_empty() {
13617                        let mut cursor = movement::next_subword_end(map, selection.head());
13618                        cursor =
13619                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13620                        selection.set_head(cursor, SelectionGoal::None);
13621                    }
13622                });
13623            });
13624            this.insert("", window, cx);
13625        });
13626    }
13627
13628    pub fn move_to_beginning_of_line(
13629        &mut self,
13630        action: &MoveToBeginningOfLine,
13631        window: &mut Window,
13632        cx: &mut Context<Self>,
13633    ) {
13634        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13635        self.change_selections(Default::default(), window, cx, |s| {
13636            s.move_cursors_with(|map, head, _| {
13637                (
13638                    movement::indented_line_beginning(
13639                        map,
13640                        head,
13641                        action.stop_at_soft_wraps,
13642                        action.stop_at_indent,
13643                    ),
13644                    SelectionGoal::None,
13645                )
13646            });
13647        })
13648    }
13649
13650    pub fn select_to_beginning_of_line(
13651        &mut self,
13652        action: &SelectToBeginningOfLine,
13653        window: &mut Window,
13654        cx: &mut Context<Self>,
13655    ) {
13656        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13657        self.change_selections(Default::default(), window, cx, |s| {
13658            s.move_heads_with(|map, head, _| {
13659                (
13660                    movement::indented_line_beginning(
13661                        map,
13662                        head,
13663                        action.stop_at_soft_wraps,
13664                        action.stop_at_indent,
13665                    ),
13666                    SelectionGoal::None,
13667                )
13668            });
13669        });
13670    }
13671
13672    pub fn delete_to_beginning_of_line(
13673        &mut self,
13674        action: &DeleteToBeginningOfLine,
13675        window: &mut Window,
13676        cx: &mut Context<Self>,
13677    ) {
13678        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13679        self.transact(window, cx, |this, window, cx| {
13680            this.change_selections(Default::default(), window, cx, |s| {
13681                s.move_with(|_, selection| {
13682                    selection.reversed = true;
13683                });
13684            });
13685
13686            this.select_to_beginning_of_line(
13687                &SelectToBeginningOfLine {
13688                    stop_at_soft_wraps: false,
13689                    stop_at_indent: action.stop_at_indent,
13690                },
13691                window,
13692                cx,
13693            );
13694            this.backspace(&Backspace, window, cx);
13695        });
13696    }
13697
13698    pub fn move_to_end_of_line(
13699        &mut self,
13700        action: &MoveToEndOfLine,
13701        window: &mut Window,
13702        cx: &mut Context<Self>,
13703    ) {
13704        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13705        self.change_selections(Default::default(), window, cx, |s| {
13706            s.move_cursors_with(|map, head, _| {
13707                (
13708                    movement::line_end(map, head, action.stop_at_soft_wraps),
13709                    SelectionGoal::None,
13710                )
13711            });
13712        })
13713    }
13714
13715    pub fn select_to_end_of_line(
13716        &mut self,
13717        action: &SelectToEndOfLine,
13718        window: &mut Window,
13719        cx: &mut Context<Self>,
13720    ) {
13721        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13722        self.change_selections(Default::default(), window, cx, |s| {
13723            s.move_heads_with(|map, head, _| {
13724                (
13725                    movement::line_end(map, head, action.stop_at_soft_wraps),
13726                    SelectionGoal::None,
13727                )
13728            });
13729        })
13730    }
13731
13732    pub fn delete_to_end_of_line(
13733        &mut self,
13734        _: &DeleteToEndOfLine,
13735        window: &mut Window,
13736        cx: &mut Context<Self>,
13737    ) {
13738        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13739        self.transact(window, cx, |this, window, cx| {
13740            this.select_to_end_of_line(
13741                &SelectToEndOfLine {
13742                    stop_at_soft_wraps: false,
13743                },
13744                window,
13745                cx,
13746            );
13747            this.delete(&Delete, window, cx);
13748        });
13749    }
13750
13751    pub fn cut_to_end_of_line(
13752        &mut self,
13753        action: &CutToEndOfLine,
13754        window: &mut Window,
13755        cx: &mut Context<Self>,
13756    ) {
13757        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13758        self.transact(window, cx, |this, window, cx| {
13759            this.select_to_end_of_line(
13760                &SelectToEndOfLine {
13761                    stop_at_soft_wraps: false,
13762                },
13763                window,
13764                cx,
13765            );
13766            if !action.stop_at_newlines {
13767                this.change_selections(Default::default(), window, cx, |s| {
13768                    s.move_with(|_, sel| {
13769                        if sel.is_empty() {
13770                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13771                        }
13772                    });
13773                });
13774            }
13775            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13776            let item = this.cut_common(false, window, cx);
13777            cx.write_to_clipboard(item);
13778        });
13779    }
13780
13781    pub fn move_to_start_of_paragraph(
13782        &mut self,
13783        _: &MoveToStartOfParagraph,
13784        window: &mut Window,
13785        cx: &mut Context<Self>,
13786    ) {
13787        if matches!(self.mode, EditorMode::SingleLine) {
13788            cx.propagate();
13789            return;
13790        }
13791        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13792        self.change_selections(Default::default(), window, cx, |s| {
13793            s.move_with(|map, selection| {
13794                selection.collapse_to(
13795                    movement::start_of_paragraph(map, selection.head(), 1),
13796                    SelectionGoal::None,
13797                )
13798            });
13799        })
13800    }
13801
13802    pub fn move_to_end_of_paragraph(
13803        &mut self,
13804        _: &MoveToEndOfParagraph,
13805        window: &mut Window,
13806        cx: &mut Context<Self>,
13807    ) {
13808        if matches!(self.mode, EditorMode::SingleLine) {
13809            cx.propagate();
13810            return;
13811        }
13812        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13813        self.change_selections(Default::default(), window, cx, |s| {
13814            s.move_with(|map, selection| {
13815                selection.collapse_to(
13816                    movement::end_of_paragraph(map, selection.head(), 1),
13817                    SelectionGoal::None,
13818                )
13819            });
13820        })
13821    }
13822
13823    pub fn select_to_start_of_paragraph(
13824        &mut self,
13825        _: &SelectToStartOfParagraph,
13826        window: &mut Window,
13827        cx: &mut Context<Self>,
13828    ) {
13829        if matches!(self.mode, EditorMode::SingleLine) {
13830            cx.propagate();
13831            return;
13832        }
13833        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13834        self.change_selections(Default::default(), window, cx, |s| {
13835            s.move_heads_with(|map, head, _| {
13836                (
13837                    movement::start_of_paragraph(map, head, 1),
13838                    SelectionGoal::None,
13839                )
13840            });
13841        })
13842    }
13843
13844    pub fn select_to_end_of_paragraph(
13845        &mut self,
13846        _: &SelectToEndOfParagraph,
13847        window: &mut Window,
13848        cx: &mut Context<Self>,
13849    ) {
13850        if matches!(self.mode, EditorMode::SingleLine) {
13851            cx.propagate();
13852            return;
13853        }
13854        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13855        self.change_selections(Default::default(), window, cx, |s| {
13856            s.move_heads_with(|map, head, _| {
13857                (
13858                    movement::end_of_paragraph(map, head, 1),
13859                    SelectionGoal::None,
13860                )
13861            });
13862        })
13863    }
13864
13865    pub fn move_to_start_of_excerpt(
13866        &mut self,
13867        _: &MoveToStartOfExcerpt,
13868        window: &mut Window,
13869        cx: &mut Context<Self>,
13870    ) {
13871        if matches!(self.mode, EditorMode::SingleLine) {
13872            cx.propagate();
13873            return;
13874        }
13875        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13876        self.change_selections(Default::default(), window, cx, |s| {
13877            s.move_with(|map, selection| {
13878                selection.collapse_to(
13879                    movement::start_of_excerpt(
13880                        map,
13881                        selection.head(),
13882                        workspace::searchable::Direction::Prev,
13883                    ),
13884                    SelectionGoal::None,
13885                )
13886            });
13887        })
13888    }
13889
13890    pub fn move_to_start_of_next_excerpt(
13891        &mut self,
13892        _: &MoveToStartOfNextExcerpt,
13893        window: &mut Window,
13894        cx: &mut Context<Self>,
13895    ) {
13896        if matches!(self.mode, EditorMode::SingleLine) {
13897            cx.propagate();
13898            return;
13899        }
13900
13901        self.change_selections(Default::default(), window, cx, |s| {
13902            s.move_with(|map, selection| {
13903                selection.collapse_to(
13904                    movement::start_of_excerpt(
13905                        map,
13906                        selection.head(),
13907                        workspace::searchable::Direction::Next,
13908                    ),
13909                    SelectionGoal::None,
13910                )
13911            });
13912        })
13913    }
13914
13915    pub fn move_to_end_of_excerpt(
13916        &mut self,
13917        _: &MoveToEndOfExcerpt,
13918        window: &mut Window,
13919        cx: &mut Context<Self>,
13920    ) {
13921        if matches!(self.mode, EditorMode::SingleLine) {
13922            cx.propagate();
13923            return;
13924        }
13925        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13926        self.change_selections(Default::default(), window, cx, |s| {
13927            s.move_with(|map, selection| {
13928                selection.collapse_to(
13929                    movement::end_of_excerpt(
13930                        map,
13931                        selection.head(),
13932                        workspace::searchable::Direction::Next,
13933                    ),
13934                    SelectionGoal::None,
13935                )
13936            });
13937        })
13938    }
13939
13940    pub fn move_to_end_of_previous_excerpt(
13941        &mut self,
13942        _: &MoveToEndOfPreviousExcerpt,
13943        window: &mut Window,
13944        cx: &mut Context<Self>,
13945    ) {
13946        if matches!(self.mode, EditorMode::SingleLine) {
13947            cx.propagate();
13948            return;
13949        }
13950        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13951        self.change_selections(Default::default(), window, cx, |s| {
13952            s.move_with(|map, selection| {
13953                selection.collapse_to(
13954                    movement::end_of_excerpt(
13955                        map,
13956                        selection.head(),
13957                        workspace::searchable::Direction::Prev,
13958                    ),
13959                    SelectionGoal::None,
13960                )
13961            });
13962        })
13963    }
13964
13965    pub fn select_to_start_of_excerpt(
13966        &mut self,
13967        _: &SelectToStartOfExcerpt,
13968        window: &mut Window,
13969        cx: &mut Context<Self>,
13970    ) {
13971        if matches!(self.mode, EditorMode::SingleLine) {
13972            cx.propagate();
13973            return;
13974        }
13975        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13976        self.change_selections(Default::default(), window, cx, |s| {
13977            s.move_heads_with(|map, head, _| {
13978                (
13979                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13980                    SelectionGoal::None,
13981                )
13982            });
13983        })
13984    }
13985
13986    pub fn select_to_start_of_next_excerpt(
13987        &mut self,
13988        _: &SelectToStartOfNextExcerpt,
13989        window: &mut Window,
13990        cx: &mut Context<Self>,
13991    ) {
13992        if matches!(self.mode, EditorMode::SingleLine) {
13993            cx.propagate();
13994            return;
13995        }
13996        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13997        self.change_selections(Default::default(), window, cx, |s| {
13998            s.move_heads_with(|map, head, _| {
13999                (
14000                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14001                    SelectionGoal::None,
14002                )
14003            });
14004        })
14005    }
14006
14007    pub fn select_to_end_of_excerpt(
14008        &mut self,
14009        _: &SelectToEndOfExcerpt,
14010        window: &mut Window,
14011        cx: &mut Context<Self>,
14012    ) {
14013        if matches!(self.mode, EditorMode::SingleLine) {
14014            cx.propagate();
14015            return;
14016        }
14017        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14018        self.change_selections(Default::default(), window, cx, |s| {
14019            s.move_heads_with(|map, head, _| {
14020                (
14021                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14022                    SelectionGoal::None,
14023                )
14024            });
14025        })
14026    }
14027
14028    pub fn select_to_end_of_previous_excerpt(
14029        &mut self,
14030        _: &SelectToEndOfPreviousExcerpt,
14031        window: &mut Window,
14032        cx: &mut Context<Self>,
14033    ) {
14034        if matches!(self.mode, EditorMode::SingleLine) {
14035            cx.propagate();
14036            return;
14037        }
14038        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14039        self.change_selections(Default::default(), window, cx, |s| {
14040            s.move_heads_with(|map, head, _| {
14041                (
14042                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14043                    SelectionGoal::None,
14044                )
14045            });
14046        })
14047    }
14048
14049    pub fn move_to_beginning(
14050        &mut self,
14051        _: &MoveToBeginning,
14052        window: &mut Window,
14053        cx: &mut Context<Self>,
14054    ) {
14055        if matches!(self.mode, EditorMode::SingleLine) {
14056            cx.propagate();
14057            return;
14058        }
14059        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14060        self.change_selections(Default::default(), window, cx, |s| {
14061            s.select_ranges(vec![0..0]);
14062        });
14063    }
14064
14065    pub fn select_to_beginning(
14066        &mut self,
14067        _: &SelectToBeginning,
14068        window: &mut Window,
14069        cx: &mut Context<Self>,
14070    ) {
14071        let mut selection = self.selections.last::<Point>(cx);
14072        selection.set_head(Point::zero(), SelectionGoal::None);
14073        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14074        self.change_selections(Default::default(), window, cx, |s| {
14075            s.select(vec![selection]);
14076        });
14077    }
14078
14079    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14080        if matches!(self.mode, EditorMode::SingleLine) {
14081            cx.propagate();
14082            return;
14083        }
14084        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14085        let cursor = self.buffer.read(cx).read(cx).len();
14086        self.change_selections(Default::default(), window, cx, |s| {
14087            s.select_ranges(vec![cursor..cursor])
14088        });
14089    }
14090
14091    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14092        self.nav_history = nav_history;
14093    }
14094
14095    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14096        self.nav_history.as_ref()
14097    }
14098
14099    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14100        self.push_to_nav_history(
14101            self.selections.newest_anchor().head(),
14102            None,
14103            false,
14104            true,
14105            cx,
14106        );
14107    }
14108
14109    fn push_to_nav_history(
14110        &mut self,
14111        cursor_anchor: Anchor,
14112        new_position: Option<Point>,
14113        is_deactivate: bool,
14114        always: bool,
14115        cx: &mut Context<Self>,
14116    ) {
14117        if let Some(nav_history) = self.nav_history.as_mut() {
14118            let buffer = self.buffer.read(cx).read(cx);
14119            let cursor_position = cursor_anchor.to_point(&buffer);
14120            let scroll_state = self.scroll_manager.anchor();
14121            let scroll_top_row = scroll_state.top_row(&buffer);
14122            drop(buffer);
14123
14124            if let Some(new_position) = new_position {
14125                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14126                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14127                    return;
14128                }
14129            }
14130
14131            nav_history.push(
14132                Some(NavigationData {
14133                    cursor_anchor,
14134                    cursor_position,
14135                    scroll_anchor: scroll_state,
14136                    scroll_top_row,
14137                }),
14138                cx,
14139            );
14140            cx.emit(EditorEvent::PushedToNavHistory {
14141                anchor: cursor_anchor,
14142                is_deactivate,
14143            })
14144        }
14145    }
14146
14147    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14148        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14149        let buffer = self.buffer.read(cx).snapshot(cx);
14150        let mut selection = self.selections.first::<usize>(cx);
14151        selection.set_head(buffer.len(), SelectionGoal::None);
14152        self.change_selections(Default::default(), window, cx, |s| {
14153            s.select(vec![selection]);
14154        });
14155    }
14156
14157    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14158        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14159        let end = self.buffer.read(cx).read(cx).len();
14160        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14161            s.select_ranges(vec![0..end]);
14162        });
14163    }
14164
14165    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14166        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14167        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14168        let mut selections = self.selections.all::<Point>(cx);
14169        let max_point = display_map.buffer_snapshot().max_point();
14170        for selection in &mut selections {
14171            let rows = selection.spanned_rows(true, &display_map);
14172            selection.start = Point::new(rows.start.0, 0);
14173            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14174            selection.reversed = false;
14175        }
14176        self.change_selections(Default::default(), window, cx, |s| {
14177            s.select(selections);
14178        });
14179    }
14180
14181    pub fn split_selection_into_lines(
14182        &mut self,
14183        action: &SplitSelectionIntoLines,
14184        window: &mut Window,
14185        cx: &mut Context<Self>,
14186    ) {
14187        let selections = self
14188            .selections
14189            .all::<Point>(cx)
14190            .into_iter()
14191            .map(|selection| selection.start..selection.end)
14192            .collect::<Vec<_>>();
14193        self.unfold_ranges(&selections, true, true, cx);
14194
14195        let mut new_selection_ranges = Vec::new();
14196        {
14197            let buffer = self.buffer.read(cx).read(cx);
14198            for selection in selections {
14199                for row in selection.start.row..selection.end.row {
14200                    let line_start = Point::new(row, 0);
14201                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14202
14203                    if action.keep_selections {
14204                        // Keep the selection range for each line
14205                        let selection_start = if row == selection.start.row {
14206                            selection.start
14207                        } else {
14208                            line_start
14209                        };
14210                        new_selection_ranges.push(selection_start..line_end);
14211                    } else {
14212                        // Collapse to cursor at end of line
14213                        new_selection_ranges.push(line_end..line_end);
14214                    }
14215                }
14216
14217                let is_multiline_selection = selection.start.row != selection.end.row;
14218                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14219                // so this action feels more ergonomic when paired with other selection operations
14220                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14221                if !should_skip_last {
14222                    if action.keep_selections {
14223                        if is_multiline_selection {
14224                            let line_start = Point::new(selection.end.row, 0);
14225                            new_selection_ranges.push(line_start..selection.end);
14226                        } else {
14227                            new_selection_ranges.push(selection.start..selection.end);
14228                        }
14229                    } else {
14230                        new_selection_ranges.push(selection.end..selection.end);
14231                    }
14232                }
14233            }
14234        }
14235        self.change_selections(Default::default(), window, cx, |s| {
14236            s.select_ranges(new_selection_ranges);
14237        });
14238    }
14239
14240    pub fn add_selection_above(
14241        &mut self,
14242        _: &AddSelectionAbove,
14243        window: &mut Window,
14244        cx: &mut Context<Self>,
14245    ) {
14246        self.add_selection(true, window, cx);
14247    }
14248
14249    pub fn add_selection_below(
14250        &mut self,
14251        _: &AddSelectionBelow,
14252        window: &mut Window,
14253        cx: &mut Context<Self>,
14254    ) {
14255        self.add_selection(false, window, cx);
14256    }
14257
14258    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14259        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14260
14261        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14262        let all_selections = self.selections.all::<Point>(cx);
14263        let text_layout_details = self.text_layout_details(window);
14264
14265        let (mut columnar_selections, new_selections_to_columnarize) = {
14266            if let Some(state) = self.add_selections_state.as_ref() {
14267                let columnar_selection_ids: HashSet<_> = state
14268                    .groups
14269                    .iter()
14270                    .flat_map(|group| group.stack.iter())
14271                    .copied()
14272                    .collect();
14273
14274                all_selections
14275                    .into_iter()
14276                    .partition(|s| columnar_selection_ids.contains(&s.id))
14277            } else {
14278                (Vec::new(), all_selections)
14279            }
14280        };
14281
14282        let mut state = self
14283            .add_selections_state
14284            .take()
14285            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14286
14287        for selection in new_selections_to_columnarize {
14288            let range = selection.display_range(&display_map).sorted();
14289            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14290            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14291            let positions = start_x.min(end_x)..start_x.max(end_x);
14292            let mut stack = Vec::new();
14293            for row in range.start.row().0..=range.end.row().0 {
14294                if let Some(selection) = self.selections.build_columnar_selection(
14295                    &display_map,
14296                    DisplayRow(row),
14297                    &positions,
14298                    selection.reversed,
14299                    &text_layout_details,
14300                ) {
14301                    stack.push(selection.id);
14302                    columnar_selections.push(selection);
14303                }
14304            }
14305            if !stack.is_empty() {
14306                if above {
14307                    stack.reverse();
14308                }
14309                state.groups.push(AddSelectionsGroup { above, stack });
14310            }
14311        }
14312
14313        let mut final_selections = Vec::new();
14314        let end_row = if above {
14315            DisplayRow(0)
14316        } else {
14317            display_map.max_point().row()
14318        };
14319
14320        let mut last_added_item_per_group = HashMap::default();
14321        for group in state.groups.iter_mut() {
14322            if let Some(last_id) = group.stack.last() {
14323                last_added_item_per_group.insert(*last_id, group);
14324            }
14325        }
14326
14327        for selection in columnar_selections {
14328            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14329                if above == group.above {
14330                    let range = selection.display_range(&display_map).sorted();
14331                    debug_assert_eq!(range.start.row(), range.end.row());
14332                    let mut row = range.start.row();
14333                    let positions =
14334                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14335                            Pixels::from(start)..Pixels::from(end)
14336                        } else {
14337                            let start_x =
14338                                display_map.x_for_display_point(range.start, &text_layout_details);
14339                            let end_x =
14340                                display_map.x_for_display_point(range.end, &text_layout_details);
14341                            start_x.min(end_x)..start_x.max(end_x)
14342                        };
14343
14344                    let mut maybe_new_selection = None;
14345                    while row != end_row {
14346                        if above {
14347                            row.0 -= 1;
14348                        } else {
14349                            row.0 += 1;
14350                        }
14351                        if let Some(new_selection) = self.selections.build_columnar_selection(
14352                            &display_map,
14353                            row,
14354                            &positions,
14355                            selection.reversed,
14356                            &text_layout_details,
14357                        ) {
14358                            maybe_new_selection = Some(new_selection);
14359                            break;
14360                        }
14361                    }
14362
14363                    if let Some(new_selection) = maybe_new_selection {
14364                        group.stack.push(new_selection.id);
14365                        if above {
14366                            final_selections.push(new_selection);
14367                            final_selections.push(selection);
14368                        } else {
14369                            final_selections.push(selection);
14370                            final_selections.push(new_selection);
14371                        }
14372                    } else {
14373                        final_selections.push(selection);
14374                    }
14375                } else {
14376                    group.stack.pop();
14377                }
14378            } else {
14379                final_selections.push(selection);
14380            }
14381        }
14382
14383        self.change_selections(Default::default(), window, cx, |s| {
14384            s.select(final_selections);
14385        });
14386
14387        let final_selection_ids: HashSet<_> = self
14388            .selections
14389            .all::<Point>(cx)
14390            .iter()
14391            .map(|s| s.id)
14392            .collect();
14393        state.groups.retain_mut(|group| {
14394            // selections might get merged above so we remove invalid items from stacks
14395            group.stack.retain(|id| final_selection_ids.contains(id));
14396
14397            // single selection in stack can be treated as initial state
14398            group.stack.len() > 1
14399        });
14400
14401        if !state.groups.is_empty() {
14402            self.add_selections_state = Some(state);
14403        }
14404    }
14405
14406    fn select_match_ranges(
14407        &mut self,
14408        range: Range<usize>,
14409        reversed: bool,
14410        replace_newest: bool,
14411        auto_scroll: Option<Autoscroll>,
14412        window: &mut Window,
14413        cx: &mut Context<Editor>,
14414    ) {
14415        self.unfold_ranges(
14416            std::slice::from_ref(&range),
14417            false,
14418            auto_scroll.is_some(),
14419            cx,
14420        );
14421        let effects = if let Some(scroll) = auto_scroll {
14422            SelectionEffects::scroll(scroll)
14423        } else {
14424            SelectionEffects::no_scroll()
14425        };
14426        self.change_selections(effects, window, cx, |s| {
14427            if replace_newest {
14428                s.delete(s.newest_anchor().id);
14429            }
14430            if reversed {
14431                s.insert_range(range.end..range.start);
14432            } else {
14433                s.insert_range(range);
14434            }
14435        });
14436    }
14437
14438    pub fn select_next_match_internal(
14439        &mut self,
14440        display_map: &DisplaySnapshot,
14441        replace_newest: bool,
14442        autoscroll: Option<Autoscroll>,
14443        window: &mut Window,
14444        cx: &mut Context<Self>,
14445    ) -> Result<()> {
14446        let buffer = display_map.buffer_snapshot();
14447        let mut selections = self.selections.all::<usize>(cx);
14448        if let Some(mut select_next_state) = self.select_next_state.take() {
14449            let query = &select_next_state.query;
14450            if !select_next_state.done {
14451                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14452                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14453                let mut next_selected_range = None;
14454
14455                // Collect and sort selection ranges for efficient overlap checking
14456                let mut selection_ranges: Vec<_> = selections.iter().map(|s| s.range()).collect();
14457                selection_ranges.sort_by_key(|r| r.start);
14458
14459                let bytes_after_last_selection =
14460                    buffer.bytes_in_range(last_selection.end..buffer.len());
14461                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14462                let query_matches = query
14463                    .stream_find_iter(bytes_after_last_selection)
14464                    .map(|result| (last_selection.end, result))
14465                    .chain(
14466                        query
14467                            .stream_find_iter(bytes_before_first_selection)
14468                            .map(|result| (0, result)),
14469                    );
14470
14471                for (start_offset, query_match) in query_matches {
14472                    let query_match = query_match.unwrap(); // can only fail due to I/O
14473                    let offset_range =
14474                        start_offset + query_match.start()..start_offset + query_match.end();
14475
14476                    if !select_next_state.wordwise
14477                        || (!buffer.is_inside_word(offset_range.start, None)
14478                            && !buffer.is_inside_word(offset_range.end, None))
14479                    {
14480                        // Use binary search to check for overlap (O(log n))
14481                        let overlaps = selection_ranges
14482                            .binary_search_by(|range| {
14483                                if range.end <= offset_range.start {
14484                                    std::cmp::Ordering::Less
14485                                } else if range.start >= offset_range.end {
14486                                    std::cmp::Ordering::Greater
14487                                } else {
14488                                    std::cmp::Ordering::Equal
14489                                }
14490                            })
14491                            .is_ok();
14492
14493                        if !overlaps {
14494                            next_selected_range = Some(offset_range);
14495                            break;
14496                        }
14497                    }
14498                }
14499
14500                if let Some(next_selected_range) = next_selected_range {
14501                    self.select_match_ranges(
14502                        next_selected_range,
14503                        last_selection.reversed,
14504                        replace_newest,
14505                        autoscroll,
14506                        window,
14507                        cx,
14508                    );
14509                } else {
14510                    select_next_state.done = true;
14511                }
14512            }
14513
14514            self.select_next_state = Some(select_next_state);
14515        } else {
14516            let mut only_carets = true;
14517            let mut same_text_selected = true;
14518            let mut selected_text = None;
14519
14520            let mut selections_iter = selections.iter().peekable();
14521            while let Some(selection) = selections_iter.next() {
14522                if selection.start != selection.end {
14523                    only_carets = false;
14524                }
14525
14526                if same_text_selected {
14527                    if selected_text.is_none() {
14528                        selected_text =
14529                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14530                    }
14531
14532                    if let Some(next_selection) = selections_iter.peek() {
14533                        if next_selection.range().len() == selection.range().len() {
14534                            let next_selected_text = buffer
14535                                .text_for_range(next_selection.range())
14536                                .collect::<String>();
14537                            if Some(next_selected_text) != selected_text {
14538                                same_text_selected = false;
14539                                selected_text = None;
14540                            }
14541                        } else {
14542                            same_text_selected = false;
14543                            selected_text = None;
14544                        }
14545                    }
14546                }
14547            }
14548
14549            if only_carets {
14550                for selection in &mut selections {
14551                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14552                    selection.start = word_range.start;
14553                    selection.end = word_range.end;
14554                    selection.goal = SelectionGoal::None;
14555                    selection.reversed = false;
14556                    self.select_match_ranges(
14557                        selection.start..selection.end,
14558                        selection.reversed,
14559                        replace_newest,
14560                        autoscroll,
14561                        window,
14562                        cx,
14563                    );
14564                }
14565
14566                if selections.len() == 1 {
14567                    let selection = selections
14568                        .last()
14569                        .expect("ensured that there's only one selection");
14570                    let query = buffer
14571                        .text_for_range(selection.start..selection.end)
14572                        .collect::<String>();
14573                    let is_empty = query.is_empty();
14574                    let select_state = SelectNextState {
14575                        query: AhoCorasick::new(&[query])?,
14576                        wordwise: true,
14577                        done: is_empty,
14578                    };
14579                    self.select_next_state = Some(select_state);
14580                } else {
14581                    self.select_next_state = None;
14582                }
14583            } else if let Some(selected_text) = selected_text {
14584                self.select_next_state = Some(SelectNextState {
14585                    query: AhoCorasick::new(&[selected_text])?,
14586                    wordwise: false,
14587                    done: false,
14588                });
14589                self.select_next_match_internal(
14590                    display_map,
14591                    replace_newest,
14592                    autoscroll,
14593                    window,
14594                    cx,
14595                )?;
14596            }
14597        }
14598        Ok(())
14599    }
14600
14601    pub fn select_all_matches(
14602        &mut self,
14603        _action: &SelectAllMatches,
14604        window: &mut Window,
14605        cx: &mut Context<Self>,
14606    ) -> Result<()> {
14607        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14608
14609        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14610
14611        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14612        let Some(select_next_state) = self.select_next_state.as_mut() else {
14613            return Ok(());
14614        };
14615        if select_next_state.done {
14616            return Ok(());
14617        }
14618
14619        let mut new_selections = Vec::new();
14620
14621        let reversed = self.selections.oldest::<usize>(cx).reversed;
14622        let buffer = display_map.buffer_snapshot();
14623        let query_matches = select_next_state
14624            .query
14625            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14626
14627        for query_match in query_matches.into_iter() {
14628            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14629            let offset_range = if reversed {
14630                query_match.end()..query_match.start()
14631            } else {
14632                query_match.start()..query_match.end()
14633            };
14634
14635            if !select_next_state.wordwise
14636                || (!buffer.is_inside_word(offset_range.start, None)
14637                    && !buffer.is_inside_word(offset_range.end, None))
14638            {
14639                new_selections.push(offset_range.start..offset_range.end);
14640            }
14641        }
14642
14643        select_next_state.done = true;
14644
14645        if new_selections.is_empty() {
14646            log::error!("bug: new_selections is empty in select_all_matches");
14647            return Ok(());
14648        }
14649
14650        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14651        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14652            selections.select_ranges(new_selections)
14653        });
14654
14655        Ok(())
14656    }
14657
14658    pub fn select_next(
14659        &mut self,
14660        action: &SelectNext,
14661        window: &mut Window,
14662        cx: &mut Context<Self>,
14663    ) -> Result<()> {
14664        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14665        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14666        self.select_next_match_internal(
14667            &display_map,
14668            action.replace_newest,
14669            Some(Autoscroll::newest()),
14670            window,
14671            cx,
14672        )?;
14673        Ok(())
14674    }
14675
14676    pub fn select_previous(
14677        &mut self,
14678        action: &SelectPrevious,
14679        window: &mut Window,
14680        cx: &mut Context<Self>,
14681    ) -> Result<()> {
14682        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14683        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14684        let buffer = display_map.buffer_snapshot();
14685        let mut selections = self.selections.all::<usize>(cx);
14686        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14687            let query = &select_prev_state.query;
14688            if !select_prev_state.done {
14689                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14690                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14691                let mut next_selected_range = None;
14692                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14693                let bytes_before_last_selection =
14694                    buffer.reversed_bytes_in_range(0..last_selection.start);
14695                let bytes_after_first_selection =
14696                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14697                let query_matches = query
14698                    .stream_find_iter(bytes_before_last_selection)
14699                    .map(|result| (last_selection.start, result))
14700                    .chain(
14701                        query
14702                            .stream_find_iter(bytes_after_first_selection)
14703                            .map(|result| (buffer.len(), result)),
14704                    );
14705                for (end_offset, query_match) in query_matches {
14706                    let query_match = query_match.unwrap(); // can only fail due to I/O
14707                    let offset_range =
14708                        end_offset - query_match.end()..end_offset - query_match.start();
14709
14710                    if !select_prev_state.wordwise
14711                        || (!buffer.is_inside_word(offset_range.start, None)
14712                            && !buffer.is_inside_word(offset_range.end, None))
14713                    {
14714                        next_selected_range = Some(offset_range);
14715                        break;
14716                    }
14717                }
14718
14719                if let Some(next_selected_range) = next_selected_range {
14720                    self.select_match_ranges(
14721                        next_selected_range,
14722                        last_selection.reversed,
14723                        action.replace_newest,
14724                        Some(Autoscroll::newest()),
14725                        window,
14726                        cx,
14727                    );
14728                } else {
14729                    select_prev_state.done = true;
14730                }
14731            }
14732
14733            self.select_prev_state = Some(select_prev_state);
14734        } else {
14735            let mut only_carets = true;
14736            let mut same_text_selected = true;
14737            let mut selected_text = None;
14738
14739            let mut selections_iter = selections.iter().peekable();
14740            while let Some(selection) = selections_iter.next() {
14741                if selection.start != selection.end {
14742                    only_carets = false;
14743                }
14744
14745                if same_text_selected {
14746                    if selected_text.is_none() {
14747                        selected_text =
14748                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14749                    }
14750
14751                    if let Some(next_selection) = selections_iter.peek() {
14752                        if next_selection.range().len() == selection.range().len() {
14753                            let next_selected_text = buffer
14754                                .text_for_range(next_selection.range())
14755                                .collect::<String>();
14756                            if Some(next_selected_text) != selected_text {
14757                                same_text_selected = false;
14758                                selected_text = None;
14759                            }
14760                        } else {
14761                            same_text_selected = false;
14762                            selected_text = None;
14763                        }
14764                    }
14765                }
14766            }
14767
14768            if only_carets {
14769                for selection in &mut selections {
14770                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14771                    selection.start = word_range.start;
14772                    selection.end = word_range.end;
14773                    selection.goal = SelectionGoal::None;
14774                    selection.reversed = false;
14775                    self.select_match_ranges(
14776                        selection.start..selection.end,
14777                        selection.reversed,
14778                        action.replace_newest,
14779                        Some(Autoscroll::newest()),
14780                        window,
14781                        cx,
14782                    );
14783                }
14784                if selections.len() == 1 {
14785                    let selection = selections
14786                        .last()
14787                        .expect("ensured that there's only one selection");
14788                    let query = buffer
14789                        .text_for_range(selection.start..selection.end)
14790                        .collect::<String>();
14791                    let is_empty = query.is_empty();
14792                    let select_state = SelectNextState {
14793                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14794                        wordwise: true,
14795                        done: is_empty,
14796                    };
14797                    self.select_prev_state = Some(select_state);
14798                } else {
14799                    self.select_prev_state = None;
14800                }
14801            } else if let Some(selected_text) = selected_text {
14802                self.select_prev_state = Some(SelectNextState {
14803                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14804                    wordwise: false,
14805                    done: false,
14806                });
14807                self.select_previous(action, window, cx)?;
14808            }
14809        }
14810        Ok(())
14811    }
14812
14813    pub fn find_next_match(
14814        &mut self,
14815        _: &FindNextMatch,
14816        window: &mut Window,
14817        cx: &mut Context<Self>,
14818    ) -> Result<()> {
14819        let selections = self.selections.disjoint_anchors_arc();
14820        match selections.first() {
14821            Some(first) if selections.len() >= 2 => {
14822                self.change_selections(Default::default(), window, cx, |s| {
14823                    s.select_ranges([first.range()]);
14824                });
14825            }
14826            _ => self.select_next(
14827                &SelectNext {
14828                    replace_newest: true,
14829                },
14830                window,
14831                cx,
14832            )?,
14833        }
14834        Ok(())
14835    }
14836
14837    pub fn find_previous_match(
14838        &mut self,
14839        _: &FindPreviousMatch,
14840        window: &mut Window,
14841        cx: &mut Context<Self>,
14842    ) -> Result<()> {
14843        let selections = self.selections.disjoint_anchors_arc();
14844        match selections.last() {
14845            Some(last) if selections.len() >= 2 => {
14846                self.change_selections(Default::default(), window, cx, |s| {
14847                    s.select_ranges([last.range()]);
14848                });
14849            }
14850            _ => self.select_previous(
14851                &SelectPrevious {
14852                    replace_newest: true,
14853                },
14854                window,
14855                cx,
14856            )?,
14857        }
14858        Ok(())
14859    }
14860
14861    pub fn toggle_comments(
14862        &mut self,
14863        action: &ToggleComments,
14864        window: &mut Window,
14865        cx: &mut Context<Self>,
14866    ) {
14867        if self.read_only(cx) {
14868            return;
14869        }
14870        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14871        let text_layout_details = &self.text_layout_details(window);
14872        self.transact(window, cx, |this, window, cx| {
14873            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14874            let mut edits = Vec::new();
14875            let mut selection_edit_ranges = Vec::new();
14876            let mut last_toggled_row = None;
14877            let snapshot = this.buffer.read(cx).read(cx);
14878            let empty_str: Arc<str> = Arc::default();
14879            let mut suffixes_inserted = Vec::new();
14880            let ignore_indent = action.ignore_indent;
14881
14882            fn comment_prefix_range(
14883                snapshot: &MultiBufferSnapshot,
14884                row: MultiBufferRow,
14885                comment_prefix: &str,
14886                comment_prefix_whitespace: &str,
14887                ignore_indent: bool,
14888            ) -> Range<Point> {
14889                let indent_size = if ignore_indent {
14890                    0
14891                } else {
14892                    snapshot.indent_size_for_line(row).len
14893                };
14894
14895                let start = Point::new(row.0, indent_size);
14896
14897                let mut line_bytes = snapshot
14898                    .bytes_in_range(start..snapshot.max_point())
14899                    .flatten()
14900                    .copied();
14901
14902                // If this line currently begins with the line comment prefix, then record
14903                // the range containing the prefix.
14904                if line_bytes
14905                    .by_ref()
14906                    .take(comment_prefix.len())
14907                    .eq(comment_prefix.bytes())
14908                {
14909                    // Include any whitespace that matches the comment prefix.
14910                    let matching_whitespace_len = line_bytes
14911                        .zip(comment_prefix_whitespace.bytes())
14912                        .take_while(|(a, b)| a == b)
14913                        .count() as u32;
14914                    let end = Point::new(
14915                        start.row,
14916                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14917                    );
14918                    start..end
14919                } else {
14920                    start..start
14921                }
14922            }
14923
14924            fn comment_suffix_range(
14925                snapshot: &MultiBufferSnapshot,
14926                row: MultiBufferRow,
14927                comment_suffix: &str,
14928                comment_suffix_has_leading_space: bool,
14929            ) -> Range<Point> {
14930                let end = Point::new(row.0, snapshot.line_len(row));
14931                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14932
14933                let mut line_end_bytes = snapshot
14934                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14935                    .flatten()
14936                    .copied();
14937
14938                let leading_space_len = if suffix_start_column > 0
14939                    && line_end_bytes.next() == Some(b' ')
14940                    && comment_suffix_has_leading_space
14941                {
14942                    1
14943                } else {
14944                    0
14945                };
14946
14947                // If this line currently begins with the line comment prefix, then record
14948                // the range containing the prefix.
14949                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14950                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14951                    start..end
14952                } else {
14953                    end..end
14954                }
14955            }
14956
14957            // TODO: Handle selections that cross excerpts
14958            for selection in &mut selections {
14959                let start_column = snapshot
14960                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14961                    .len;
14962                let language = if let Some(language) =
14963                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14964                {
14965                    language
14966                } else {
14967                    continue;
14968                };
14969
14970                selection_edit_ranges.clear();
14971
14972                // If multiple selections contain a given row, avoid processing that
14973                // row more than once.
14974                let mut start_row = MultiBufferRow(selection.start.row);
14975                if last_toggled_row == Some(start_row) {
14976                    start_row = start_row.next_row();
14977                }
14978                let end_row =
14979                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14980                        MultiBufferRow(selection.end.row - 1)
14981                    } else {
14982                        MultiBufferRow(selection.end.row)
14983                    };
14984                last_toggled_row = Some(end_row);
14985
14986                if start_row > end_row {
14987                    continue;
14988                }
14989
14990                // If the language has line comments, toggle those.
14991                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14992
14993                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14994                if ignore_indent {
14995                    full_comment_prefixes = full_comment_prefixes
14996                        .into_iter()
14997                        .map(|s| Arc::from(s.trim_end()))
14998                        .collect();
14999                }
15000
15001                if !full_comment_prefixes.is_empty() {
15002                    let first_prefix = full_comment_prefixes
15003                        .first()
15004                        .expect("prefixes is non-empty");
15005                    let prefix_trimmed_lengths = full_comment_prefixes
15006                        .iter()
15007                        .map(|p| p.trim_end_matches(' ').len())
15008                        .collect::<SmallVec<[usize; 4]>>();
15009
15010                    let mut all_selection_lines_are_comments = true;
15011
15012                    for row in start_row.0..=end_row.0 {
15013                        let row = MultiBufferRow(row);
15014                        if start_row < end_row && snapshot.is_line_blank(row) {
15015                            continue;
15016                        }
15017
15018                        let prefix_range = full_comment_prefixes
15019                            .iter()
15020                            .zip(prefix_trimmed_lengths.iter().copied())
15021                            .map(|(prefix, trimmed_prefix_len)| {
15022                                comment_prefix_range(
15023                                    snapshot.deref(),
15024                                    row,
15025                                    &prefix[..trimmed_prefix_len],
15026                                    &prefix[trimmed_prefix_len..],
15027                                    ignore_indent,
15028                                )
15029                            })
15030                            .max_by_key(|range| range.end.column - range.start.column)
15031                            .expect("prefixes is non-empty");
15032
15033                        if prefix_range.is_empty() {
15034                            all_selection_lines_are_comments = false;
15035                        }
15036
15037                        selection_edit_ranges.push(prefix_range);
15038                    }
15039
15040                    if all_selection_lines_are_comments {
15041                        edits.extend(
15042                            selection_edit_ranges
15043                                .iter()
15044                                .cloned()
15045                                .map(|range| (range, empty_str.clone())),
15046                        );
15047                    } else {
15048                        let min_column = selection_edit_ranges
15049                            .iter()
15050                            .map(|range| range.start.column)
15051                            .min()
15052                            .unwrap_or(0);
15053                        edits.extend(selection_edit_ranges.iter().map(|range| {
15054                            let position = Point::new(range.start.row, min_column);
15055                            (position..position, first_prefix.clone())
15056                        }));
15057                    }
15058                } else if let Some(BlockCommentConfig {
15059                    start: full_comment_prefix,
15060                    end: comment_suffix,
15061                    ..
15062                }) = language.block_comment()
15063                {
15064                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15065                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15066                    let prefix_range = comment_prefix_range(
15067                        snapshot.deref(),
15068                        start_row,
15069                        comment_prefix,
15070                        comment_prefix_whitespace,
15071                        ignore_indent,
15072                    );
15073                    let suffix_range = comment_suffix_range(
15074                        snapshot.deref(),
15075                        end_row,
15076                        comment_suffix.trim_start_matches(' '),
15077                        comment_suffix.starts_with(' '),
15078                    );
15079
15080                    if prefix_range.is_empty() || suffix_range.is_empty() {
15081                        edits.push((
15082                            prefix_range.start..prefix_range.start,
15083                            full_comment_prefix.clone(),
15084                        ));
15085                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15086                        suffixes_inserted.push((end_row, comment_suffix.len()));
15087                    } else {
15088                        edits.push((prefix_range, empty_str.clone()));
15089                        edits.push((suffix_range, empty_str.clone()));
15090                    }
15091                } else {
15092                    continue;
15093                }
15094            }
15095
15096            drop(snapshot);
15097            this.buffer.update(cx, |buffer, cx| {
15098                buffer.edit(edits, None, cx);
15099            });
15100
15101            // Adjust selections so that they end before any comment suffixes that
15102            // were inserted.
15103            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15104            let mut selections = this.selections.all::<Point>(cx);
15105            let snapshot = this.buffer.read(cx).read(cx);
15106            for selection in &mut selections {
15107                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15108                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15109                        Ordering::Less => {
15110                            suffixes_inserted.next();
15111                            continue;
15112                        }
15113                        Ordering::Greater => break,
15114                        Ordering::Equal => {
15115                            if selection.end.column == snapshot.line_len(row) {
15116                                if selection.is_empty() {
15117                                    selection.start.column -= suffix_len as u32;
15118                                }
15119                                selection.end.column -= suffix_len as u32;
15120                            }
15121                            break;
15122                        }
15123                    }
15124                }
15125            }
15126
15127            drop(snapshot);
15128            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15129
15130            let selections = this.selections.all::<Point>(cx);
15131            let selections_on_single_row = selections.windows(2).all(|selections| {
15132                selections[0].start.row == selections[1].start.row
15133                    && selections[0].end.row == selections[1].end.row
15134                    && selections[0].start.row == selections[0].end.row
15135            });
15136            let selections_selecting = selections
15137                .iter()
15138                .any(|selection| selection.start != selection.end);
15139            let advance_downwards = action.advance_downwards
15140                && selections_on_single_row
15141                && !selections_selecting
15142                && !matches!(this.mode, EditorMode::SingleLine);
15143
15144            if advance_downwards {
15145                let snapshot = this.buffer.read(cx).snapshot(cx);
15146
15147                this.change_selections(Default::default(), window, cx, |s| {
15148                    s.move_cursors_with(|display_snapshot, display_point, _| {
15149                        let mut point = display_point.to_point(display_snapshot);
15150                        point.row += 1;
15151                        point = snapshot.clip_point(point, Bias::Left);
15152                        let display_point = point.to_display_point(display_snapshot);
15153                        let goal = SelectionGoal::HorizontalPosition(
15154                            display_snapshot
15155                                .x_for_display_point(display_point, text_layout_details)
15156                                .into(),
15157                        );
15158                        (display_point, goal)
15159                    })
15160                });
15161            }
15162        });
15163    }
15164
15165    pub fn select_enclosing_symbol(
15166        &mut self,
15167        _: &SelectEnclosingSymbol,
15168        window: &mut Window,
15169        cx: &mut Context<Self>,
15170    ) {
15171        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15172
15173        let buffer = self.buffer.read(cx).snapshot(cx);
15174        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
15175
15176        fn update_selection(
15177            selection: &Selection<usize>,
15178            buffer_snap: &MultiBufferSnapshot,
15179        ) -> Option<Selection<usize>> {
15180            let cursor = selection.head();
15181            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15182            for symbol in symbols.iter().rev() {
15183                let start = symbol.range.start.to_offset(buffer_snap);
15184                let end = symbol.range.end.to_offset(buffer_snap);
15185                let new_range = start..end;
15186                if start < selection.start || end > selection.end {
15187                    return Some(Selection {
15188                        id: selection.id,
15189                        start: new_range.start,
15190                        end: new_range.end,
15191                        goal: SelectionGoal::None,
15192                        reversed: selection.reversed,
15193                    });
15194                }
15195            }
15196            None
15197        }
15198
15199        let mut selected_larger_symbol = false;
15200        let new_selections = old_selections
15201            .iter()
15202            .map(|selection| match update_selection(selection, &buffer) {
15203                Some(new_selection) => {
15204                    if new_selection.range() != selection.range() {
15205                        selected_larger_symbol = true;
15206                    }
15207                    new_selection
15208                }
15209                None => selection.clone(),
15210            })
15211            .collect::<Vec<_>>();
15212
15213        if selected_larger_symbol {
15214            self.change_selections(Default::default(), window, cx, |s| {
15215                s.select(new_selections);
15216            });
15217        }
15218    }
15219
15220    pub fn select_larger_syntax_node(
15221        &mut self,
15222        _: &SelectLargerSyntaxNode,
15223        window: &mut Window,
15224        cx: &mut Context<Self>,
15225    ) {
15226        let Some(visible_row_count) = self.visible_row_count() else {
15227            return;
15228        };
15229        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15230        if old_selections.is_empty() {
15231            return;
15232        }
15233
15234        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15235
15236        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15237        let buffer = self.buffer.read(cx).snapshot(cx);
15238
15239        let mut selected_larger_node = false;
15240        let mut new_selections = old_selections
15241            .iter()
15242            .map(|selection| {
15243                let old_range = selection.start..selection.end;
15244
15245                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15246                    // manually select word at selection
15247                    if ["string_content", "inline"].contains(&node.kind()) {
15248                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15249                        // ignore if word is already selected
15250                        if !word_range.is_empty() && old_range != word_range {
15251                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15252                            // only select word if start and end point belongs to same word
15253                            if word_range == last_word_range {
15254                                selected_larger_node = true;
15255                                return Selection {
15256                                    id: selection.id,
15257                                    start: word_range.start,
15258                                    end: word_range.end,
15259                                    goal: SelectionGoal::None,
15260                                    reversed: selection.reversed,
15261                                };
15262                            }
15263                        }
15264                    }
15265                }
15266
15267                let mut new_range = old_range.clone();
15268                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15269                    new_range = range;
15270                    if !node.is_named() {
15271                        continue;
15272                    }
15273                    if !display_map.intersects_fold(new_range.start)
15274                        && !display_map.intersects_fold(new_range.end)
15275                    {
15276                        break;
15277                    }
15278                }
15279
15280                selected_larger_node |= new_range != old_range;
15281                Selection {
15282                    id: selection.id,
15283                    start: new_range.start,
15284                    end: new_range.end,
15285                    goal: SelectionGoal::None,
15286                    reversed: selection.reversed,
15287                }
15288            })
15289            .collect::<Vec<_>>();
15290
15291        if !selected_larger_node {
15292            return; // don't put this call in the history
15293        }
15294
15295        // scroll based on transformation done to the last selection created by the user
15296        let (last_old, last_new) = old_selections
15297            .last()
15298            .zip(new_selections.last().cloned())
15299            .expect("old_selections isn't empty");
15300
15301        // revert selection
15302        let is_selection_reversed = {
15303            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15304            new_selections.last_mut().expect("checked above").reversed =
15305                should_newest_selection_be_reversed;
15306            should_newest_selection_be_reversed
15307        };
15308
15309        if selected_larger_node {
15310            self.select_syntax_node_history.disable_clearing = true;
15311            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15312                s.select(new_selections.clone());
15313            });
15314            self.select_syntax_node_history.disable_clearing = false;
15315        }
15316
15317        let start_row = last_new.start.to_display_point(&display_map).row().0;
15318        let end_row = last_new.end.to_display_point(&display_map).row().0;
15319        let selection_height = end_row - start_row + 1;
15320        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15321
15322        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15323        let scroll_behavior = if fits_on_the_screen {
15324            self.request_autoscroll(Autoscroll::fit(), cx);
15325            SelectSyntaxNodeScrollBehavior::FitSelection
15326        } else if is_selection_reversed {
15327            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15328            SelectSyntaxNodeScrollBehavior::CursorTop
15329        } else {
15330            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15331            SelectSyntaxNodeScrollBehavior::CursorBottom
15332        };
15333
15334        self.select_syntax_node_history.push((
15335            old_selections,
15336            scroll_behavior,
15337            is_selection_reversed,
15338        ));
15339    }
15340
15341    pub fn select_smaller_syntax_node(
15342        &mut self,
15343        _: &SelectSmallerSyntaxNode,
15344        window: &mut Window,
15345        cx: &mut Context<Self>,
15346    ) {
15347        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15348
15349        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15350            self.select_syntax_node_history.pop()
15351        {
15352            if let Some(selection) = selections.last_mut() {
15353                selection.reversed = is_selection_reversed;
15354            }
15355
15356            self.select_syntax_node_history.disable_clearing = true;
15357            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15358                s.select(selections.to_vec());
15359            });
15360            self.select_syntax_node_history.disable_clearing = false;
15361
15362            match scroll_behavior {
15363                SelectSyntaxNodeScrollBehavior::CursorTop => {
15364                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15365                }
15366                SelectSyntaxNodeScrollBehavior::FitSelection => {
15367                    self.request_autoscroll(Autoscroll::fit(), cx);
15368                }
15369                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15370                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15371                }
15372            }
15373        }
15374    }
15375
15376    pub fn unwrap_syntax_node(
15377        &mut self,
15378        _: &UnwrapSyntaxNode,
15379        window: &mut Window,
15380        cx: &mut Context<Self>,
15381    ) {
15382        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15383
15384        let buffer = self.buffer.read(cx).snapshot(cx);
15385        let selections = self
15386            .selections
15387            .all::<usize>(cx)
15388            .into_iter()
15389            // subtracting the offset requires sorting
15390            .sorted_by_key(|i| i.start);
15391
15392        let full_edits = selections
15393            .into_iter()
15394            .filter_map(|selection| {
15395                let child = if selection.is_empty()
15396                    && let Some((_, ancestor_range)) =
15397                        buffer.syntax_ancestor(selection.start..selection.end)
15398                {
15399                    ancestor_range
15400                } else {
15401                    selection.range()
15402                };
15403
15404                let mut parent = child.clone();
15405                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15406                    parent = ancestor_range;
15407                    if parent.start < child.start || parent.end > child.end {
15408                        break;
15409                    }
15410                }
15411
15412                if parent == child {
15413                    return None;
15414                }
15415                let text = buffer.text_for_range(child).collect::<String>();
15416                Some((selection.id, parent, text))
15417            })
15418            .collect::<Vec<_>>();
15419        if full_edits.is_empty() {
15420            return;
15421        }
15422
15423        self.transact(window, cx, |this, window, cx| {
15424            this.buffer.update(cx, |buffer, cx| {
15425                buffer.edit(
15426                    full_edits
15427                        .iter()
15428                        .map(|(_, p, t)| (p.clone(), t.clone()))
15429                        .collect::<Vec<_>>(),
15430                    None,
15431                    cx,
15432                );
15433            });
15434            this.change_selections(Default::default(), window, cx, |s| {
15435                let mut offset = 0;
15436                let mut selections = vec![];
15437                for (id, parent, text) in full_edits {
15438                    let start = parent.start - offset;
15439                    offset += parent.len() - text.len();
15440                    selections.push(Selection {
15441                        id,
15442                        start,
15443                        end: start + text.len(),
15444                        reversed: false,
15445                        goal: Default::default(),
15446                    });
15447                }
15448                s.select(selections);
15449            });
15450        });
15451    }
15452
15453    pub fn select_next_syntax_node(
15454        &mut self,
15455        _: &SelectNextSyntaxNode,
15456        window: &mut Window,
15457        cx: &mut Context<Self>,
15458    ) {
15459        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15460        if old_selections.is_empty() {
15461            return;
15462        }
15463
15464        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15465
15466        let buffer = self.buffer.read(cx).snapshot(cx);
15467        let mut selected_sibling = false;
15468
15469        let new_selections = old_selections
15470            .iter()
15471            .map(|selection| {
15472                let old_range = selection.start..selection.end;
15473
15474                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15475                    let new_range = node.byte_range();
15476                    selected_sibling = true;
15477                    Selection {
15478                        id: selection.id,
15479                        start: new_range.start,
15480                        end: new_range.end,
15481                        goal: SelectionGoal::None,
15482                        reversed: selection.reversed,
15483                    }
15484                } else {
15485                    selection.clone()
15486                }
15487            })
15488            .collect::<Vec<_>>();
15489
15490        if selected_sibling {
15491            self.change_selections(
15492                SelectionEffects::scroll(Autoscroll::fit()),
15493                window,
15494                cx,
15495                |s| {
15496                    s.select(new_selections);
15497                },
15498            );
15499        }
15500    }
15501
15502    pub fn select_prev_syntax_node(
15503        &mut self,
15504        _: &SelectPreviousSyntaxNode,
15505        window: &mut Window,
15506        cx: &mut Context<Self>,
15507    ) {
15508        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15509        if old_selections.is_empty() {
15510            return;
15511        }
15512
15513        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15514
15515        let buffer = self.buffer.read(cx).snapshot(cx);
15516        let mut selected_sibling = false;
15517
15518        let new_selections = old_selections
15519            .iter()
15520            .map(|selection| {
15521                let old_range = selection.start..selection.end;
15522
15523                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15524                    let new_range = node.byte_range();
15525                    selected_sibling = true;
15526                    Selection {
15527                        id: selection.id,
15528                        start: new_range.start,
15529                        end: new_range.end,
15530                        goal: SelectionGoal::None,
15531                        reversed: selection.reversed,
15532                    }
15533                } else {
15534                    selection.clone()
15535                }
15536            })
15537            .collect::<Vec<_>>();
15538
15539        if selected_sibling {
15540            self.change_selections(
15541                SelectionEffects::scroll(Autoscroll::fit()),
15542                window,
15543                cx,
15544                |s| {
15545                    s.select(new_selections);
15546                },
15547            );
15548        }
15549    }
15550
15551    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15552        if !EditorSettings::get_global(cx).gutter.runnables {
15553            self.clear_tasks();
15554            return Task::ready(());
15555        }
15556        let project = self.project().map(Entity::downgrade);
15557        let task_sources = self.lsp_task_sources(cx);
15558        let multi_buffer = self.buffer.downgrade();
15559        cx.spawn_in(window, async move |editor, cx| {
15560            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15561            let Some(project) = project.and_then(|p| p.upgrade()) else {
15562                return;
15563            };
15564            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15565                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15566            }) else {
15567                return;
15568            };
15569
15570            let hide_runnables = project
15571                .update(cx, |project, _| project.is_via_collab())
15572                .unwrap_or(true);
15573            if hide_runnables {
15574                return;
15575            }
15576            let new_rows =
15577                cx.background_spawn({
15578                    let snapshot = display_snapshot.clone();
15579                    async move {
15580                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15581                    }
15582                })
15583                    .await;
15584            let Ok(lsp_tasks) =
15585                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15586            else {
15587                return;
15588            };
15589            let lsp_tasks = lsp_tasks.await;
15590
15591            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15592                lsp_tasks
15593                    .into_iter()
15594                    .flat_map(|(kind, tasks)| {
15595                        tasks.into_iter().filter_map(move |(location, task)| {
15596                            Some((kind.clone(), location?, task))
15597                        })
15598                    })
15599                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15600                        let buffer = location.target.buffer;
15601                        let buffer_snapshot = buffer.read(cx).snapshot();
15602                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15603                            |(excerpt_id, snapshot, _)| {
15604                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15605                                    display_snapshot
15606                                        .buffer_snapshot()
15607                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15608                                } else {
15609                                    None
15610                                }
15611                            },
15612                        );
15613                        if let Some(offset) = offset {
15614                            let task_buffer_range =
15615                                location.target.range.to_point(&buffer_snapshot);
15616                            let context_buffer_range =
15617                                task_buffer_range.to_offset(&buffer_snapshot);
15618                            let context_range = BufferOffset(context_buffer_range.start)
15619                                ..BufferOffset(context_buffer_range.end);
15620
15621                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15622                                .or_insert_with(|| RunnableTasks {
15623                                    templates: Vec::new(),
15624                                    offset,
15625                                    column: task_buffer_range.start.column,
15626                                    extra_variables: HashMap::default(),
15627                                    context_range,
15628                                })
15629                                .templates
15630                                .push((kind, task.original_task().clone()));
15631                        }
15632
15633                        acc
15634                    })
15635            }) else {
15636                return;
15637            };
15638
15639            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15640                buffer.language_settings(cx).tasks.prefer_lsp
15641            }) else {
15642                return;
15643            };
15644
15645            let rows = Self::runnable_rows(
15646                project,
15647                display_snapshot,
15648                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15649                new_rows,
15650                cx.clone(),
15651            )
15652            .await;
15653            editor
15654                .update(cx, |editor, _| {
15655                    editor.clear_tasks();
15656                    for (key, mut value) in rows {
15657                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15658                            value.templates.extend(lsp_tasks.templates);
15659                        }
15660
15661                        editor.insert_tasks(key, value);
15662                    }
15663                    for (key, value) in lsp_tasks_by_rows {
15664                        editor.insert_tasks(key, value);
15665                    }
15666                })
15667                .ok();
15668        })
15669    }
15670    fn fetch_runnable_ranges(
15671        snapshot: &DisplaySnapshot,
15672        range: Range<Anchor>,
15673    ) -> Vec<language::RunnableRange> {
15674        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15675    }
15676
15677    fn runnable_rows(
15678        project: Entity<Project>,
15679        snapshot: DisplaySnapshot,
15680        prefer_lsp: bool,
15681        runnable_ranges: Vec<RunnableRange>,
15682        cx: AsyncWindowContext,
15683    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15684        cx.spawn(async move |cx| {
15685            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15686            for mut runnable in runnable_ranges {
15687                let Some(tasks) = cx
15688                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15689                    .ok()
15690                else {
15691                    continue;
15692                };
15693                let mut tasks = tasks.await;
15694
15695                if prefer_lsp {
15696                    tasks.retain(|(task_kind, _)| {
15697                        !matches!(task_kind, TaskSourceKind::Language { .. })
15698                    });
15699                }
15700                if tasks.is_empty() {
15701                    continue;
15702                }
15703
15704                let point = runnable
15705                    .run_range
15706                    .start
15707                    .to_point(&snapshot.buffer_snapshot());
15708                let Some(row) = snapshot
15709                    .buffer_snapshot()
15710                    .buffer_line_for_row(MultiBufferRow(point.row))
15711                    .map(|(_, range)| range.start.row)
15712                else {
15713                    continue;
15714                };
15715
15716                let context_range =
15717                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15718                runnable_rows.push((
15719                    (runnable.buffer_id, row),
15720                    RunnableTasks {
15721                        templates: tasks,
15722                        offset: snapshot
15723                            .buffer_snapshot()
15724                            .anchor_before(runnable.run_range.start),
15725                        context_range,
15726                        column: point.column,
15727                        extra_variables: runnable.extra_captures,
15728                    },
15729                ));
15730            }
15731            runnable_rows
15732        })
15733    }
15734
15735    fn templates_with_tags(
15736        project: &Entity<Project>,
15737        runnable: &mut Runnable,
15738        cx: &mut App,
15739    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15740        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15741            let (worktree_id, file) = project
15742                .buffer_for_id(runnable.buffer, cx)
15743                .and_then(|buffer| buffer.read(cx).file())
15744                .map(|file| (file.worktree_id(cx), file.clone()))
15745                .unzip();
15746
15747            (
15748                project.task_store().read(cx).task_inventory().cloned(),
15749                worktree_id,
15750                file,
15751            )
15752        });
15753
15754        let tags = mem::take(&mut runnable.tags);
15755        let language = runnable.language.clone();
15756        cx.spawn(async move |cx| {
15757            let mut templates_with_tags = Vec::new();
15758            if let Some(inventory) = inventory {
15759                for RunnableTag(tag) in tags {
15760                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15761                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15762                    }) else {
15763                        return templates_with_tags;
15764                    };
15765                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15766                        move |(_, template)| {
15767                            template.tags.iter().any(|source_tag| source_tag == &tag)
15768                        },
15769                    ));
15770                }
15771            }
15772            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15773
15774            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15775                // Strongest source wins; if we have worktree tag binding, prefer that to
15776                // global and language bindings;
15777                // if we have a global binding, prefer that to language binding.
15778                let first_mismatch = templates_with_tags
15779                    .iter()
15780                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15781                if let Some(index) = first_mismatch {
15782                    templates_with_tags.truncate(index);
15783                }
15784            }
15785
15786            templates_with_tags
15787        })
15788    }
15789
15790    pub fn move_to_enclosing_bracket(
15791        &mut self,
15792        _: &MoveToEnclosingBracket,
15793        window: &mut Window,
15794        cx: &mut Context<Self>,
15795    ) {
15796        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15797        self.change_selections(Default::default(), window, cx, |s| {
15798            s.move_offsets_with(|snapshot, selection| {
15799                let Some(enclosing_bracket_ranges) =
15800                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15801                else {
15802                    return;
15803                };
15804
15805                let mut best_length = usize::MAX;
15806                let mut best_inside = false;
15807                let mut best_in_bracket_range = false;
15808                let mut best_destination = None;
15809                for (open, close) in enclosing_bracket_ranges {
15810                    let close = close.to_inclusive();
15811                    let length = close.end() - open.start;
15812                    let inside = selection.start >= open.end && selection.end <= *close.start();
15813                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15814                        || close.contains(&selection.head());
15815
15816                    // If best is next to a bracket and current isn't, skip
15817                    if !in_bracket_range && best_in_bracket_range {
15818                        continue;
15819                    }
15820
15821                    // Prefer smaller lengths unless best is inside and current isn't
15822                    if length > best_length && (best_inside || !inside) {
15823                        continue;
15824                    }
15825
15826                    best_length = length;
15827                    best_inside = inside;
15828                    best_in_bracket_range = in_bracket_range;
15829                    best_destination = Some(
15830                        if close.contains(&selection.start) && close.contains(&selection.end) {
15831                            if inside { open.end } else { open.start }
15832                        } else if inside {
15833                            *close.start()
15834                        } else {
15835                            *close.end()
15836                        },
15837                    );
15838                }
15839
15840                if let Some(destination) = best_destination {
15841                    selection.collapse_to(destination, SelectionGoal::None);
15842                }
15843            })
15844        });
15845    }
15846
15847    pub fn undo_selection(
15848        &mut self,
15849        _: &UndoSelection,
15850        window: &mut Window,
15851        cx: &mut Context<Self>,
15852    ) {
15853        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15854        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15855            self.selection_history.mode = SelectionHistoryMode::Undoing;
15856            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15857                this.end_selection(window, cx);
15858                this.change_selections(
15859                    SelectionEffects::scroll(Autoscroll::newest()),
15860                    window,
15861                    cx,
15862                    |s| s.select_anchors(entry.selections.to_vec()),
15863                );
15864            });
15865            self.selection_history.mode = SelectionHistoryMode::Normal;
15866
15867            self.select_next_state = entry.select_next_state;
15868            self.select_prev_state = entry.select_prev_state;
15869            self.add_selections_state = entry.add_selections_state;
15870        }
15871    }
15872
15873    pub fn redo_selection(
15874        &mut self,
15875        _: &RedoSelection,
15876        window: &mut Window,
15877        cx: &mut Context<Self>,
15878    ) {
15879        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15880        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15881            self.selection_history.mode = SelectionHistoryMode::Redoing;
15882            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15883                this.end_selection(window, cx);
15884                this.change_selections(
15885                    SelectionEffects::scroll(Autoscroll::newest()),
15886                    window,
15887                    cx,
15888                    |s| s.select_anchors(entry.selections.to_vec()),
15889                );
15890            });
15891            self.selection_history.mode = SelectionHistoryMode::Normal;
15892
15893            self.select_next_state = entry.select_next_state;
15894            self.select_prev_state = entry.select_prev_state;
15895            self.add_selections_state = entry.add_selections_state;
15896        }
15897    }
15898
15899    pub fn expand_excerpts(
15900        &mut self,
15901        action: &ExpandExcerpts,
15902        _: &mut Window,
15903        cx: &mut Context<Self>,
15904    ) {
15905        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15906    }
15907
15908    pub fn expand_excerpts_down(
15909        &mut self,
15910        action: &ExpandExcerptsDown,
15911        _: &mut Window,
15912        cx: &mut Context<Self>,
15913    ) {
15914        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15915    }
15916
15917    pub fn expand_excerpts_up(
15918        &mut self,
15919        action: &ExpandExcerptsUp,
15920        _: &mut Window,
15921        cx: &mut Context<Self>,
15922    ) {
15923        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15924    }
15925
15926    pub fn expand_excerpts_for_direction(
15927        &mut self,
15928        lines: u32,
15929        direction: ExpandExcerptDirection,
15930
15931        cx: &mut Context<Self>,
15932    ) {
15933        let selections = self.selections.disjoint_anchors_arc();
15934
15935        let lines = if lines == 0 {
15936            EditorSettings::get_global(cx).expand_excerpt_lines
15937        } else {
15938            lines
15939        };
15940
15941        self.buffer.update(cx, |buffer, cx| {
15942            let snapshot = buffer.snapshot(cx);
15943            let mut excerpt_ids = selections
15944                .iter()
15945                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15946                .collect::<Vec<_>>();
15947            excerpt_ids.sort();
15948            excerpt_ids.dedup();
15949            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15950        })
15951    }
15952
15953    pub fn expand_excerpt(
15954        &mut self,
15955        excerpt: ExcerptId,
15956        direction: ExpandExcerptDirection,
15957        window: &mut Window,
15958        cx: &mut Context<Self>,
15959    ) {
15960        let current_scroll_position = self.scroll_position(cx);
15961        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15962        let mut should_scroll_up = false;
15963
15964        if direction == ExpandExcerptDirection::Down {
15965            let multi_buffer = self.buffer.read(cx);
15966            let snapshot = multi_buffer.snapshot(cx);
15967            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15968                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15969                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15970            {
15971                let buffer_snapshot = buffer.read(cx).snapshot();
15972                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15973                let last_row = buffer_snapshot.max_point().row;
15974                let lines_below = last_row.saturating_sub(excerpt_end_row);
15975                should_scroll_up = lines_below >= lines_to_expand;
15976            }
15977        }
15978
15979        self.buffer.update(cx, |buffer, cx| {
15980            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15981        });
15982
15983        if should_scroll_up {
15984            let new_scroll_position =
15985                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
15986            self.set_scroll_position(new_scroll_position, window, cx);
15987        }
15988    }
15989
15990    pub fn go_to_singleton_buffer_point(
15991        &mut self,
15992        point: Point,
15993        window: &mut Window,
15994        cx: &mut Context<Self>,
15995    ) {
15996        self.go_to_singleton_buffer_range(point..point, window, cx);
15997    }
15998
15999    pub fn go_to_singleton_buffer_range(
16000        &mut self,
16001        range: Range<Point>,
16002        window: &mut Window,
16003        cx: &mut Context<Self>,
16004    ) {
16005        let multibuffer = self.buffer().read(cx);
16006        let Some(buffer) = multibuffer.as_singleton() else {
16007            return;
16008        };
16009        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16010            return;
16011        };
16012        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16013            return;
16014        };
16015        self.change_selections(
16016            SelectionEffects::default().nav_history(true),
16017            window,
16018            cx,
16019            |s| s.select_anchor_ranges([start..end]),
16020        );
16021    }
16022
16023    pub fn go_to_diagnostic(
16024        &mut self,
16025        action: &GoToDiagnostic,
16026        window: &mut Window,
16027        cx: &mut Context<Self>,
16028    ) {
16029        if !self.diagnostics_enabled() {
16030            return;
16031        }
16032        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16033        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16034    }
16035
16036    pub fn go_to_prev_diagnostic(
16037        &mut self,
16038        action: &GoToPreviousDiagnostic,
16039        window: &mut Window,
16040        cx: &mut Context<Self>,
16041    ) {
16042        if !self.diagnostics_enabled() {
16043            return;
16044        }
16045        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16046        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16047    }
16048
16049    pub fn go_to_diagnostic_impl(
16050        &mut self,
16051        direction: Direction,
16052        severity: GoToDiagnosticSeverityFilter,
16053        window: &mut Window,
16054        cx: &mut Context<Self>,
16055    ) {
16056        let buffer = self.buffer.read(cx).snapshot(cx);
16057        let selection = self.selections.newest::<usize>(cx);
16058
16059        let mut active_group_id = None;
16060        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16061            && active_group.active_range.start.to_offset(&buffer) == selection.start
16062        {
16063            active_group_id = Some(active_group.group_id);
16064        }
16065
16066        fn filtered<'a>(
16067            snapshot: EditorSnapshot,
16068            severity: GoToDiagnosticSeverityFilter,
16069            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16070        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16071            diagnostics
16072                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16073                .filter(|entry| entry.range.start != entry.range.end)
16074                .filter(|entry| !entry.diagnostic.is_unnecessary)
16075                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
16076        }
16077
16078        let snapshot = self.snapshot(window, cx);
16079        let before = filtered(
16080            snapshot.clone(),
16081            severity,
16082            buffer
16083                .diagnostics_in_range(0..selection.start)
16084                .filter(|entry| entry.range.start <= selection.start),
16085        );
16086        let after = filtered(
16087            snapshot,
16088            severity,
16089            buffer
16090                .diagnostics_in_range(selection.start..buffer.len())
16091                .filter(|entry| entry.range.start >= selection.start),
16092        );
16093
16094        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16095        if direction == Direction::Prev {
16096            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16097            {
16098                for diagnostic in prev_diagnostics.into_iter().rev() {
16099                    if diagnostic.range.start != selection.start
16100                        || active_group_id
16101                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16102                    {
16103                        found = Some(diagnostic);
16104                        break 'outer;
16105                    }
16106                }
16107            }
16108        } else {
16109            for diagnostic in after.chain(before) {
16110                if diagnostic.range.start != selection.start
16111                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16112                {
16113                    found = Some(diagnostic);
16114                    break;
16115                }
16116            }
16117        }
16118        let Some(next_diagnostic) = found else {
16119            return;
16120        };
16121
16122        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16123        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16124            return;
16125        };
16126        self.change_selections(Default::default(), window, cx, |s| {
16127            s.select_ranges(vec![
16128                next_diagnostic.range.start..next_diagnostic.range.start,
16129            ])
16130        });
16131        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16132        self.refresh_edit_prediction(false, true, window, cx);
16133    }
16134
16135    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16136        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16137        let snapshot = self.snapshot(window, cx);
16138        let selection = self.selections.newest::<Point>(cx);
16139        self.go_to_hunk_before_or_after_position(
16140            &snapshot,
16141            selection.head(),
16142            Direction::Next,
16143            window,
16144            cx,
16145        );
16146    }
16147
16148    pub fn go_to_hunk_before_or_after_position(
16149        &mut self,
16150        snapshot: &EditorSnapshot,
16151        position: Point,
16152        direction: Direction,
16153        window: &mut Window,
16154        cx: &mut Context<Editor>,
16155    ) {
16156        let row = if direction == Direction::Next {
16157            self.hunk_after_position(snapshot, position)
16158                .map(|hunk| hunk.row_range.start)
16159        } else {
16160            self.hunk_before_position(snapshot, position)
16161        };
16162
16163        if let Some(row) = row {
16164            let destination = Point::new(row.0, 0);
16165            let autoscroll = Autoscroll::center();
16166
16167            self.unfold_ranges(&[destination..destination], false, false, cx);
16168            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16169                s.select_ranges([destination..destination]);
16170            });
16171        }
16172    }
16173
16174    fn hunk_after_position(
16175        &mut self,
16176        snapshot: &EditorSnapshot,
16177        position: Point,
16178    ) -> Option<MultiBufferDiffHunk> {
16179        snapshot
16180            .buffer_snapshot()
16181            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16182            .find(|hunk| hunk.row_range.start.0 > position.row)
16183            .or_else(|| {
16184                snapshot
16185                    .buffer_snapshot()
16186                    .diff_hunks_in_range(Point::zero()..position)
16187                    .find(|hunk| hunk.row_range.end.0 < position.row)
16188            })
16189    }
16190
16191    fn go_to_prev_hunk(
16192        &mut self,
16193        _: &GoToPreviousHunk,
16194        window: &mut Window,
16195        cx: &mut Context<Self>,
16196    ) {
16197        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16198        let snapshot = self.snapshot(window, cx);
16199        let selection = self.selections.newest::<Point>(cx);
16200        self.go_to_hunk_before_or_after_position(
16201            &snapshot,
16202            selection.head(),
16203            Direction::Prev,
16204            window,
16205            cx,
16206        );
16207    }
16208
16209    fn hunk_before_position(
16210        &mut self,
16211        snapshot: &EditorSnapshot,
16212        position: Point,
16213    ) -> Option<MultiBufferRow> {
16214        snapshot
16215            .buffer_snapshot()
16216            .diff_hunk_before(position)
16217            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16218    }
16219
16220    fn go_to_next_change(
16221        &mut self,
16222        _: &GoToNextChange,
16223        window: &mut Window,
16224        cx: &mut Context<Self>,
16225    ) {
16226        if let Some(selections) = self
16227            .change_list
16228            .next_change(1, Direction::Next)
16229            .map(|s| s.to_vec())
16230        {
16231            self.change_selections(Default::default(), window, cx, |s| {
16232                let map = s.display_map();
16233                s.select_display_ranges(selections.iter().map(|a| {
16234                    let point = a.to_display_point(&map);
16235                    point..point
16236                }))
16237            })
16238        }
16239    }
16240
16241    fn go_to_previous_change(
16242        &mut self,
16243        _: &GoToPreviousChange,
16244        window: &mut Window,
16245        cx: &mut Context<Self>,
16246    ) {
16247        if let Some(selections) = self
16248            .change_list
16249            .next_change(1, Direction::Prev)
16250            .map(|s| s.to_vec())
16251        {
16252            self.change_selections(Default::default(), window, cx, |s| {
16253                let map = s.display_map();
16254                s.select_display_ranges(selections.iter().map(|a| {
16255                    let point = a.to_display_point(&map);
16256                    point..point
16257                }))
16258            })
16259        }
16260    }
16261
16262    pub fn go_to_next_document_highlight(
16263        &mut self,
16264        _: &GoToNextDocumentHighlight,
16265        window: &mut Window,
16266        cx: &mut Context<Self>,
16267    ) {
16268        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16269    }
16270
16271    pub fn go_to_prev_document_highlight(
16272        &mut self,
16273        _: &GoToPreviousDocumentHighlight,
16274        window: &mut Window,
16275        cx: &mut Context<Self>,
16276    ) {
16277        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16278    }
16279
16280    pub fn go_to_document_highlight_before_or_after_position(
16281        &mut self,
16282        direction: Direction,
16283        window: &mut Window,
16284        cx: &mut Context<Editor>,
16285    ) {
16286        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16287        let snapshot = self.snapshot(window, cx);
16288        let buffer = &snapshot.buffer_snapshot();
16289        let position = self.selections.newest::<Point>(cx).head();
16290        let anchor_position = buffer.anchor_after(position);
16291
16292        // Get all document highlights (both read and write)
16293        let mut all_highlights = Vec::new();
16294
16295        if let Some((_, read_highlights)) = self
16296            .background_highlights
16297            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16298        {
16299            all_highlights.extend(read_highlights.iter());
16300        }
16301
16302        if let Some((_, write_highlights)) = self
16303            .background_highlights
16304            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16305        {
16306            all_highlights.extend(write_highlights.iter());
16307        }
16308
16309        if all_highlights.is_empty() {
16310            return;
16311        }
16312
16313        // Sort highlights by position
16314        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16315
16316        let target_highlight = match direction {
16317            Direction::Next => {
16318                // Find the first highlight after the current position
16319                all_highlights
16320                    .iter()
16321                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16322            }
16323            Direction::Prev => {
16324                // Find the last highlight before the current position
16325                all_highlights
16326                    .iter()
16327                    .rev()
16328                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16329            }
16330        };
16331
16332        if let Some(highlight) = target_highlight {
16333            let destination = highlight.start.to_point(buffer);
16334            let autoscroll = Autoscroll::center();
16335
16336            self.unfold_ranges(&[destination..destination], false, false, cx);
16337            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16338                s.select_ranges([destination..destination]);
16339            });
16340        }
16341    }
16342
16343    fn go_to_line<T: 'static>(
16344        &mut self,
16345        position: Anchor,
16346        highlight_color: Option<Hsla>,
16347        window: &mut Window,
16348        cx: &mut Context<Self>,
16349    ) {
16350        let snapshot = self.snapshot(window, cx).display_snapshot;
16351        let position = position.to_point(&snapshot.buffer_snapshot());
16352        let start = snapshot
16353            .buffer_snapshot()
16354            .clip_point(Point::new(position.row, 0), Bias::Left);
16355        let end = start + Point::new(1, 0);
16356        let start = snapshot.buffer_snapshot().anchor_before(start);
16357        let end = snapshot.buffer_snapshot().anchor_before(end);
16358
16359        self.highlight_rows::<T>(
16360            start..end,
16361            highlight_color
16362                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16363            Default::default(),
16364            cx,
16365        );
16366
16367        if self.buffer.read(cx).is_singleton() {
16368            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16369        }
16370    }
16371
16372    pub fn go_to_definition(
16373        &mut self,
16374        _: &GoToDefinition,
16375        window: &mut Window,
16376        cx: &mut Context<Self>,
16377    ) -> Task<Result<Navigated>> {
16378        let definition =
16379            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16380        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16381        cx.spawn_in(window, async move |editor, cx| {
16382            if definition.await? == Navigated::Yes {
16383                return Ok(Navigated::Yes);
16384            }
16385            match fallback_strategy {
16386                GoToDefinitionFallback::None => Ok(Navigated::No),
16387                GoToDefinitionFallback::FindAllReferences => {
16388                    match editor.update_in(cx, |editor, window, cx| {
16389                        editor.find_all_references(&FindAllReferences, window, cx)
16390                    })? {
16391                        Some(references) => references.await,
16392                        None => Ok(Navigated::No),
16393                    }
16394                }
16395            }
16396        })
16397    }
16398
16399    pub fn go_to_declaration(
16400        &mut self,
16401        _: &GoToDeclaration,
16402        window: &mut Window,
16403        cx: &mut Context<Self>,
16404    ) -> Task<Result<Navigated>> {
16405        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16406    }
16407
16408    pub fn go_to_declaration_split(
16409        &mut self,
16410        _: &GoToDeclaration,
16411        window: &mut Window,
16412        cx: &mut Context<Self>,
16413    ) -> Task<Result<Navigated>> {
16414        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16415    }
16416
16417    pub fn go_to_implementation(
16418        &mut self,
16419        _: &GoToImplementation,
16420        window: &mut Window,
16421        cx: &mut Context<Self>,
16422    ) -> Task<Result<Navigated>> {
16423        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16424    }
16425
16426    pub fn go_to_implementation_split(
16427        &mut self,
16428        _: &GoToImplementationSplit,
16429        window: &mut Window,
16430        cx: &mut Context<Self>,
16431    ) -> Task<Result<Navigated>> {
16432        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16433    }
16434
16435    pub fn go_to_type_definition(
16436        &mut self,
16437        _: &GoToTypeDefinition,
16438        window: &mut Window,
16439        cx: &mut Context<Self>,
16440    ) -> Task<Result<Navigated>> {
16441        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16442    }
16443
16444    pub fn go_to_definition_split(
16445        &mut self,
16446        _: &GoToDefinitionSplit,
16447        window: &mut Window,
16448        cx: &mut Context<Self>,
16449    ) -> Task<Result<Navigated>> {
16450        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16451    }
16452
16453    pub fn go_to_type_definition_split(
16454        &mut self,
16455        _: &GoToTypeDefinitionSplit,
16456        window: &mut Window,
16457        cx: &mut Context<Self>,
16458    ) -> Task<Result<Navigated>> {
16459        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16460    }
16461
16462    fn go_to_definition_of_kind(
16463        &mut self,
16464        kind: GotoDefinitionKind,
16465        split: bool,
16466        window: &mut Window,
16467        cx: &mut Context<Self>,
16468    ) -> Task<Result<Navigated>> {
16469        let Some(provider) = self.semantics_provider.clone() else {
16470            return Task::ready(Ok(Navigated::No));
16471        };
16472        let head = self.selections.newest::<usize>(cx).head();
16473        let buffer = self.buffer.read(cx);
16474        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16475            return Task::ready(Ok(Navigated::No));
16476        };
16477        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16478            return Task::ready(Ok(Navigated::No));
16479        };
16480
16481        cx.spawn_in(window, async move |editor, cx| {
16482            let Some(definitions) = definitions.await? else {
16483                return Ok(Navigated::No);
16484            };
16485            let navigated = editor
16486                .update_in(cx, |editor, window, cx| {
16487                    editor.navigate_to_hover_links(
16488                        Some(kind),
16489                        definitions
16490                            .into_iter()
16491                            .filter(|location| {
16492                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16493                            })
16494                            .map(HoverLink::Text)
16495                            .collect::<Vec<_>>(),
16496                        split,
16497                        window,
16498                        cx,
16499                    )
16500                })?
16501                .await?;
16502            anyhow::Ok(navigated)
16503        })
16504    }
16505
16506    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16507        let selection = self.selections.newest_anchor();
16508        let head = selection.head();
16509        let tail = selection.tail();
16510
16511        let Some((buffer, start_position)) =
16512            self.buffer.read(cx).text_anchor_for_position(head, cx)
16513        else {
16514            return;
16515        };
16516
16517        let end_position = if head != tail {
16518            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16519                return;
16520            };
16521            Some(pos)
16522        } else {
16523            None
16524        };
16525
16526        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16527            let url = if let Some(end_pos) = end_position {
16528                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16529            } else {
16530                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16531            };
16532
16533            if let Some(url) = url {
16534                cx.update(|window, cx| {
16535                    if parse_zed_link(&url, cx).is_some() {
16536                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16537                    } else {
16538                        cx.open_url(&url);
16539                    }
16540                })?;
16541            }
16542
16543            anyhow::Ok(())
16544        });
16545
16546        url_finder.detach();
16547    }
16548
16549    pub fn open_selected_filename(
16550        &mut self,
16551        _: &OpenSelectedFilename,
16552        window: &mut Window,
16553        cx: &mut Context<Self>,
16554    ) {
16555        let Some(workspace) = self.workspace() else {
16556            return;
16557        };
16558
16559        let position = self.selections.newest_anchor().head();
16560
16561        let Some((buffer, buffer_position)) =
16562            self.buffer.read(cx).text_anchor_for_position(position, cx)
16563        else {
16564            return;
16565        };
16566
16567        let project = self.project.clone();
16568
16569        cx.spawn_in(window, async move |_, cx| {
16570            let result = find_file(&buffer, project, buffer_position, cx).await;
16571
16572            if let Some((_, path)) = result {
16573                workspace
16574                    .update_in(cx, |workspace, window, cx| {
16575                        workspace.open_resolved_path(path, window, cx)
16576                    })?
16577                    .await?;
16578            }
16579            anyhow::Ok(())
16580        })
16581        .detach();
16582    }
16583
16584    pub(crate) fn navigate_to_hover_links(
16585        &mut self,
16586        kind: Option<GotoDefinitionKind>,
16587        definitions: Vec<HoverLink>,
16588        split: bool,
16589        window: &mut Window,
16590        cx: &mut Context<Editor>,
16591    ) -> Task<Result<Navigated>> {
16592        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16593        let mut first_url_or_file = None;
16594        let definitions: Vec<_> = definitions
16595            .into_iter()
16596            .filter_map(|def| match def {
16597                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16598                HoverLink::InlayHint(lsp_location, server_id) => {
16599                    let computation =
16600                        self.compute_target_location(lsp_location, server_id, window, cx);
16601                    Some(cx.background_spawn(computation))
16602                }
16603                HoverLink::Url(url) => {
16604                    first_url_or_file = Some(Either::Left(url));
16605                    None
16606                }
16607                HoverLink::File(path) => {
16608                    first_url_or_file = Some(Either::Right(path));
16609                    None
16610                }
16611            })
16612            .collect();
16613
16614        let workspace = self.workspace();
16615
16616        cx.spawn_in(window, async move |editor, cx| {
16617            let locations: Vec<Location> = future::join_all(definitions)
16618                .await
16619                .into_iter()
16620                .filter_map(|location| location.transpose())
16621                .collect::<Result<_>>()
16622                .context("location tasks")?;
16623            let mut locations = cx.update(|_, cx| {
16624                locations
16625                    .into_iter()
16626                    .map(|location| {
16627                        let buffer = location.buffer.read(cx);
16628                        (location.buffer, location.range.to_point(buffer))
16629                    })
16630                    .into_group_map()
16631            })?;
16632            let mut num_locations = 0;
16633            for ranges in locations.values_mut() {
16634                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16635                ranges.dedup();
16636                num_locations += ranges.len();
16637            }
16638
16639            if num_locations > 1 {
16640                let Some(workspace) = workspace else {
16641                    return Ok(Navigated::No);
16642                };
16643
16644                let tab_kind = match kind {
16645                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16646                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16647                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16648                    Some(GotoDefinitionKind::Type) => "Types",
16649                };
16650                let title = editor
16651                    .update_in(cx, |_, _, cx| {
16652                        let target = locations
16653                            .iter()
16654                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16655                            .map(|(buffer, location)| {
16656                                buffer
16657                                    .read(cx)
16658                                    .text_for_range(location.clone())
16659                                    .collect::<String>()
16660                            })
16661                            .filter(|text| !text.contains('\n'))
16662                            .unique()
16663                            .take(3)
16664                            .join(", ");
16665                        if target.is_empty() {
16666                            tab_kind.to_owned()
16667                        } else {
16668                            format!("{tab_kind} for {target}")
16669                        }
16670                    })
16671                    .context("buffer title")?;
16672
16673                let opened = workspace
16674                    .update_in(cx, |workspace, window, cx| {
16675                        Self::open_locations_in_multibuffer(
16676                            workspace,
16677                            locations,
16678                            title,
16679                            split,
16680                            MultibufferSelectionMode::First,
16681                            window,
16682                            cx,
16683                        )
16684                    })
16685                    .is_ok();
16686
16687                anyhow::Ok(Navigated::from_bool(opened))
16688            } else if num_locations == 0 {
16689                // If there is one url or file, open it directly
16690                match first_url_or_file {
16691                    Some(Either::Left(url)) => {
16692                        cx.update(|_, cx| cx.open_url(&url))?;
16693                        Ok(Navigated::Yes)
16694                    }
16695                    Some(Either::Right(path)) => {
16696                        let Some(workspace) = workspace else {
16697                            return Ok(Navigated::No);
16698                        };
16699
16700                        workspace
16701                            .update_in(cx, |workspace, window, cx| {
16702                                workspace.open_resolved_path(path, window, cx)
16703                            })?
16704                            .await?;
16705                        Ok(Navigated::Yes)
16706                    }
16707                    None => Ok(Navigated::No),
16708                }
16709            } else {
16710                let Some(workspace) = workspace else {
16711                    return Ok(Navigated::No);
16712                };
16713
16714                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16715                let target_range = target_ranges.first().unwrap().clone();
16716
16717                editor.update_in(cx, |editor, window, cx| {
16718                    let range = target_range.to_point(target_buffer.read(cx));
16719                    let range = editor.range_for_match(&range);
16720                    let range = collapse_multiline_range(range);
16721
16722                    if !split
16723                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16724                    {
16725                        editor.go_to_singleton_buffer_range(range, window, cx);
16726                    } else {
16727                        let pane = workspace.read(cx).active_pane().clone();
16728                        window.defer(cx, move |window, cx| {
16729                            let target_editor: Entity<Self> =
16730                                workspace.update(cx, |workspace, cx| {
16731                                    let pane = if split {
16732                                        workspace.adjacent_pane(window, cx)
16733                                    } else {
16734                                        workspace.active_pane().clone()
16735                                    };
16736
16737                                    workspace.open_project_item(
16738                                        pane,
16739                                        target_buffer.clone(),
16740                                        true,
16741                                        true,
16742                                        window,
16743                                        cx,
16744                                    )
16745                                });
16746                            target_editor.update(cx, |target_editor, cx| {
16747                                // When selecting a definition in a different buffer, disable the nav history
16748                                // to avoid creating a history entry at the previous cursor location.
16749                                pane.update(cx, |pane, _| pane.disable_history());
16750                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16751                                pane.update(cx, |pane, _| pane.enable_history());
16752                            });
16753                        });
16754                    }
16755                    Navigated::Yes
16756                })
16757            }
16758        })
16759    }
16760
16761    fn compute_target_location(
16762        &self,
16763        lsp_location: lsp::Location,
16764        server_id: LanguageServerId,
16765        window: &mut Window,
16766        cx: &mut Context<Self>,
16767    ) -> Task<anyhow::Result<Option<Location>>> {
16768        let Some(project) = self.project.clone() else {
16769            return Task::ready(Ok(None));
16770        };
16771
16772        cx.spawn_in(window, async move |editor, cx| {
16773            let location_task = editor.update(cx, |_, cx| {
16774                project.update(cx, |project, cx| {
16775                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16776                })
16777            })?;
16778            let location = Some({
16779                let target_buffer_handle = location_task.await.context("open local buffer")?;
16780                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16781                    let target_start = target_buffer
16782                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16783                    let target_end = target_buffer
16784                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16785                    target_buffer.anchor_after(target_start)
16786                        ..target_buffer.anchor_before(target_end)
16787                })?;
16788                Location {
16789                    buffer: target_buffer_handle,
16790                    range,
16791                }
16792            });
16793            Ok(location)
16794        })
16795    }
16796
16797    pub fn find_all_references(
16798        &mut self,
16799        _: &FindAllReferences,
16800        window: &mut Window,
16801        cx: &mut Context<Self>,
16802    ) -> Option<Task<Result<Navigated>>> {
16803        let selection = self.selections.newest::<usize>(cx);
16804        let multi_buffer = self.buffer.read(cx);
16805        let head = selection.head();
16806
16807        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16808        let head_anchor = multi_buffer_snapshot.anchor_at(
16809            head,
16810            if head < selection.tail() {
16811                Bias::Right
16812            } else {
16813                Bias::Left
16814            },
16815        );
16816
16817        match self
16818            .find_all_references_task_sources
16819            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16820        {
16821            Ok(_) => {
16822                log::info!(
16823                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16824                );
16825                return None;
16826            }
16827            Err(i) => {
16828                self.find_all_references_task_sources.insert(i, head_anchor);
16829            }
16830        }
16831
16832        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16833        let workspace = self.workspace()?;
16834        let project = workspace.read(cx).project().clone();
16835        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16836        Some(cx.spawn_in(window, async move |editor, cx| {
16837            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16838                if let Ok(i) = editor
16839                    .find_all_references_task_sources
16840                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16841                {
16842                    editor.find_all_references_task_sources.remove(i);
16843                }
16844            });
16845
16846            let Some(locations) = references.await? else {
16847                return anyhow::Ok(Navigated::No);
16848            };
16849            let mut locations = cx.update(|_, cx| {
16850                locations
16851                    .into_iter()
16852                    .map(|location| {
16853                        let buffer = location.buffer.read(cx);
16854                        (location.buffer, location.range.to_point(buffer))
16855                    })
16856                    .into_group_map()
16857            })?;
16858            if locations.is_empty() {
16859                return anyhow::Ok(Navigated::No);
16860            }
16861            for ranges in locations.values_mut() {
16862                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16863                ranges.dedup();
16864            }
16865
16866            workspace.update_in(cx, |workspace, window, cx| {
16867                let target = locations
16868                    .iter()
16869                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16870                    .map(|(buffer, location)| {
16871                        buffer
16872                            .read(cx)
16873                            .text_for_range(location.clone())
16874                            .collect::<String>()
16875                    })
16876                    .filter(|text| !text.contains('\n'))
16877                    .unique()
16878                    .take(3)
16879                    .join(", ");
16880                let title = if target.is_empty() {
16881                    "References".to_owned()
16882                } else {
16883                    format!("References to {target}")
16884                };
16885                Self::open_locations_in_multibuffer(
16886                    workspace,
16887                    locations,
16888                    title,
16889                    false,
16890                    MultibufferSelectionMode::First,
16891                    window,
16892                    cx,
16893                );
16894                Navigated::Yes
16895            })
16896        }))
16897    }
16898
16899    /// Opens a multibuffer with the given project locations in it
16900    pub fn open_locations_in_multibuffer(
16901        workspace: &mut Workspace,
16902        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16903        title: String,
16904        split: bool,
16905        multibuffer_selection_mode: MultibufferSelectionMode,
16906        window: &mut Window,
16907        cx: &mut Context<Workspace>,
16908    ) {
16909        if locations.is_empty() {
16910            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16911            return;
16912        }
16913
16914        let capability = workspace.project().read(cx).capability();
16915        let mut ranges = <Vec<Range<Anchor>>>::new();
16916
16917        // a key to find existing multibuffer editors with the same set of locations
16918        // to prevent us from opening more and more multibuffer tabs for searches and the like
16919        let mut key = (title.clone(), vec![]);
16920        let excerpt_buffer = cx.new(|cx| {
16921            let key = &mut key.1;
16922            let mut multibuffer = MultiBuffer::new(capability);
16923            for (buffer, mut ranges_for_buffer) in locations {
16924                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16925                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16926                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16927                    PathKey::for_buffer(&buffer, cx),
16928                    buffer.clone(),
16929                    ranges_for_buffer,
16930                    multibuffer_context_lines(cx),
16931                    cx,
16932                );
16933                ranges.extend(new_ranges)
16934            }
16935
16936            multibuffer.with_title(title)
16937        });
16938        let existing = workspace.active_pane().update(cx, |pane, cx| {
16939            pane.items()
16940                .filter_map(|item| item.downcast::<Editor>())
16941                .find(|editor| {
16942                    editor
16943                        .read(cx)
16944                        .lookup_key
16945                        .as_ref()
16946                        .and_then(|it| {
16947                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16948                        })
16949                        .is_some_and(|it| *it == key)
16950                })
16951        });
16952        let editor = existing.unwrap_or_else(|| {
16953            cx.new(|cx| {
16954                let mut editor = Editor::for_multibuffer(
16955                    excerpt_buffer,
16956                    Some(workspace.project().clone()),
16957                    window,
16958                    cx,
16959                );
16960                editor.lookup_key = Some(Box::new(key));
16961                editor
16962            })
16963        });
16964        editor.update(cx, |editor, cx| {
16965            match multibuffer_selection_mode {
16966                MultibufferSelectionMode::First => {
16967                    if let Some(first_range) = ranges.first() {
16968                        editor.change_selections(
16969                            SelectionEffects::no_scroll(),
16970                            window,
16971                            cx,
16972                            |selections| {
16973                                selections.clear_disjoint();
16974                                selections
16975                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16976                            },
16977                        );
16978                    }
16979                    editor.highlight_background::<Self>(
16980                        &ranges,
16981                        |theme| theme.colors().editor_highlighted_line_background,
16982                        cx,
16983                    );
16984                }
16985                MultibufferSelectionMode::All => {
16986                    editor.change_selections(
16987                        SelectionEffects::no_scroll(),
16988                        window,
16989                        cx,
16990                        |selections| {
16991                            selections.clear_disjoint();
16992                            selections.select_anchor_ranges(ranges);
16993                        },
16994                    );
16995                }
16996            }
16997            editor.register_buffers_with_language_servers(cx);
16998        });
16999
17000        let item = Box::new(editor);
17001        let item_id = item.item_id();
17002
17003        if split {
17004            let pane = workspace.adjacent_pane(window, cx);
17005            workspace.add_item(pane, item, None, true, true, window, cx);
17006        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17007            let (preview_item_id, preview_item_idx) =
17008                workspace.active_pane().read_with(cx, |pane, _| {
17009                    (pane.preview_item_id(), pane.preview_item_idx())
17010                });
17011
17012            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17013
17014            if let Some(preview_item_id) = preview_item_id {
17015                workspace.active_pane().update(cx, |pane, cx| {
17016                    pane.remove_item(preview_item_id, false, false, window, cx);
17017                });
17018            }
17019        } else {
17020            workspace.add_item_to_active_pane(item, None, true, window, cx);
17021        }
17022        workspace.active_pane().update(cx, |pane, cx| {
17023            pane.set_preview_item_id(Some(item_id), cx);
17024        });
17025    }
17026
17027    pub fn rename(
17028        &mut self,
17029        _: &Rename,
17030        window: &mut Window,
17031        cx: &mut Context<Self>,
17032    ) -> Option<Task<Result<()>>> {
17033        use language::ToOffset as _;
17034
17035        let provider = self.semantics_provider.clone()?;
17036        let selection = self.selections.newest_anchor().clone();
17037        let (cursor_buffer, cursor_buffer_position) = self
17038            .buffer
17039            .read(cx)
17040            .text_anchor_for_position(selection.head(), cx)?;
17041        let (tail_buffer, cursor_buffer_position_end) = self
17042            .buffer
17043            .read(cx)
17044            .text_anchor_for_position(selection.tail(), cx)?;
17045        if tail_buffer != cursor_buffer {
17046            return None;
17047        }
17048
17049        let snapshot = cursor_buffer.read(cx).snapshot();
17050        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17051        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17052        let prepare_rename = provider
17053            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17054            .unwrap_or_else(|| Task::ready(Ok(None)));
17055        drop(snapshot);
17056
17057        Some(cx.spawn_in(window, async move |this, cx| {
17058            let rename_range = if let Some(range) = prepare_rename.await? {
17059                Some(range)
17060            } else {
17061                this.update(cx, |this, cx| {
17062                    let buffer = this.buffer.read(cx).snapshot(cx);
17063                    let mut buffer_highlights = this
17064                        .document_highlights_for_position(selection.head(), &buffer)
17065                        .filter(|highlight| {
17066                            highlight.start.excerpt_id == selection.head().excerpt_id
17067                                && highlight.end.excerpt_id == selection.head().excerpt_id
17068                        });
17069                    buffer_highlights
17070                        .next()
17071                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17072                })?
17073            };
17074            if let Some(rename_range) = rename_range {
17075                this.update_in(cx, |this, window, cx| {
17076                    let snapshot = cursor_buffer.read(cx).snapshot();
17077                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17078                    let cursor_offset_in_rename_range =
17079                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17080                    let cursor_offset_in_rename_range_end =
17081                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17082
17083                    this.take_rename(false, window, cx);
17084                    let buffer = this.buffer.read(cx).read(cx);
17085                    let cursor_offset = selection.head().to_offset(&buffer);
17086                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17087                    let rename_end = rename_start + rename_buffer_range.len();
17088                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17089                    let mut old_highlight_id = None;
17090                    let old_name: Arc<str> = buffer
17091                        .chunks(rename_start..rename_end, true)
17092                        .map(|chunk| {
17093                            if old_highlight_id.is_none() {
17094                                old_highlight_id = chunk.syntax_highlight_id;
17095                            }
17096                            chunk.text
17097                        })
17098                        .collect::<String>()
17099                        .into();
17100
17101                    drop(buffer);
17102
17103                    // Position the selection in the rename editor so that it matches the current selection.
17104                    this.show_local_selections = false;
17105                    let rename_editor = cx.new(|cx| {
17106                        let mut editor = Editor::single_line(window, cx);
17107                        editor.buffer.update(cx, |buffer, cx| {
17108                            buffer.edit([(0..0, old_name.clone())], None, cx)
17109                        });
17110                        let rename_selection_range = match cursor_offset_in_rename_range
17111                            .cmp(&cursor_offset_in_rename_range_end)
17112                        {
17113                            Ordering::Equal => {
17114                                editor.select_all(&SelectAll, window, cx);
17115                                return editor;
17116                            }
17117                            Ordering::Less => {
17118                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17119                            }
17120                            Ordering::Greater => {
17121                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17122                            }
17123                        };
17124                        if rename_selection_range.end > old_name.len() {
17125                            editor.select_all(&SelectAll, window, cx);
17126                        } else {
17127                            editor.change_selections(Default::default(), window, cx, |s| {
17128                                s.select_ranges([rename_selection_range]);
17129                            });
17130                        }
17131                        editor
17132                    });
17133                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17134                        if e == &EditorEvent::Focused {
17135                            cx.emit(EditorEvent::FocusedIn)
17136                        }
17137                    })
17138                    .detach();
17139
17140                    let write_highlights =
17141                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17142                    let read_highlights =
17143                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17144                    let ranges = write_highlights
17145                        .iter()
17146                        .flat_map(|(_, ranges)| ranges.iter())
17147                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17148                        .cloned()
17149                        .collect();
17150
17151                    this.highlight_text::<Rename>(
17152                        ranges,
17153                        HighlightStyle {
17154                            fade_out: Some(0.6),
17155                            ..Default::default()
17156                        },
17157                        cx,
17158                    );
17159                    let rename_focus_handle = rename_editor.focus_handle(cx);
17160                    window.focus(&rename_focus_handle);
17161                    let block_id = this.insert_blocks(
17162                        [BlockProperties {
17163                            style: BlockStyle::Flex,
17164                            placement: BlockPlacement::Below(range.start),
17165                            height: Some(1),
17166                            render: Arc::new({
17167                                let rename_editor = rename_editor.clone();
17168                                move |cx: &mut BlockContext| {
17169                                    let mut text_style = cx.editor_style.text.clone();
17170                                    if let Some(highlight_style) = old_highlight_id
17171                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17172                                    {
17173                                        text_style = text_style.highlight(highlight_style);
17174                                    }
17175                                    div()
17176                                        .block_mouse_except_scroll()
17177                                        .pl(cx.anchor_x)
17178                                        .child(EditorElement::new(
17179                                            &rename_editor,
17180                                            EditorStyle {
17181                                                background: cx.theme().system().transparent,
17182                                                local_player: cx.editor_style.local_player,
17183                                                text: text_style,
17184                                                scrollbar_width: cx.editor_style.scrollbar_width,
17185                                                syntax: cx.editor_style.syntax.clone(),
17186                                                status: cx.editor_style.status.clone(),
17187                                                inlay_hints_style: HighlightStyle {
17188                                                    font_weight: Some(FontWeight::BOLD),
17189                                                    ..make_inlay_hints_style(cx.app)
17190                                                },
17191                                                edit_prediction_styles: make_suggestion_styles(
17192                                                    cx.app,
17193                                                ),
17194                                                ..EditorStyle::default()
17195                                            },
17196                                        ))
17197                                        .into_any_element()
17198                                }
17199                            }),
17200                            priority: 0,
17201                        }],
17202                        Some(Autoscroll::fit()),
17203                        cx,
17204                    )[0];
17205                    this.pending_rename = Some(RenameState {
17206                        range,
17207                        old_name,
17208                        editor: rename_editor,
17209                        block_id,
17210                    });
17211                })?;
17212            }
17213
17214            Ok(())
17215        }))
17216    }
17217
17218    pub fn confirm_rename(
17219        &mut self,
17220        _: &ConfirmRename,
17221        window: &mut Window,
17222        cx: &mut Context<Self>,
17223    ) -> Option<Task<Result<()>>> {
17224        let rename = self.take_rename(false, window, cx)?;
17225        let workspace = self.workspace()?.downgrade();
17226        let (buffer, start) = self
17227            .buffer
17228            .read(cx)
17229            .text_anchor_for_position(rename.range.start, cx)?;
17230        let (end_buffer, _) = self
17231            .buffer
17232            .read(cx)
17233            .text_anchor_for_position(rename.range.end, cx)?;
17234        if buffer != end_buffer {
17235            return None;
17236        }
17237
17238        let old_name = rename.old_name;
17239        let new_name = rename.editor.read(cx).text(cx);
17240
17241        let rename = self.semantics_provider.as_ref()?.perform_rename(
17242            &buffer,
17243            start,
17244            new_name.clone(),
17245            cx,
17246        )?;
17247
17248        Some(cx.spawn_in(window, async move |editor, cx| {
17249            let project_transaction = rename.await?;
17250            Self::open_project_transaction(
17251                &editor,
17252                workspace,
17253                project_transaction,
17254                format!("Rename: {}{}", old_name, new_name),
17255                cx,
17256            )
17257            .await?;
17258
17259            editor.update(cx, |editor, cx| {
17260                editor.refresh_document_highlights(cx);
17261            })?;
17262            Ok(())
17263        }))
17264    }
17265
17266    fn take_rename(
17267        &mut self,
17268        moving_cursor: bool,
17269        window: &mut Window,
17270        cx: &mut Context<Self>,
17271    ) -> Option<RenameState> {
17272        let rename = self.pending_rename.take()?;
17273        if rename.editor.focus_handle(cx).is_focused(window) {
17274            window.focus(&self.focus_handle);
17275        }
17276
17277        self.remove_blocks(
17278            [rename.block_id].into_iter().collect(),
17279            Some(Autoscroll::fit()),
17280            cx,
17281        );
17282        self.clear_highlights::<Rename>(cx);
17283        self.show_local_selections = true;
17284
17285        if moving_cursor {
17286            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17287                editor.selections.newest::<usize>(cx).head()
17288            });
17289
17290            // Update the selection to match the position of the selection inside
17291            // the rename editor.
17292            let snapshot = self.buffer.read(cx).read(cx);
17293            let rename_range = rename.range.to_offset(&snapshot);
17294            let cursor_in_editor = snapshot
17295                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17296                .min(rename_range.end);
17297            drop(snapshot);
17298
17299            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17300                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17301            });
17302        } else {
17303            self.refresh_document_highlights(cx);
17304        }
17305
17306        Some(rename)
17307    }
17308
17309    pub fn pending_rename(&self) -> Option<&RenameState> {
17310        self.pending_rename.as_ref()
17311    }
17312
17313    fn format(
17314        &mut self,
17315        _: &Format,
17316        window: &mut Window,
17317        cx: &mut Context<Self>,
17318    ) -> Option<Task<Result<()>>> {
17319        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17320
17321        let project = match &self.project {
17322            Some(project) => project.clone(),
17323            None => return None,
17324        };
17325
17326        Some(self.perform_format(
17327            project,
17328            FormatTrigger::Manual,
17329            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17330            window,
17331            cx,
17332        ))
17333    }
17334
17335    fn format_selections(
17336        &mut self,
17337        _: &FormatSelections,
17338        window: &mut Window,
17339        cx: &mut Context<Self>,
17340    ) -> Option<Task<Result<()>>> {
17341        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17342
17343        let project = match &self.project {
17344            Some(project) => project.clone(),
17345            None => return None,
17346        };
17347
17348        let ranges = self
17349            .selections
17350            .all_adjusted(cx)
17351            .into_iter()
17352            .map(|selection| selection.range())
17353            .collect_vec();
17354
17355        Some(self.perform_format(
17356            project,
17357            FormatTrigger::Manual,
17358            FormatTarget::Ranges(ranges),
17359            window,
17360            cx,
17361        ))
17362    }
17363
17364    fn perform_format(
17365        &mut self,
17366        project: Entity<Project>,
17367        trigger: FormatTrigger,
17368        target: FormatTarget,
17369        window: &mut Window,
17370        cx: &mut Context<Self>,
17371    ) -> Task<Result<()>> {
17372        let buffer = self.buffer.clone();
17373        let (buffers, target) = match target {
17374            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17375            FormatTarget::Ranges(selection_ranges) => {
17376                let multi_buffer = buffer.read(cx);
17377                let snapshot = multi_buffer.read(cx);
17378                let mut buffers = HashSet::default();
17379                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17380                    BTreeMap::new();
17381                for selection_range in selection_ranges {
17382                    for (buffer, buffer_range, _) in
17383                        snapshot.range_to_buffer_ranges(selection_range)
17384                    {
17385                        let buffer_id = buffer.remote_id();
17386                        let start = buffer.anchor_before(buffer_range.start);
17387                        let end = buffer.anchor_after(buffer_range.end);
17388                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17389                        buffer_id_to_ranges
17390                            .entry(buffer_id)
17391                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17392                            .or_insert_with(|| vec![start..end]);
17393                    }
17394                }
17395                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17396            }
17397        };
17398
17399        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17400        let selections_prev = transaction_id_prev
17401            .and_then(|transaction_id_prev| {
17402                // default to selections as they were after the last edit, if we have them,
17403                // instead of how they are now.
17404                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17405                // will take you back to where you made the last edit, instead of staying where you scrolled
17406                self.selection_history
17407                    .transaction(transaction_id_prev)
17408                    .map(|t| t.0.clone())
17409            })
17410            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17411
17412        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17413        let format = project.update(cx, |project, cx| {
17414            project.format(buffers, target, true, trigger, cx)
17415        });
17416
17417        cx.spawn_in(window, async move |editor, cx| {
17418            let transaction = futures::select_biased! {
17419                transaction = format.log_err().fuse() => transaction,
17420                () = timeout => {
17421                    log::warn!("timed out waiting for formatting");
17422                    None
17423                }
17424            };
17425
17426            buffer
17427                .update(cx, |buffer, cx| {
17428                    if let Some(transaction) = transaction
17429                        && !buffer.is_singleton()
17430                    {
17431                        buffer.push_transaction(&transaction.0, cx);
17432                    }
17433                    cx.notify();
17434                })
17435                .ok();
17436
17437            if let Some(transaction_id_now) =
17438                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17439            {
17440                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17441                if has_new_transaction {
17442                    _ = editor.update(cx, |editor, _| {
17443                        editor
17444                            .selection_history
17445                            .insert_transaction(transaction_id_now, selections_prev);
17446                    });
17447                }
17448            }
17449
17450            Ok(())
17451        })
17452    }
17453
17454    fn organize_imports(
17455        &mut self,
17456        _: &OrganizeImports,
17457        window: &mut Window,
17458        cx: &mut Context<Self>,
17459    ) -> Option<Task<Result<()>>> {
17460        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17461        let project = match &self.project {
17462            Some(project) => project.clone(),
17463            None => return None,
17464        };
17465        Some(self.perform_code_action_kind(
17466            project,
17467            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17468            window,
17469            cx,
17470        ))
17471    }
17472
17473    fn perform_code_action_kind(
17474        &mut self,
17475        project: Entity<Project>,
17476        kind: CodeActionKind,
17477        window: &mut Window,
17478        cx: &mut Context<Self>,
17479    ) -> Task<Result<()>> {
17480        let buffer = self.buffer.clone();
17481        let buffers = buffer.read(cx).all_buffers();
17482        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17483        let apply_action = project.update(cx, |project, cx| {
17484            project.apply_code_action_kind(buffers, kind, true, cx)
17485        });
17486        cx.spawn_in(window, async move |_, cx| {
17487            let transaction = futures::select_biased! {
17488                () = timeout => {
17489                    log::warn!("timed out waiting for executing code action");
17490                    None
17491                }
17492                transaction = apply_action.log_err().fuse() => transaction,
17493            };
17494            buffer
17495                .update(cx, |buffer, cx| {
17496                    // check if we need this
17497                    if let Some(transaction) = transaction
17498                        && !buffer.is_singleton()
17499                    {
17500                        buffer.push_transaction(&transaction.0, cx);
17501                    }
17502                    cx.notify();
17503                })
17504                .ok();
17505            Ok(())
17506        })
17507    }
17508
17509    pub fn restart_language_server(
17510        &mut self,
17511        _: &RestartLanguageServer,
17512        _: &mut Window,
17513        cx: &mut Context<Self>,
17514    ) {
17515        if let Some(project) = self.project.clone() {
17516            self.buffer.update(cx, |multi_buffer, cx| {
17517                project.update(cx, |project, cx| {
17518                    project.restart_language_servers_for_buffers(
17519                        multi_buffer.all_buffers().into_iter().collect(),
17520                        HashSet::default(),
17521                        cx,
17522                    );
17523                });
17524            })
17525        }
17526    }
17527
17528    pub fn stop_language_server(
17529        &mut self,
17530        _: &StopLanguageServer,
17531        _: &mut Window,
17532        cx: &mut Context<Self>,
17533    ) {
17534        if let Some(project) = self.project.clone() {
17535            self.buffer.update(cx, |multi_buffer, cx| {
17536                project.update(cx, |project, cx| {
17537                    project.stop_language_servers_for_buffers(
17538                        multi_buffer.all_buffers().into_iter().collect(),
17539                        HashSet::default(),
17540                        cx,
17541                    );
17542                    cx.emit(project::Event::RefreshInlayHints);
17543                });
17544            });
17545        }
17546    }
17547
17548    fn cancel_language_server_work(
17549        workspace: &mut Workspace,
17550        _: &actions::CancelLanguageServerWork,
17551        _: &mut Window,
17552        cx: &mut Context<Workspace>,
17553    ) {
17554        let project = workspace.project();
17555        let buffers = workspace
17556            .active_item(cx)
17557            .and_then(|item| item.act_as::<Editor>(cx))
17558            .map_or(HashSet::default(), |editor| {
17559                editor.read(cx).buffer.read(cx).all_buffers()
17560            });
17561        project.update(cx, |project, cx| {
17562            project.cancel_language_server_work_for_buffers(buffers, cx);
17563        });
17564    }
17565
17566    fn show_character_palette(
17567        &mut self,
17568        _: &ShowCharacterPalette,
17569        window: &mut Window,
17570        _: &mut Context<Self>,
17571    ) {
17572        window.show_character_palette();
17573    }
17574
17575    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17576        if !self.diagnostics_enabled() {
17577            return;
17578        }
17579
17580        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17581            let buffer = self.buffer.read(cx).snapshot(cx);
17582            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17583            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17584            let is_valid = buffer
17585                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17586                .any(|entry| {
17587                    entry.diagnostic.is_primary
17588                        && !entry.range.is_empty()
17589                        && entry.range.start == primary_range_start
17590                        && entry.diagnostic.message == active_diagnostics.active_message
17591                });
17592
17593            if !is_valid {
17594                self.dismiss_diagnostics(cx);
17595            }
17596        }
17597    }
17598
17599    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17600        match &self.active_diagnostics {
17601            ActiveDiagnostic::Group(group) => Some(group),
17602            _ => None,
17603        }
17604    }
17605
17606    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17607        if !self.diagnostics_enabled() {
17608            return;
17609        }
17610        self.dismiss_diagnostics(cx);
17611        self.active_diagnostics = ActiveDiagnostic::All;
17612    }
17613
17614    fn activate_diagnostics(
17615        &mut self,
17616        buffer_id: BufferId,
17617        diagnostic: DiagnosticEntryRef<'_, usize>,
17618        window: &mut Window,
17619        cx: &mut Context<Self>,
17620    ) {
17621        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17622            return;
17623        }
17624        self.dismiss_diagnostics(cx);
17625        let snapshot = self.snapshot(window, cx);
17626        let buffer = self.buffer.read(cx).snapshot(cx);
17627        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17628            return;
17629        };
17630
17631        let diagnostic_group = buffer
17632            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17633            .collect::<Vec<_>>();
17634
17635        let blocks =
17636            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17637
17638        let blocks = self.display_map.update(cx, |display_map, cx| {
17639            display_map.insert_blocks(blocks, cx).into_iter().collect()
17640        });
17641        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17642            active_range: buffer.anchor_before(diagnostic.range.start)
17643                ..buffer.anchor_after(diagnostic.range.end),
17644            active_message: diagnostic.diagnostic.message.clone(),
17645            group_id: diagnostic.diagnostic.group_id,
17646            blocks,
17647        });
17648        cx.notify();
17649    }
17650
17651    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17652        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17653            return;
17654        };
17655
17656        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17657        if let ActiveDiagnostic::Group(group) = prev {
17658            self.display_map.update(cx, |display_map, cx| {
17659                display_map.remove_blocks(group.blocks, cx);
17660            });
17661            cx.notify();
17662        }
17663    }
17664
17665    /// Disable inline diagnostics rendering for this editor.
17666    pub fn disable_inline_diagnostics(&mut self) {
17667        self.inline_diagnostics_enabled = false;
17668        self.inline_diagnostics_update = Task::ready(());
17669        self.inline_diagnostics.clear();
17670    }
17671
17672    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17673        self.diagnostics_enabled = false;
17674        self.dismiss_diagnostics(cx);
17675        self.inline_diagnostics_update = Task::ready(());
17676        self.inline_diagnostics.clear();
17677    }
17678
17679    pub fn disable_word_completions(&mut self) {
17680        self.word_completions_enabled = false;
17681    }
17682
17683    pub fn diagnostics_enabled(&self) -> bool {
17684        self.diagnostics_enabled && self.mode.is_full()
17685    }
17686
17687    pub fn inline_diagnostics_enabled(&self) -> bool {
17688        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17689    }
17690
17691    pub fn show_inline_diagnostics(&self) -> bool {
17692        self.show_inline_diagnostics
17693    }
17694
17695    pub fn toggle_inline_diagnostics(
17696        &mut self,
17697        _: &ToggleInlineDiagnostics,
17698        window: &mut Window,
17699        cx: &mut Context<Editor>,
17700    ) {
17701        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17702        self.refresh_inline_diagnostics(false, window, cx);
17703    }
17704
17705    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17706        self.diagnostics_max_severity = severity;
17707        self.display_map.update(cx, |display_map, _| {
17708            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17709        });
17710    }
17711
17712    pub fn toggle_diagnostics(
17713        &mut self,
17714        _: &ToggleDiagnostics,
17715        window: &mut Window,
17716        cx: &mut Context<Editor>,
17717    ) {
17718        if !self.diagnostics_enabled() {
17719            return;
17720        }
17721
17722        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17723            EditorSettings::get_global(cx)
17724                .diagnostics_max_severity
17725                .filter(|severity| severity != &DiagnosticSeverity::Off)
17726                .unwrap_or(DiagnosticSeverity::Hint)
17727        } else {
17728            DiagnosticSeverity::Off
17729        };
17730        self.set_max_diagnostics_severity(new_severity, cx);
17731        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17732            self.active_diagnostics = ActiveDiagnostic::None;
17733            self.inline_diagnostics_update = Task::ready(());
17734            self.inline_diagnostics.clear();
17735        } else {
17736            self.refresh_inline_diagnostics(false, window, cx);
17737        }
17738
17739        cx.notify();
17740    }
17741
17742    pub fn toggle_minimap(
17743        &mut self,
17744        _: &ToggleMinimap,
17745        window: &mut Window,
17746        cx: &mut Context<Editor>,
17747    ) {
17748        if self.supports_minimap(cx) {
17749            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17750        }
17751    }
17752
17753    fn refresh_inline_diagnostics(
17754        &mut self,
17755        debounce: bool,
17756        window: &mut Window,
17757        cx: &mut Context<Self>,
17758    ) {
17759        let max_severity = ProjectSettings::get_global(cx)
17760            .diagnostics
17761            .inline
17762            .max_severity
17763            .unwrap_or(self.diagnostics_max_severity);
17764
17765        if !self.inline_diagnostics_enabled()
17766            || !self.show_inline_diagnostics
17767            || max_severity == DiagnosticSeverity::Off
17768        {
17769            self.inline_diagnostics_update = Task::ready(());
17770            self.inline_diagnostics.clear();
17771            return;
17772        }
17773
17774        let debounce_ms = ProjectSettings::get_global(cx)
17775            .diagnostics
17776            .inline
17777            .update_debounce_ms;
17778        let debounce = if debounce && debounce_ms > 0 {
17779            Some(Duration::from_millis(debounce_ms))
17780        } else {
17781            None
17782        };
17783        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17784            if let Some(debounce) = debounce {
17785                cx.background_executor().timer(debounce).await;
17786            }
17787            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17788                editor
17789                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17790                    .ok()
17791            }) else {
17792                return;
17793            };
17794
17795            let new_inline_diagnostics = cx
17796                .background_spawn(async move {
17797                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17798                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17799                        let message = diagnostic_entry
17800                            .diagnostic
17801                            .message
17802                            .split_once('\n')
17803                            .map(|(line, _)| line)
17804                            .map(SharedString::new)
17805                            .unwrap_or_else(|| {
17806                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17807                            });
17808                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17809                        let (Ok(i) | Err(i)) = inline_diagnostics
17810                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17811                        inline_diagnostics.insert(
17812                            i,
17813                            (
17814                                start_anchor,
17815                                InlineDiagnostic {
17816                                    message,
17817                                    group_id: diagnostic_entry.diagnostic.group_id,
17818                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17819                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17820                                    severity: diagnostic_entry.diagnostic.severity,
17821                                },
17822                            ),
17823                        );
17824                    }
17825                    inline_diagnostics
17826                })
17827                .await;
17828
17829            editor
17830                .update(cx, |editor, cx| {
17831                    editor.inline_diagnostics = new_inline_diagnostics;
17832                    cx.notify();
17833                })
17834                .ok();
17835        });
17836    }
17837
17838    fn pull_diagnostics(
17839        &mut self,
17840        buffer_id: Option<BufferId>,
17841        window: &Window,
17842        cx: &mut Context<Self>,
17843    ) -> Option<()> {
17844        if !self.mode().is_full() {
17845            return None;
17846        }
17847        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17848            .diagnostics
17849            .lsp_pull_diagnostics;
17850        if !pull_diagnostics_settings.enabled {
17851            return None;
17852        }
17853        let project = self.project()?.downgrade();
17854        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17855        let mut buffers = self.buffer.read(cx).all_buffers();
17856        if let Some(buffer_id) = buffer_id {
17857            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17858        }
17859
17860        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17861            cx.background_executor().timer(debounce).await;
17862
17863            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17864                buffers
17865                    .into_iter()
17866                    .filter_map(|buffer| {
17867                        project
17868                            .update(cx, |project, cx| {
17869                                project.lsp_store().update(cx, |lsp_store, cx| {
17870                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17871                                })
17872                            })
17873                            .ok()
17874                    })
17875                    .collect::<FuturesUnordered<_>>()
17876            }) else {
17877                return;
17878            };
17879
17880            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17881                match pull_task {
17882                    Ok(()) => {
17883                        if editor
17884                            .update_in(cx, |editor, window, cx| {
17885                                editor.update_diagnostics_state(window, cx);
17886                            })
17887                            .is_err()
17888                        {
17889                            return;
17890                        }
17891                    }
17892                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17893                }
17894            }
17895        });
17896
17897        Some(())
17898    }
17899
17900    pub fn set_selections_from_remote(
17901        &mut self,
17902        selections: Vec<Selection<Anchor>>,
17903        pending_selection: Option<Selection<Anchor>>,
17904        window: &mut Window,
17905        cx: &mut Context<Self>,
17906    ) {
17907        let old_cursor_position = self.selections.newest_anchor().head();
17908        self.selections.change_with(cx, |s| {
17909            s.select_anchors(selections);
17910            if let Some(pending_selection) = pending_selection {
17911                s.set_pending(pending_selection, SelectMode::Character);
17912            } else {
17913                s.clear_pending();
17914            }
17915        });
17916        self.selections_did_change(
17917            false,
17918            &old_cursor_position,
17919            SelectionEffects::default(),
17920            window,
17921            cx,
17922        );
17923    }
17924
17925    pub fn transact(
17926        &mut self,
17927        window: &mut Window,
17928        cx: &mut Context<Self>,
17929        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17930    ) -> Option<TransactionId> {
17931        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17932            this.start_transaction_at(Instant::now(), window, cx);
17933            update(this, window, cx);
17934            this.end_transaction_at(Instant::now(), cx)
17935        })
17936    }
17937
17938    pub fn start_transaction_at(
17939        &mut self,
17940        now: Instant,
17941        window: &mut Window,
17942        cx: &mut Context<Self>,
17943    ) -> Option<TransactionId> {
17944        self.end_selection(window, cx);
17945        if let Some(tx_id) = self
17946            .buffer
17947            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17948        {
17949            self.selection_history
17950                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17951            cx.emit(EditorEvent::TransactionBegun {
17952                transaction_id: tx_id,
17953            });
17954            Some(tx_id)
17955        } else {
17956            None
17957        }
17958    }
17959
17960    pub fn end_transaction_at(
17961        &mut self,
17962        now: Instant,
17963        cx: &mut Context<Self>,
17964    ) -> Option<TransactionId> {
17965        if let Some(transaction_id) = self
17966            .buffer
17967            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17968        {
17969            if let Some((_, end_selections)) =
17970                self.selection_history.transaction_mut(transaction_id)
17971            {
17972                *end_selections = Some(self.selections.disjoint_anchors_arc());
17973            } else {
17974                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17975            }
17976
17977            cx.emit(EditorEvent::Edited { transaction_id });
17978            Some(transaction_id)
17979        } else {
17980            None
17981        }
17982    }
17983
17984    pub fn modify_transaction_selection_history(
17985        &mut self,
17986        transaction_id: TransactionId,
17987        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17988    ) -> bool {
17989        self.selection_history
17990            .transaction_mut(transaction_id)
17991            .map(modify)
17992            .is_some()
17993    }
17994
17995    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17996        if self.selection_mark_mode {
17997            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17998                s.move_with(|_, sel| {
17999                    sel.collapse_to(sel.head(), SelectionGoal::None);
18000                });
18001            })
18002        }
18003        self.selection_mark_mode = true;
18004        cx.notify();
18005    }
18006
18007    pub fn swap_selection_ends(
18008        &mut self,
18009        _: &actions::SwapSelectionEnds,
18010        window: &mut Window,
18011        cx: &mut Context<Self>,
18012    ) {
18013        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18014            s.move_with(|_, sel| {
18015                if sel.start != sel.end {
18016                    sel.reversed = !sel.reversed
18017                }
18018            });
18019        });
18020        self.request_autoscroll(Autoscroll::newest(), cx);
18021        cx.notify();
18022    }
18023
18024    pub fn toggle_focus(
18025        workspace: &mut Workspace,
18026        _: &actions::ToggleFocus,
18027        window: &mut Window,
18028        cx: &mut Context<Workspace>,
18029    ) {
18030        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18031            return;
18032        };
18033        workspace.activate_item(&item, true, true, window, cx);
18034    }
18035
18036    pub fn toggle_fold(
18037        &mut self,
18038        _: &actions::ToggleFold,
18039        window: &mut Window,
18040        cx: &mut Context<Self>,
18041    ) {
18042        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18043            let selection = self.selections.newest::<Point>(cx);
18044
18045            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18046            let range = if selection.is_empty() {
18047                let point = selection.head().to_display_point(&display_map);
18048                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18049                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18050                    .to_point(&display_map);
18051                start..end
18052            } else {
18053                selection.range()
18054            };
18055            if display_map.folds_in_range(range).next().is_some() {
18056                self.unfold_lines(&Default::default(), window, cx)
18057            } else {
18058                self.fold(&Default::default(), window, cx)
18059            }
18060        } else {
18061            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18062            let buffer_ids: HashSet<_> = self
18063                .selections
18064                .disjoint_anchor_ranges()
18065                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18066                .collect();
18067
18068            let should_unfold = buffer_ids
18069                .iter()
18070                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18071
18072            for buffer_id in buffer_ids {
18073                if should_unfold {
18074                    self.unfold_buffer(buffer_id, cx);
18075                } else {
18076                    self.fold_buffer(buffer_id, cx);
18077                }
18078            }
18079        }
18080    }
18081
18082    pub fn toggle_fold_recursive(
18083        &mut self,
18084        _: &actions::ToggleFoldRecursive,
18085        window: &mut Window,
18086        cx: &mut Context<Self>,
18087    ) {
18088        let selection = self.selections.newest::<Point>(cx);
18089
18090        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18091        let range = if selection.is_empty() {
18092            let point = selection.head().to_display_point(&display_map);
18093            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18094            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18095                .to_point(&display_map);
18096            start..end
18097        } else {
18098            selection.range()
18099        };
18100        if display_map.folds_in_range(range).next().is_some() {
18101            self.unfold_recursive(&Default::default(), window, cx)
18102        } else {
18103            self.fold_recursive(&Default::default(), window, cx)
18104        }
18105    }
18106
18107    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18108        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18109            let mut to_fold = Vec::new();
18110            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18111            let selections = self.selections.all_adjusted(cx);
18112
18113            for selection in selections {
18114                let range = selection.range().sorted();
18115                let buffer_start_row = range.start.row;
18116
18117                if range.start.row != range.end.row {
18118                    let mut found = false;
18119                    let mut row = range.start.row;
18120                    while row <= range.end.row {
18121                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18122                        {
18123                            found = true;
18124                            row = crease.range().end.row + 1;
18125                            to_fold.push(crease);
18126                        } else {
18127                            row += 1
18128                        }
18129                    }
18130                    if found {
18131                        continue;
18132                    }
18133                }
18134
18135                for row in (0..=range.start.row).rev() {
18136                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18137                        && crease.range().end.row >= buffer_start_row
18138                    {
18139                        to_fold.push(crease);
18140                        if row <= range.start.row {
18141                            break;
18142                        }
18143                    }
18144                }
18145            }
18146
18147            self.fold_creases(to_fold, true, window, cx);
18148        } else {
18149            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18150            let buffer_ids = self
18151                .selections
18152                .disjoint_anchor_ranges()
18153                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18154                .collect::<HashSet<_>>();
18155            for buffer_id in buffer_ids {
18156                self.fold_buffer(buffer_id, cx);
18157            }
18158        }
18159    }
18160
18161    pub fn toggle_fold_all(
18162        &mut self,
18163        _: &actions::ToggleFoldAll,
18164        window: &mut Window,
18165        cx: &mut Context<Self>,
18166    ) {
18167        if self.buffer.read(cx).is_singleton() {
18168            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18169            let has_folds = display_map
18170                .folds_in_range(0..display_map.buffer_snapshot().len())
18171                .next()
18172                .is_some();
18173
18174            if has_folds {
18175                self.unfold_all(&actions::UnfoldAll, window, cx);
18176            } else {
18177                self.fold_all(&actions::FoldAll, window, cx);
18178            }
18179        } else {
18180            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18181            let should_unfold = buffer_ids
18182                .iter()
18183                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18184
18185            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18186                editor
18187                    .update_in(cx, |editor, _, cx| {
18188                        for buffer_id in buffer_ids {
18189                            if should_unfold {
18190                                editor.unfold_buffer(buffer_id, cx);
18191                            } else {
18192                                editor.fold_buffer(buffer_id, cx);
18193                            }
18194                        }
18195                    })
18196                    .ok();
18197            });
18198        }
18199    }
18200
18201    fn fold_at_level(
18202        &mut self,
18203        fold_at: &FoldAtLevel,
18204        window: &mut Window,
18205        cx: &mut Context<Self>,
18206    ) {
18207        if !self.buffer.read(cx).is_singleton() {
18208            return;
18209        }
18210
18211        let fold_at_level = fold_at.0;
18212        let snapshot = self.buffer.read(cx).snapshot(cx);
18213        let mut to_fold = Vec::new();
18214        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18215
18216        let row_ranges_to_keep: Vec<Range<u32>> = self
18217            .selections
18218            .all::<Point>(cx)
18219            .into_iter()
18220            .map(|sel| sel.start.row..sel.end.row)
18221            .collect();
18222
18223        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18224            while start_row < end_row {
18225                match self
18226                    .snapshot(window, cx)
18227                    .crease_for_buffer_row(MultiBufferRow(start_row))
18228                {
18229                    Some(crease) => {
18230                        let nested_start_row = crease.range().start.row + 1;
18231                        let nested_end_row = crease.range().end.row;
18232
18233                        if current_level < fold_at_level {
18234                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18235                        } else if current_level == fold_at_level {
18236                            // Fold iff there is no selection completely contained within the fold region
18237                            if !row_ranges_to_keep.iter().any(|selection| {
18238                                selection.end >= nested_start_row
18239                                    && selection.start <= nested_end_row
18240                            }) {
18241                                to_fold.push(crease);
18242                            }
18243                        }
18244
18245                        start_row = nested_end_row + 1;
18246                    }
18247                    None => start_row += 1,
18248                }
18249            }
18250        }
18251
18252        self.fold_creases(to_fold, true, window, cx);
18253    }
18254
18255    pub fn fold_at_level_1(
18256        &mut self,
18257        _: &actions::FoldAtLevel1,
18258        window: &mut Window,
18259        cx: &mut Context<Self>,
18260    ) {
18261        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18262    }
18263
18264    pub fn fold_at_level_2(
18265        &mut self,
18266        _: &actions::FoldAtLevel2,
18267        window: &mut Window,
18268        cx: &mut Context<Self>,
18269    ) {
18270        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18271    }
18272
18273    pub fn fold_at_level_3(
18274        &mut self,
18275        _: &actions::FoldAtLevel3,
18276        window: &mut Window,
18277        cx: &mut Context<Self>,
18278    ) {
18279        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18280    }
18281
18282    pub fn fold_at_level_4(
18283        &mut self,
18284        _: &actions::FoldAtLevel4,
18285        window: &mut Window,
18286        cx: &mut Context<Self>,
18287    ) {
18288        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18289    }
18290
18291    pub fn fold_at_level_5(
18292        &mut self,
18293        _: &actions::FoldAtLevel5,
18294        window: &mut Window,
18295        cx: &mut Context<Self>,
18296    ) {
18297        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18298    }
18299
18300    pub fn fold_at_level_6(
18301        &mut self,
18302        _: &actions::FoldAtLevel6,
18303        window: &mut Window,
18304        cx: &mut Context<Self>,
18305    ) {
18306        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18307    }
18308
18309    pub fn fold_at_level_7(
18310        &mut self,
18311        _: &actions::FoldAtLevel7,
18312        window: &mut Window,
18313        cx: &mut Context<Self>,
18314    ) {
18315        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18316    }
18317
18318    pub fn fold_at_level_8(
18319        &mut self,
18320        _: &actions::FoldAtLevel8,
18321        window: &mut Window,
18322        cx: &mut Context<Self>,
18323    ) {
18324        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18325    }
18326
18327    pub fn fold_at_level_9(
18328        &mut self,
18329        _: &actions::FoldAtLevel9,
18330        window: &mut Window,
18331        cx: &mut Context<Self>,
18332    ) {
18333        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18334    }
18335
18336    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18337        if self.buffer.read(cx).is_singleton() {
18338            let mut fold_ranges = Vec::new();
18339            let snapshot = self.buffer.read(cx).snapshot(cx);
18340
18341            for row in 0..snapshot.max_row().0 {
18342                if let Some(foldable_range) = self
18343                    .snapshot(window, cx)
18344                    .crease_for_buffer_row(MultiBufferRow(row))
18345                {
18346                    fold_ranges.push(foldable_range);
18347                }
18348            }
18349
18350            self.fold_creases(fold_ranges, true, window, cx);
18351        } else {
18352            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18353                editor
18354                    .update_in(cx, |editor, _, cx| {
18355                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18356                            editor.fold_buffer(buffer_id, cx);
18357                        }
18358                    })
18359                    .ok();
18360            });
18361        }
18362    }
18363
18364    pub fn fold_function_bodies(
18365        &mut self,
18366        _: &actions::FoldFunctionBodies,
18367        window: &mut Window,
18368        cx: &mut Context<Self>,
18369    ) {
18370        let snapshot = self.buffer.read(cx).snapshot(cx);
18371
18372        let ranges = snapshot
18373            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18374            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18375            .collect::<Vec<_>>();
18376
18377        let creases = ranges
18378            .into_iter()
18379            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18380            .collect();
18381
18382        self.fold_creases(creases, true, window, cx);
18383    }
18384
18385    pub fn fold_recursive(
18386        &mut self,
18387        _: &actions::FoldRecursive,
18388        window: &mut Window,
18389        cx: &mut Context<Self>,
18390    ) {
18391        let mut to_fold = Vec::new();
18392        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18393        let selections = self.selections.all_adjusted(cx);
18394
18395        for selection in selections {
18396            let range = selection.range().sorted();
18397            let buffer_start_row = range.start.row;
18398
18399            if range.start.row != range.end.row {
18400                let mut found = false;
18401                for row in range.start.row..=range.end.row {
18402                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18403                        found = true;
18404                        to_fold.push(crease);
18405                    }
18406                }
18407                if found {
18408                    continue;
18409                }
18410            }
18411
18412            for row in (0..=range.start.row).rev() {
18413                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18414                    if crease.range().end.row >= buffer_start_row {
18415                        to_fold.push(crease);
18416                    } else {
18417                        break;
18418                    }
18419                }
18420            }
18421        }
18422
18423        self.fold_creases(to_fold, true, window, cx);
18424    }
18425
18426    pub fn fold_at(
18427        &mut self,
18428        buffer_row: MultiBufferRow,
18429        window: &mut Window,
18430        cx: &mut Context<Self>,
18431    ) {
18432        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18433
18434        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18435            let autoscroll = self
18436                .selections
18437                .all::<Point>(cx)
18438                .iter()
18439                .any(|selection| crease.range().overlaps(&selection.range()));
18440
18441            self.fold_creases(vec![crease], autoscroll, window, cx);
18442        }
18443    }
18444
18445    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18446        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18447            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18448            let buffer = display_map.buffer_snapshot();
18449            let selections = self.selections.all::<Point>(cx);
18450            let ranges = selections
18451                .iter()
18452                .map(|s| {
18453                    let range = s.display_range(&display_map).sorted();
18454                    let mut start = range.start.to_point(&display_map);
18455                    let mut end = range.end.to_point(&display_map);
18456                    start.column = 0;
18457                    end.column = buffer.line_len(MultiBufferRow(end.row));
18458                    start..end
18459                })
18460                .collect::<Vec<_>>();
18461
18462            self.unfold_ranges(&ranges, true, true, cx);
18463        } else {
18464            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18465            let buffer_ids = self
18466                .selections
18467                .disjoint_anchor_ranges()
18468                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18469                .collect::<HashSet<_>>();
18470            for buffer_id in buffer_ids {
18471                self.unfold_buffer(buffer_id, cx);
18472            }
18473        }
18474    }
18475
18476    pub fn unfold_recursive(
18477        &mut self,
18478        _: &UnfoldRecursive,
18479        _window: &mut Window,
18480        cx: &mut Context<Self>,
18481    ) {
18482        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18483        let selections = self.selections.all::<Point>(cx);
18484        let ranges = selections
18485            .iter()
18486            .map(|s| {
18487                let mut range = s.display_range(&display_map).sorted();
18488                *range.start.column_mut() = 0;
18489                *range.end.column_mut() = display_map.line_len(range.end.row());
18490                let start = range.start.to_point(&display_map);
18491                let end = range.end.to_point(&display_map);
18492                start..end
18493            })
18494            .collect::<Vec<_>>();
18495
18496        self.unfold_ranges(&ranges, true, true, cx);
18497    }
18498
18499    pub fn unfold_at(
18500        &mut self,
18501        buffer_row: MultiBufferRow,
18502        _window: &mut Window,
18503        cx: &mut Context<Self>,
18504    ) {
18505        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18506
18507        let intersection_range = Point::new(buffer_row.0, 0)
18508            ..Point::new(
18509                buffer_row.0,
18510                display_map.buffer_snapshot().line_len(buffer_row),
18511            );
18512
18513        let autoscroll = self
18514            .selections
18515            .all::<Point>(cx)
18516            .iter()
18517            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18518
18519        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18520    }
18521
18522    pub fn unfold_all(
18523        &mut self,
18524        _: &actions::UnfoldAll,
18525        _window: &mut Window,
18526        cx: &mut Context<Self>,
18527    ) {
18528        if self.buffer.read(cx).is_singleton() {
18529            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18530            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18531        } else {
18532            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18533                editor
18534                    .update(cx, |editor, cx| {
18535                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18536                            editor.unfold_buffer(buffer_id, cx);
18537                        }
18538                    })
18539                    .ok();
18540            });
18541        }
18542    }
18543
18544    pub fn fold_selected_ranges(
18545        &mut self,
18546        _: &FoldSelectedRanges,
18547        window: &mut Window,
18548        cx: &mut Context<Self>,
18549    ) {
18550        let selections = self.selections.all_adjusted(cx);
18551        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18552        let ranges = selections
18553            .into_iter()
18554            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18555            .collect::<Vec<_>>();
18556        self.fold_creases(ranges, true, window, cx);
18557    }
18558
18559    pub fn fold_ranges<T: ToOffset + Clone>(
18560        &mut self,
18561        ranges: Vec<Range<T>>,
18562        auto_scroll: bool,
18563        window: &mut Window,
18564        cx: &mut Context<Self>,
18565    ) {
18566        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18567        let ranges = ranges
18568            .into_iter()
18569            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18570            .collect::<Vec<_>>();
18571        self.fold_creases(ranges, auto_scroll, window, cx);
18572    }
18573
18574    pub fn fold_creases<T: ToOffset + Clone>(
18575        &mut self,
18576        creases: Vec<Crease<T>>,
18577        auto_scroll: bool,
18578        _window: &mut Window,
18579        cx: &mut Context<Self>,
18580    ) {
18581        if creases.is_empty() {
18582            return;
18583        }
18584
18585        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18586
18587        if auto_scroll {
18588            self.request_autoscroll(Autoscroll::fit(), cx);
18589        }
18590
18591        cx.notify();
18592
18593        self.scrollbar_marker_state.dirty = true;
18594        self.folds_did_change(cx);
18595    }
18596
18597    /// Removes any folds whose ranges intersect any of the given ranges.
18598    pub fn unfold_ranges<T: ToOffset + Clone>(
18599        &mut self,
18600        ranges: &[Range<T>],
18601        inclusive: bool,
18602        auto_scroll: bool,
18603        cx: &mut Context<Self>,
18604    ) {
18605        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18606            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18607        });
18608        self.folds_did_change(cx);
18609    }
18610
18611    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18612        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18613            return;
18614        }
18615        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18616        self.display_map.update(cx, |display_map, cx| {
18617            display_map.fold_buffers([buffer_id], cx)
18618        });
18619        cx.emit(EditorEvent::BufferFoldToggled {
18620            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18621            folded: true,
18622        });
18623        cx.notify();
18624    }
18625
18626    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18627        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18628            return;
18629        }
18630        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18631        self.display_map.update(cx, |display_map, cx| {
18632            display_map.unfold_buffers([buffer_id], cx);
18633        });
18634        cx.emit(EditorEvent::BufferFoldToggled {
18635            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18636            folded: false,
18637        });
18638        cx.notify();
18639    }
18640
18641    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18642        self.display_map.read(cx).is_buffer_folded(buffer)
18643    }
18644
18645    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18646        self.display_map.read(cx).folded_buffers()
18647    }
18648
18649    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18650        self.display_map.update(cx, |display_map, cx| {
18651            display_map.disable_header_for_buffer(buffer_id, cx);
18652        });
18653        cx.notify();
18654    }
18655
18656    /// Removes any folds with the given ranges.
18657    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18658        &mut self,
18659        ranges: &[Range<T>],
18660        type_id: TypeId,
18661        auto_scroll: bool,
18662        cx: &mut Context<Self>,
18663    ) {
18664        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18665            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18666        });
18667        self.folds_did_change(cx);
18668    }
18669
18670    fn remove_folds_with<T: ToOffset + Clone>(
18671        &mut self,
18672        ranges: &[Range<T>],
18673        auto_scroll: bool,
18674        cx: &mut Context<Self>,
18675        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18676    ) {
18677        if ranges.is_empty() {
18678            return;
18679        }
18680
18681        let mut buffers_affected = HashSet::default();
18682        let multi_buffer = self.buffer().read(cx);
18683        for range in ranges {
18684            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18685                buffers_affected.insert(buffer.read(cx).remote_id());
18686            };
18687        }
18688
18689        self.display_map.update(cx, update);
18690
18691        if auto_scroll {
18692            self.request_autoscroll(Autoscroll::fit(), cx);
18693        }
18694
18695        cx.notify();
18696        self.scrollbar_marker_state.dirty = true;
18697        self.active_indent_guides_state.dirty = true;
18698    }
18699
18700    pub fn update_renderer_widths(
18701        &mut self,
18702        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18703        cx: &mut Context<Self>,
18704    ) -> bool {
18705        self.display_map
18706            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18707    }
18708
18709    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18710        self.display_map.read(cx).fold_placeholder.clone()
18711    }
18712
18713    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18714        self.buffer.update(cx, |buffer, cx| {
18715            buffer.set_all_diff_hunks_expanded(cx);
18716        });
18717    }
18718
18719    pub fn expand_all_diff_hunks(
18720        &mut self,
18721        _: &ExpandAllDiffHunks,
18722        _window: &mut Window,
18723        cx: &mut Context<Self>,
18724    ) {
18725        self.buffer.update(cx, |buffer, cx| {
18726            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18727        });
18728    }
18729
18730    pub fn toggle_selected_diff_hunks(
18731        &mut self,
18732        _: &ToggleSelectedDiffHunks,
18733        _window: &mut Window,
18734        cx: &mut Context<Self>,
18735    ) {
18736        let ranges: Vec<_> = self
18737            .selections
18738            .disjoint_anchors()
18739            .iter()
18740            .map(|s| s.range())
18741            .collect();
18742        self.toggle_diff_hunks_in_ranges(ranges, cx);
18743    }
18744
18745    pub fn diff_hunks_in_ranges<'a>(
18746        &'a self,
18747        ranges: &'a [Range<Anchor>],
18748        buffer: &'a MultiBufferSnapshot,
18749    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18750        ranges.iter().flat_map(move |range| {
18751            let end_excerpt_id = range.end.excerpt_id;
18752            let range = range.to_point(buffer);
18753            let mut peek_end = range.end;
18754            if range.end.row < buffer.max_row().0 {
18755                peek_end = Point::new(range.end.row + 1, 0);
18756            }
18757            buffer
18758                .diff_hunks_in_range(range.start..peek_end)
18759                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18760        })
18761    }
18762
18763    pub fn has_stageable_diff_hunks_in_ranges(
18764        &self,
18765        ranges: &[Range<Anchor>],
18766        snapshot: &MultiBufferSnapshot,
18767    ) -> bool {
18768        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18769        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18770    }
18771
18772    pub fn toggle_staged_selected_diff_hunks(
18773        &mut self,
18774        _: &::git::ToggleStaged,
18775        _: &mut Window,
18776        cx: &mut Context<Self>,
18777    ) {
18778        let snapshot = self.buffer.read(cx).snapshot(cx);
18779        let ranges: Vec<_> = self
18780            .selections
18781            .disjoint_anchors()
18782            .iter()
18783            .map(|s| s.range())
18784            .collect();
18785        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18786        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18787    }
18788
18789    pub fn set_render_diff_hunk_controls(
18790        &mut self,
18791        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18792        cx: &mut Context<Self>,
18793    ) {
18794        self.render_diff_hunk_controls = render_diff_hunk_controls;
18795        cx.notify();
18796    }
18797
18798    pub fn stage_and_next(
18799        &mut self,
18800        _: &::git::StageAndNext,
18801        window: &mut Window,
18802        cx: &mut Context<Self>,
18803    ) {
18804        self.do_stage_or_unstage_and_next(true, window, cx);
18805    }
18806
18807    pub fn unstage_and_next(
18808        &mut self,
18809        _: &::git::UnstageAndNext,
18810        window: &mut Window,
18811        cx: &mut Context<Self>,
18812    ) {
18813        self.do_stage_or_unstage_and_next(false, window, cx);
18814    }
18815
18816    pub fn stage_or_unstage_diff_hunks(
18817        &mut self,
18818        stage: bool,
18819        ranges: Vec<Range<Anchor>>,
18820        cx: &mut Context<Self>,
18821    ) {
18822        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18823        cx.spawn(async move |this, cx| {
18824            task.await?;
18825            this.update(cx, |this, cx| {
18826                let snapshot = this.buffer.read(cx).snapshot(cx);
18827                let chunk_by = this
18828                    .diff_hunks_in_ranges(&ranges, &snapshot)
18829                    .chunk_by(|hunk| hunk.buffer_id);
18830                for (buffer_id, hunks) in &chunk_by {
18831                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18832                }
18833            })
18834        })
18835        .detach_and_log_err(cx);
18836    }
18837
18838    fn save_buffers_for_ranges_if_needed(
18839        &mut self,
18840        ranges: &[Range<Anchor>],
18841        cx: &mut Context<Editor>,
18842    ) -> Task<Result<()>> {
18843        let multibuffer = self.buffer.read(cx);
18844        let snapshot = multibuffer.read(cx);
18845        let buffer_ids: HashSet<_> = ranges
18846            .iter()
18847            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18848            .collect();
18849        drop(snapshot);
18850
18851        let mut buffers = HashSet::default();
18852        for buffer_id in buffer_ids {
18853            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18854                let buffer = buffer_entity.read(cx);
18855                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18856                {
18857                    buffers.insert(buffer_entity);
18858                }
18859            }
18860        }
18861
18862        if let Some(project) = &self.project {
18863            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18864        } else {
18865            Task::ready(Ok(()))
18866        }
18867    }
18868
18869    fn do_stage_or_unstage_and_next(
18870        &mut self,
18871        stage: bool,
18872        window: &mut Window,
18873        cx: &mut Context<Self>,
18874    ) {
18875        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18876
18877        if ranges.iter().any(|range| range.start != range.end) {
18878            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18879            return;
18880        }
18881
18882        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18883        let snapshot = self.snapshot(window, cx);
18884        let position = self.selections.newest::<Point>(cx).head();
18885        let mut row = snapshot
18886            .buffer_snapshot()
18887            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18888            .find(|hunk| hunk.row_range.start.0 > position.row)
18889            .map(|hunk| hunk.row_range.start);
18890
18891        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18892        // Outside of the project diff editor, wrap around to the beginning.
18893        if !all_diff_hunks_expanded {
18894            row = row.or_else(|| {
18895                snapshot
18896                    .buffer_snapshot()
18897                    .diff_hunks_in_range(Point::zero()..position)
18898                    .find(|hunk| hunk.row_range.end.0 < position.row)
18899                    .map(|hunk| hunk.row_range.start)
18900            });
18901        }
18902
18903        if let Some(row) = row {
18904            let destination = Point::new(row.0, 0);
18905            let autoscroll = Autoscroll::center();
18906
18907            self.unfold_ranges(&[destination..destination], false, false, cx);
18908            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18909                s.select_ranges([destination..destination]);
18910            });
18911        }
18912    }
18913
18914    fn do_stage_or_unstage(
18915        &self,
18916        stage: bool,
18917        buffer_id: BufferId,
18918        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18919        cx: &mut App,
18920    ) -> Option<()> {
18921        let project = self.project()?;
18922        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18923        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18924        let buffer_snapshot = buffer.read(cx).snapshot();
18925        let file_exists = buffer_snapshot
18926            .file()
18927            .is_some_and(|file| file.disk_state().exists());
18928        diff.update(cx, |diff, cx| {
18929            diff.stage_or_unstage_hunks(
18930                stage,
18931                &hunks
18932                    .map(|hunk| buffer_diff::DiffHunk {
18933                        buffer_range: hunk.buffer_range,
18934                        diff_base_byte_range: hunk.diff_base_byte_range,
18935                        secondary_status: hunk.secondary_status,
18936                        range: Point::zero()..Point::zero(), // unused
18937                    })
18938                    .collect::<Vec<_>>(),
18939                &buffer_snapshot,
18940                file_exists,
18941                cx,
18942            )
18943        });
18944        None
18945    }
18946
18947    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18948        let ranges: Vec<_> = self
18949            .selections
18950            .disjoint_anchors()
18951            .iter()
18952            .map(|s| s.range())
18953            .collect();
18954        self.buffer
18955            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18956    }
18957
18958    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18959        self.buffer.update(cx, |buffer, cx| {
18960            let ranges = vec![Anchor::min()..Anchor::max()];
18961            if !buffer.all_diff_hunks_expanded()
18962                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18963            {
18964                buffer.collapse_diff_hunks(ranges, cx);
18965                true
18966            } else {
18967                false
18968            }
18969        })
18970    }
18971
18972    fn toggle_diff_hunks_in_ranges(
18973        &mut self,
18974        ranges: Vec<Range<Anchor>>,
18975        cx: &mut Context<Editor>,
18976    ) {
18977        self.buffer.update(cx, |buffer, cx| {
18978            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18979            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18980        })
18981    }
18982
18983    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18984        self.buffer.update(cx, |buffer, cx| {
18985            let snapshot = buffer.snapshot(cx);
18986            let excerpt_id = range.end.excerpt_id;
18987            let point_range = range.to_point(&snapshot);
18988            let expand = !buffer.single_hunk_is_expanded(range, cx);
18989            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18990        })
18991    }
18992
18993    pub(crate) fn apply_all_diff_hunks(
18994        &mut self,
18995        _: &ApplyAllDiffHunks,
18996        window: &mut Window,
18997        cx: &mut Context<Self>,
18998    ) {
18999        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19000
19001        let buffers = self.buffer.read(cx).all_buffers();
19002        for branch_buffer in buffers {
19003            branch_buffer.update(cx, |branch_buffer, cx| {
19004                branch_buffer.merge_into_base(Vec::new(), cx);
19005            });
19006        }
19007
19008        if let Some(project) = self.project.clone() {
19009            self.save(
19010                SaveOptions {
19011                    format: true,
19012                    autosave: false,
19013                },
19014                project,
19015                window,
19016                cx,
19017            )
19018            .detach_and_log_err(cx);
19019        }
19020    }
19021
19022    pub(crate) fn apply_selected_diff_hunks(
19023        &mut self,
19024        _: &ApplyDiffHunk,
19025        window: &mut Window,
19026        cx: &mut Context<Self>,
19027    ) {
19028        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19029        let snapshot = self.snapshot(window, cx);
19030        let hunks = snapshot.hunks_for_ranges(
19031            self.selections
19032                .all(cx)
19033                .into_iter()
19034                .map(|selection| selection.range()),
19035        );
19036        let mut ranges_by_buffer = HashMap::default();
19037        self.transact(window, cx, |editor, _window, cx| {
19038            for hunk in hunks {
19039                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19040                    ranges_by_buffer
19041                        .entry(buffer.clone())
19042                        .or_insert_with(Vec::new)
19043                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19044                }
19045            }
19046
19047            for (buffer, ranges) in ranges_by_buffer {
19048                buffer.update(cx, |buffer, cx| {
19049                    buffer.merge_into_base(ranges, cx);
19050                });
19051            }
19052        });
19053
19054        if let Some(project) = self.project.clone() {
19055            self.save(
19056                SaveOptions {
19057                    format: true,
19058                    autosave: false,
19059                },
19060                project,
19061                window,
19062                cx,
19063            )
19064            .detach_and_log_err(cx);
19065        }
19066    }
19067
19068    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19069        if hovered != self.gutter_hovered {
19070            self.gutter_hovered = hovered;
19071            cx.notify();
19072        }
19073    }
19074
19075    pub fn insert_blocks(
19076        &mut self,
19077        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19078        autoscroll: Option<Autoscroll>,
19079        cx: &mut Context<Self>,
19080    ) -> Vec<CustomBlockId> {
19081        let blocks = self
19082            .display_map
19083            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19084        if let Some(autoscroll) = autoscroll {
19085            self.request_autoscroll(autoscroll, cx);
19086        }
19087        cx.notify();
19088        blocks
19089    }
19090
19091    pub fn resize_blocks(
19092        &mut self,
19093        heights: HashMap<CustomBlockId, u32>,
19094        autoscroll: Option<Autoscroll>,
19095        cx: &mut Context<Self>,
19096    ) {
19097        self.display_map
19098            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19099        if let Some(autoscroll) = autoscroll {
19100            self.request_autoscroll(autoscroll, cx);
19101        }
19102        cx.notify();
19103    }
19104
19105    pub fn replace_blocks(
19106        &mut self,
19107        renderers: HashMap<CustomBlockId, RenderBlock>,
19108        autoscroll: Option<Autoscroll>,
19109        cx: &mut Context<Self>,
19110    ) {
19111        self.display_map
19112            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19113        if let Some(autoscroll) = autoscroll {
19114            self.request_autoscroll(autoscroll, cx);
19115        }
19116        cx.notify();
19117    }
19118
19119    pub fn remove_blocks(
19120        &mut self,
19121        block_ids: HashSet<CustomBlockId>,
19122        autoscroll: Option<Autoscroll>,
19123        cx: &mut Context<Self>,
19124    ) {
19125        self.display_map.update(cx, |display_map, cx| {
19126            display_map.remove_blocks(block_ids, cx)
19127        });
19128        if let Some(autoscroll) = autoscroll {
19129            self.request_autoscroll(autoscroll, cx);
19130        }
19131        cx.notify();
19132    }
19133
19134    pub fn row_for_block(
19135        &self,
19136        block_id: CustomBlockId,
19137        cx: &mut Context<Self>,
19138    ) -> Option<DisplayRow> {
19139        self.display_map
19140            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19141    }
19142
19143    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19144        self.focused_block = Some(focused_block);
19145    }
19146
19147    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19148        self.focused_block.take()
19149    }
19150
19151    pub fn insert_creases(
19152        &mut self,
19153        creases: impl IntoIterator<Item = Crease<Anchor>>,
19154        cx: &mut Context<Self>,
19155    ) -> Vec<CreaseId> {
19156        self.display_map
19157            .update(cx, |map, cx| map.insert_creases(creases, cx))
19158    }
19159
19160    pub fn remove_creases(
19161        &mut self,
19162        ids: impl IntoIterator<Item = CreaseId>,
19163        cx: &mut Context<Self>,
19164    ) -> Vec<(CreaseId, Range<Anchor>)> {
19165        self.display_map
19166            .update(cx, |map, cx| map.remove_creases(ids, cx))
19167    }
19168
19169    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19170        self.display_map
19171            .update(cx, |map, cx| map.snapshot(cx))
19172            .longest_row()
19173    }
19174
19175    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19176        self.display_map
19177            .update(cx, |map, cx| map.snapshot(cx))
19178            .max_point()
19179    }
19180
19181    pub fn text(&self, cx: &App) -> String {
19182        self.buffer.read(cx).read(cx).text()
19183    }
19184
19185    pub fn is_empty(&self, cx: &App) -> bool {
19186        self.buffer.read(cx).read(cx).is_empty()
19187    }
19188
19189    pub fn text_option(&self, cx: &App) -> Option<String> {
19190        let text = self.text(cx);
19191        let text = text.trim();
19192
19193        if text.is_empty() {
19194            return None;
19195        }
19196
19197        Some(text.to_string())
19198    }
19199
19200    pub fn set_text(
19201        &mut self,
19202        text: impl Into<Arc<str>>,
19203        window: &mut Window,
19204        cx: &mut Context<Self>,
19205    ) {
19206        self.transact(window, cx, |this, _, cx| {
19207            this.buffer
19208                .read(cx)
19209                .as_singleton()
19210                .expect("you can only call set_text on editors for singleton buffers")
19211                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19212        });
19213    }
19214
19215    pub fn display_text(&self, cx: &mut App) -> String {
19216        self.display_map
19217            .update(cx, |map, cx| map.snapshot(cx))
19218            .text()
19219    }
19220
19221    fn create_minimap(
19222        &self,
19223        minimap_settings: MinimapSettings,
19224        window: &mut Window,
19225        cx: &mut Context<Self>,
19226    ) -> Option<Entity<Self>> {
19227        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19228            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19229    }
19230
19231    fn initialize_new_minimap(
19232        &self,
19233        minimap_settings: MinimapSettings,
19234        window: &mut Window,
19235        cx: &mut Context<Self>,
19236    ) -> Entity<Self> {
19237        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19238
19239        let mut minimap = Editor::new_internal(
19240            EditorMode::Minimap {
19241                parent: cx.weak_entity(),
19242            },
19243            self.buffer.clone(),
19244            None,
19245            Some(self.display_map.clone()),
19246            window,
19247            cx,
19248        );
19249        minimap.scroll_manager.clone_state(&self.scroll_manager);
19250        minimap.set_text_style_refinement(TextStyleRefinement {
19251            font_size: Some(MINIMAP_FONT_SIZE),
19252            font_weight: Some(MINIMAP_FONT_WEIGHT),
19253            ..Default::default()
19254        });
19255        minimap.update_minimap_configuration(minimap_settings, cx);
19256        cx.new(|_| minimap)
19257    }
19258
19259    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19260        let current_line_highlight = minimap_settings
19261            .current_line_highlight
19262            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19263        self.set_current_line_highlight(Some(current_line_highlight));
19264    }
19265
19266    pub fn minimap(&self) -> Option<&Entity<Self>> {
19267        self.minimap
19268            .as_ref()
19269            .filter(|_| self.minimap_visibility.visible())
19270    }
19271
19272    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19273        let mut wrap_guides = smallvec![];
19274
19275        if self.show_wrap_guides == Some(false) {
19276            return wrap_guides;
19277        }
19278
19279        let settings = self.buffer.read(cx).language_settings(cx);
19280        if settings.show_wrap_guides {
19281            match self.soft_wrap_mode(cx) {
19282                SoftWrap::Column(soft_wrap) => {
19283                    wrap_guides.push((soft_wrap as usize, true));
19284                }
19285                SoftWrap::Bounded(soft_wrap) => {
19286                    wrap_guides.push((soft_wrap as usize, true));
19287                }
19288                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19289            }
19290            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19291        }
19292
19293        wrap_guides
19294    }
19295
19296    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19297        let settings = self.buffer.read(cx).language_settings(cx);
19298        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19299        match mode {
19300            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19301                SoftWrap::None
19302            }
19303            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19304            language_settings::SoftWrap::PreferredLineLength => {
19305                SoftWrap::Column(settings.preferred_line_length)
19306            }
19307            language_settings::SoftWrap::Bounded => {
19308                SoftWrap::Bounded(settings.preferred_line_length)
19309            }
19310        }
19311    }
19312
19313    pub fn set_soft_wrap_mode(
19314        &mut self,
19315        mode: language_settings::SoftWrap,
19316
19317        cx: &mut Context<Self>,
19318    ) {
19319        self.soft_wrap_mode_override = Some(mode);
19320        cx.notify();
19321    }
19322
19323    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19324        self.hard_wrap = hard_wrap;
19325        cx.notify();
19326    }
19327
19328    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19329        self.text_style_refinement = Some(style);
19330    }
19331
19332    /// called by the Element so we know what style we were most recently rendered with.
19333    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19334        // We intentionally do not inform the display map about the minimap style
19335        // so that wrapping is not recalculated and stays consistent for the editor
19336        // and its linked minimap.
19337        if !self.mode.is_minimap() {
19338            let font = style.text.font();
19339            let font_size = style.text.font_size.to_pixels(window.rem_size());
19340            let display_map = self
19341                .placeholder_display_map
19342                .as_ref()
19343                .filter(|_| self.is_empty(cx))
19344                .unwrap_or(&self.display_map);
19345
19346            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19347        }
19348        self.style = Some(style);
19349    }
19350
19351    pub fn style(&self) -> Option<&EditorStyle> {
19352        self.style.as_ref()
19353    }
19354
19355    // Called by the element. This method is not designed to be called outside of the editor
19356    // element's layout code because it does not notify when rewrapping is computed synchronously.
19357    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19358        if self.is_empty(cx) {
19359            self.placeholder_display_map
19360                .as_ref()
19361                .map_or(false, |display_map| {
19362                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19363                })
19364        } else {
19365            self.display_map
19366                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19367        }
19368    }
19369
19370    pub fn set_soft_wrap(&mut self) {
19371        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19372    }
19373
19374    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19375        if self.soft_wrap_mode_override.is_some() {
19376            self.soft_wrap_mode_override.take();
19377        } else {
19378            let soft_wrap = match self.soft_wrap_mode(cx) {
19379                SoftWrap::GitDiff => return,
19380                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19381                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19382                    language_settings::SoftWrap::None
19383                }
19384            };
19385            self.soft_wrap_mode_override = Some(soft_wrap);
19386        }
19387        cx.notify();
19388    }
19389
19390    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19391        let Some(workspace) = self.workspace() else {
19392            return;
19393        };
19394        let fs = workspace.read(cx).app_state().fs.clone();
19395        let current_show = TabBarSettings::get_global(cx).show;
19396        update_settings_file(fs, cx, move |setting, _| {
19397            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19398        });
19399    }
19400
19401    pub fn toggle_indent_guides(
19402        &mut self,
19403        _: &ToggleIndentGuides,
19404        _: &mut Window,
19405        cx: &mut Context<Self>,
19406    ) {
19407        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19408            self.buffer
19409                .read(cx)
19410                .language_settings(cx)
19411                .indent_guides
19412                .enabled
19413        });
19414        self.show_indent_guides = Some(!currently_enabled);
19415        cx.notify();
19416    }
19417
19418    fn should_show_indent_guides(&self) -> Option<bool> {
19419        self.show_indent_guides
19420    }
19421
19422    pub fn toggle_line_numbers(
19423        &mut self,
19424        _: &ToggleLineNumbers,
19425        _: &mut Window,
19426        cx: &mut Context<Self>,
19427    ) {
19428        let mut editor_settings = EditorSettings::get_global(cx).clone();
19429        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19430        EditorSettings::override_global(editor_settings, cx);
19431    }
19432
19433    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19434        if let Some(show_line_numbers) = self.show_line_numbers {
19435            return show_line_numbers;
19436        }
19437        EditorSettings::get_global(cx).gutter.line_numbers
19438    }
19439
19440    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19441        self.use_relative_line_numbers
19442            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19443    }
19444
19445    pub fn toggle_relative_line_numbers(
19446        &mut self,
19447        _: &ToggleRelativeLineNumbers,
19448        _: &mut Window,
19449        cx: &mut Context<Self>,
19450    ) {
19451        let is_relative = self.should_use_relative_line_numbers(cx);
19452        self.set_relative_line_number(Some(!is_relative), cx)
19453    }
19454
19455    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19456        self.use_relative_line_numbers = is_relative;
19457        cx.notify();
19458    }
19459
19460    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19461        self.show_gutter = show_gutter;
19462        cx.notify();
19463    }
19464
19465    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19466        self.show_scrollbars = ScrollbarAxes {
19467            horizontal: show,
19468            vertical: show,
19469        };
19470        cx.notify();
19471    }
19472
19473    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19474        self.show_scrollbars.vertical = show;
19475        cx.notify();
19476    }
19477
19478    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19479        self.show_scrollbars.horizontal = show;
19480        cx.notify();
19481    }
19482
19483    pub fn set_minimap_visibility(
19484        &mut self,
19485        minimap_visibility: MinimapVisibility,
19486        window: &mut Window,
19487        cx: &mut Context<Self>,
19488    ) {
19489        if self.minimap_visibility != minimap_visibility {
19490            if minimap_visibility.visible() && self.minimap.is_none() {
19491                let minimap_settings = EditorSettings::get_global(cx).minimap;
19492                self.minimap =
19493                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19494            }
19495            self.minimap_visibility = minimap_visibility;
19496            cx.notify();
19497        }
19498    }
19499
19500    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19501        self.set_show_scrollbars(false, cx);
19502        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19503    }
19504
19505    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19506        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19507    }
19508
19509    /// Normally the text in full mode and auto height editors is padded on the
19510    /// left side by roughly half a character width for improved hit testing.
19511    ///
19512    /// Use this method to disable this for cases where this is not wanted (e.g.
19513    /// if you want to align the editor text with some other text above or below)
19514    /// or if you want to add this padding to single-line editors.
19515    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19516        self.offset_content = offset_content;
19517        cx.notify();
19518    }
19519
19520    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19521        self.show_line_numbers = Some(show_line_numbers);
19522        cx.notify();
19523    }
19524
19525    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19526        self.disable_expand_excerpt_buttons = true;
19527        cx.notify();
19528    }
19529
19530    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19531        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19532        cx.notify();
19533    }
19534
19535    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19536        self.show_code_actions = Some(show_code_actions);
19537        cx.notify();
19538    }
19539
19540    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19541        self.show_runnables = Some(show_runnables);
19542        cx.notify();
19543    }
19544
19545    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19546        self.show_breakpoints = Some(show_breakpoints);
19547        cx.notify();
19548    }
19549
19550    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19551        if self.display_map.read(cx).masked != masked {
19552            self.display_map.update(cx, |map, _| map.masked = masked);
19553        }
19554        cx.notify()
19555    }
19556
19557    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19558        self.show_wrap_guides = Some(show_wrap_guides);
19559        cx.notify();
19560    }
19561
19562    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19563        self.show_indent_guides = Some(show_indent_guides);
19564        cx.notify();
19565    }
19566
19567    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19568        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19569            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19570                && let Some(dir) = file.abs_path(cx).parent()
19571            {
19572                return Some(dir.to_owned());
19573            }
19574        }
19575
19576        None
19577    }
19578
19579    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19580        self.active_excerpt(cx)?
19581            .1
19582            .read(cx)
19583            .file()
19584            .and_then(|f| f.as_local())
19585    }
19586
19587    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19588        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19589            let buffer = buffer.read(cx);
19590            if let Some(project_path) = buffer.project_path(cx) {
19591                let project = self.project()?.read(cx);
19592                project.absolute_path(&project_path, cx)
19593            } else {
19594                buffer
19595                    .file()
19596                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19597            }
19598        })
19599    }
19600
19601    pub fn reveal_in_finder(
19602        &mut self,
19603        _: &RevealInFileManager,
19604        _window: &mut Window,
19605        cx: &mut Context<Self>,
19606    ) {
19607        if let Some(target) = self.target_file(cx) {
19608            cx.reveal_path(&target.abs_path(cx));
19609        }
19610    }
19611
19612    pub fn copy_path(
19613        &mut self,
19614        _: &zed_actions::workspace::CopyPath,
19615        _window: &mut Window,
19616        cx: &mut Context<Self>,
19617    ) {
19618        if let Some(path) = self.target_file_abs_path(cx)
19619            && let Some(path) = path.to_str()
19620        {
19621            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19622        } else {
19623            cx.propagate();
19624        }
19625    }
19626
19627    pub fn copy_relative_path(
19628        &mut self,
19629        _: &zed_actions::workspace::CopyRelativePath,
19630        _window: &mut Window,
19631        cx: &mut Context<Self>,
19632    ) {
19633        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19634            let project = self.project()?.read(cx);
19635            let path = buffer.read(cx).file()?.path();
19636            let path = path.display(project.path_style(cx));
19637            Some(path)
19638        }) {
19639            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19640        } else {
19641            cx.propagate();
19642        }
19643    }
19644
19645    /// Returns the project path for the editor's buffer, if any buffer is
19646    /// opened in the editor.
19647    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19648        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19649            buffer.read(cx).project_path(cx)
19650        } else {
19651            None
19652        }
19653    }
19654
19655    // Returns true if the editor handled a go-to-line request
19656    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19657        maybe!({
19658            let breakpoint_store = self.breakpoint_store.as_ref()?;
19659
19660            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19661            else {
19662                self.clear_row_highlights::<ActiveDebugLine>();
19663                return None;
19664            };
19665
19666            let position = active_stack_frame.position;
19667            let buffer_id = position.buffer_id?;
19668            let snapshot = self
19669                .project
19670                .as_ref()?
19671                .read(cx)
19672                .buffer_for_id(buffer_id, cx)?
19673                .read(cx)
19674                .snapshot();
19675
19676            let mut handled = false;
19677            for (id, ExcerptRange { context, .. }) in
19678                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19679            {
19680                if context.start.cmp(&position, &snapshot).is_ge()
19681                    || context.end.cmp(&position, &snapshot).is_lt()
19682                {
19683                    continue;
19684                }
19685                let snapshot = self.buffer.read(cx).snapshot(cx);
19686                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19687
19688                handled = true;
19689                self.clear_row_highlights::<ActiveDebugLine>();
19690
19691                self.go_to_line::<ActiveDebugLine>(
19692                    multibuffer_anchor,
19693                    Some(cx.theme().colors().editor_debugger_active_line_background),
19694                    window,
19695                    cx,
19696                );
19697
19698                cx.notify();
19699            }
19700
19701            handled.then_some(())
19702        })
19703        .is_some()
19704    }
19705
19706    pub fn copy_file_name_without_extension(
19707        &mut self,
19708        _: &CopyFileNameWithoutExtension,
19709        _: &mut Window,
19710        cx: &mut Context<Self>,
19711    ) {
19712        if let Some(file) = self.target_file(cx)
19713            && let Some(file_stem) = file.path().file_stem()
19714        {
19715            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19716        }
19717    }
19718
19719    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19720        if let Some(file) = self.target_file(cx)
19721            && let Some(name) = file.path().file_name()
19722        {
19723            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19724        }
19725    }
19726
19727    pub fn toggle_git_blame(
19728        &mut self,
19729        _: &::git::Blame,
19730        window: &mut Window,
19731        cx: &mut Context<Self>,
19732    ) {
19733        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19734
19735        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19736            self.start_git_blame(true, window, cx);
19737        }
19738
19739        cx.notify();
19740    }
19741
19742    pub fn toggle_git_blame_inline(
19743        &mut self,
19744        _: &ToggleGitBlameInline,
19745        window: &mut Window,
19746        cx: &mut Context<Self>,
19747    ) {
19748        self.toggle_git_blame_inline_internal(true, window, cx);
19749        cx.notify();
19750    }
19751
19752    pub fn open_git_blame_commit(
19753        &mut self,
19754        _: &OpenGitBlameCommit,
19755        window: &mut Window,
19756        cx: &mut Context<Self>,
19757    ) {
19758        self.open_git_blame_commit_internal(window, cx);
19759    }
19760
19761    fn open_git_blame_commit_internal(
19762        &mut self,
19763        window: &mut Window,
19764        cx: &mut Context<Self>,
19765    ) -> Option<()> {
19766        let blame = self.blame.as_ref()?;
19767        let snapshot = self.snapshot(window, cx);
19768        let cursor = self.selections.newest::<Point>(cx).head();
19769        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19770        let (_, blame_entry) = blame
19771            .update(cx, |blame, cx| {
19772                blame
19773                    .blame_for_rows(
19774                        &[RowInfo {
19775                            buffer_id: Some(buffer.remote_id()),
19776                            buffer_row: Some(point.row),
19777                            ..Default::default()
19778                        }],
19779                        cx,
19780                    )
19781                    .next()
19782            })
19783            .flatten()?;
19784        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19785        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19786        let workspace = self.workspace()?.downgrade();
19787        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19788        None
19789    }
19790
19791    pub fn git_blame_inline_enabled(&self) -> bool {
19792        self.git_blame_inline_enabled
19793    }
19794
19795    pub fn toggle_selection_menu(
19796        &mut self,
19797        _: &ToggleSelectionMenu,
19798        _: &mut Window,
19799        cx: &mut Context<Self>,
19800    ) {
19801        self.show_selection_menu = self
19802            .show_selection_menu
19803            .map(|show_selections_menu| !show_selections_menu)
19804            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19805
19806        cx.notify();
19807    }
19808
19809    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19810        self.show_selection_menu
19811            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19812    }
19813
19814    fn start_git_blame(
19815        &mut self,
19816        user_triggered: bool,
19817        window: &mut Window,
19818        cx: &mut Context<Self>,
19819    ) {
19820        if let Some(project) = self.project() {
19821            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19822                && buffer.read(cx).file().is_none()
19823            {
19824                return;
19825            }
19826
19827            let focused = self.focus_handle(cx).contains_focused(window, cx);
19828
19829            let project = project.clone();
19830            let blame = cx
19831                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19832            self.blame_subscription =
19833                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19834            self.blame = Some(blame);
19835        }
19836    }
19837
19838    fn toggle_git_blame_inline_internal(
19839        &mut self,
19840        user_triggered: bool,
19841        window: &mut Window,
19842        cx: &mut Context<Self>,
19843    ) {
19844        if self.git_blame_inline_enabled {
19845            self.git_blame_inline_enabled = false;
19846            self.show_git_blame_inline = false;
19847            self.show_git_blame_inline_delay_task.take();
19848        } else {
19849            self.git_blame_inline_enabled = true;
19850            self.start_git_blame_inline(user_triggered, window, cx);
19851        }
19852
19853        cx.notify();
19854    }
19855
19856    fn start_git_blame_inline(
19857        &mut self,
19858        user_triggered: bool,
19859        window: &mut Window,
19860        cx: &mut Context<Self>,
19861    ) {
19862        self.start_git_blame(user_triggered, window, cx);
19863
19864        if ProjectSettings::get_global(cx)
19865            .git
19866            .inline_blame_delay()
19867            .is_some()
19868        {
19869            self.start_inline_blame_timer(window, cx);
19870        } else {
19871            self.show_git_blame_inline = true
19872        }
19873    }
19874
19875    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19876        self.blame.as_ref()
19877    }
19878
19879    pub fn show_git_blame_gutter(&self) -> bool {
19880        self.show_git_blame_gutter
19881    }
19882
19883    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19884        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19885    }
19886
19887    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19888        self.show_git_blame_inline
19889            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19890            && !self.newest_selection_head_on_empty_line(cx)
19891            && self.has_blame_entries(cx)
19892    }
19893
19894    fn has_blame_entries(&self, cx: &App) -> bool {
19895        self.blame()
19896            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19897    }
19898
19899    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19900        let cursor_anchor = self.selections.newest_anchor().head();
19901
19902        let snapshot = self.buffer.read(cx).snapshot(cx);
19903        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19904
19905        snapshot.line_len(buffer_row) == 0
19906    }
19907
19908    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19909        let buffer_and_selection = maybe!({
19910            let selection = self.selections.newest::<Point>(cx);
19911            let selection_range = selection.range();
19912
19913            let multi_buffer = self.buffer().read(cx);
19914            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19915            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19916
19917            let (buffer, range, _) = if selection.reversed {
19918                buffer_ranges.first()
19919            } else {
19920                buffer_ranges.last()
19921            }?;
19922
19923            let selection = text::ToPoint::to_point(&range.start, buffer).row
19924                ..text::ToPoint::to_point(&range.end, buffer).row;
19925            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19926        });
19927
19928        let Some((buffer, selection)) = buffer_and_selection else {
19929            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19930        };
19931
19932        let Some(project) = self.project() else {
19933            return Task::ready(Err(anyhow!("editor does not have project")));
19934        };
19935
19936        project.update(cx, |project, cx| {
19937            project.get_permalink_to_line(&buffer, selection, cx)
19938        })
19939    }
19940
19941    pub fn copy_permalink_to_line(
19942        &mut self,
19943        _: &CopyPermalinkToLine,
19944        window: &mut Window,
19945        cx: &mut Context<Self>,
19946    ) {
19947        let permalink_task = self.get_permalink_to_line(cx);
19948        let workspace = self.workspace();
19949
19950        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19951            Ok(permalink) => {
19952                cx.update(|_, cx| {
19953                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19954                })
19955                .ok();
19956            }
19957            Err(err) => {
19958                let message = format!("Failed to copy permalink: {err}");
19959
19960                anyhow::Result::<()>::Err(err).log_err();
19961
19962                if let Some(workspace) = workspace {
19963                    workspace
19964                        .update_in(cx, |workspace, _, cx| {
19965                            struct CopyPermalinkToLine;
19966
19967                            workspace.show_toast(
19968                                Toast::new(
19969                                    NotificationId::unique::<CopyPermalinkToLine>(),
19970                                    message,
19971                                ),
19972                                cx,
19973                            )
19974                        })
19975                        .ok();
19976                }
19977            }
19978        })
19979        .detach();
19980    }
19981
19982    pub fn copy_file_location(
19983        &mut self,
19984        _: &CopyFileLocation,
19985        _: &mut Window,
19986        cx: &mut Context<Self>,
19987    ) {
19988        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19989        if let Some(file) = self.target_file(cx) {
19990            let path = file.path().display(file.path_style(cx));
19991            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19992        }
19993    }
19994
19995    pub fn open_permalink_to_line(
19996        &mut self,
19997        _: &OpenPermalinkToLine,
19998        window: &mut Window,
19999        cx: &mut Context<Self>,
20000    ) {
20001        let permalink_task = self.get_permalink_to_line(cx);
20002        let workspace = self.workspace();
20003
20004        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20005            Ok(permalink) => {
20006                cx.update(|_, cx| {
20007                    cx.open_url(permalink.as_ref());
20008                })
20009                .ok();
20010            }
20011            Err(err) => {
20012                let message = format!("Failed to open permalink: {err}");
20013
20014                anyhow::Result::<()>::Err(err).log_err();
20015
20016                if let Some(workspace) = workspace {
20017                    workspace
20018                        .update(cx, |workspace, cx| {
20019                            struct OpenPermalinkToLine;
20020
20021                            workspace.show_toast(
20022                                Toast::new(
20023                                    NotificationId::unique::<OpenPermalinkToLine>(),
20024                                    message,
20025                                ),
20026                                cx,
20027                            )
20028                        })
20029                        .ok();
20030                }
20031            }
20032        })
20033        .detach();
20034    }
20035
20036    pub fn insert_uuid_v4(
20037        &mut self,
20038        _: &InsertUuidV4,
20039        window: &mut Window,
20040        cx: &mut Context<Self>,
20041    ) {
20042        self.insert_uuid(UuidVersion::V4, window, cx);
20043    }
20044
20045    pub fn insert_uuid_v7(
20046        &mut self,
20047        _: &InsertUuidV7,
20048        window: &mut Window,
20049        cx: &mut Context<Self>,
20050    ) {
20051        self.insert_uuid(UuidVersion::V7, window, cx);
20052    }
20053
20054    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20055        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20056        self.transact(window, cx, |this, window, cx| {
20057            let edits = this
20058                .selections
20059                .all::<Point>(cx)
20060                .into_iter()
20061                .map(|selection| {
20062                    let uuid = match version {
20063                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20064                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20065                    };
20066
20067                    (selection.range(), uuid.to_string())
20068                });
20069            this.edit(edits, cx);
20070            this.refresh_edit_prediction(true, false, window, cx);
20071        });
20072    }
20073
20074    pub fn open_selections_in_multibuffer(
20075        &mut self,
20076        _: &OpenSelectionsInMultibuffer,
20077        window: &mut Window,
20078        cx: &mut Context<Self>,
20079    ) {
20080        let multibuffer = self.buffer.read(cx);
20081
20082        let Some(buffer) = multibuffer.as_singleton() else {
20083            return;
20084        };
20085
20086        let Some(workspace) = self.workspace() else {
20087            return;
20088        };
20089
20090        let title = multibuffer.title(cx).to_string();
20091
20092        let locations = self
20093            .selections
20094            .all_anchors(cx)
20095            .iter()
20096            .map(|selection| {
20097                (
20098                    buffer.clone(),
20099                    (selection.start.text_anchor..selection.end.text_anchor)
20100                        .to_point(buffer.read(cx)),
20101                )
20102            })
20103            .into_group_map();
20104
20105        cx.spawn_in(window, async move |_, cx| {
20106            workspace.update_in(cx, |workspace, window, cx| {
20107                Self::open_locations_in_multibuffer(
20108                    workspace,
20109                    locations,
20110                    format!("Selections for '{title}'"),
20111                    false,
20112                    MultibufferSelectionMode::All,
20113                    window,
20114                    cx,
20115                );
20116            })
20117        })
20118        .detach();
20119    }
20120
20121    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20122    /// last highlight added will be used.
20123    ///
20124    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20125    pub fn highlight_rows<T: 'static>(
20126        &mut self,
20127        range: Range<Anchor>,
20128        color: Hsla,
20129        options: RowHighlightOptions,
20130        cx: &mut Context<Self>,
20131    ) {
20132        let snapshot = self.buffer().read(cx).snapshot(cx);
20133        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20134        let ix = row_highlights.binary_search_by(|highlight| {
20135            Ordering::Equal
20136                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20137                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20138        });
20139
20140        if let Err(mut ix) = ix {
20141            let index = post_inc(&mut self.highlight_order);
20142
20143            // If this range intersects with the preceding highlight, then merge it with
20144            // the preceding highlight. Otherwise insert a new highlight.
20145            let mut merged = false;
20146            if ix > 0 {
20147                let prev_highlight = &mut row_highlights[ix - 1];
20148                if prev_highlight
20149                    .range
20150                    .end
20151                    .cmp(&range.start, &snapshot)
20152                    .is_ge()
20153                {
20154                    ix -= 1;
20155                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20156                        prev_highlight.range.end = range.end;
20157                    }
20158                    merged = true;
20159                    prev_highlight.index = index;
20160                    prev_highlight.color = color;
20161                    prev_highlight.options = options;
20162                }
20163            }
20164
20165            if !merged {
20166                row_highlights.insert(
20167                    ix,
20168                    RowHighlight {
20169                        range,
20170                        index,
20171                        color,
20172                        options,
20173                        type_id: TypeId::of::<T>(),
20174                    },
20175                );
20176            }
20177
20178            // If any of the following highlights intersect with this one, merge them.
20179            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20180                let highlight = &row_highlights[ix];
20181                if next_highlight
20182                    .range
20183                    .start
20184                    .cmp(&highlight.range.end, &snapshot)
20185                    .is_le()
20186                {
20187                    if next_highlight
20188                        .range
20189                        .end
20190                        .cmp(&highlight.range.end, &snapshot)
20191                        .is_gt()
20192                    {
20193                        row_highlights[ix].range.end = next_highlight.range.end;
20194                    }
20195                    row_highlights.remove(ix + 1);
20196                } else {
20197                    break;
20198                }
20199            }
20200        }
20201    }
20202
20203    /// Remove any highlighted row ranges of the given type that intersect the
20204    /// given ranges.
20205    pub fn remove_highlighted_rows<T: 'static>(
20206        &mut self,
20207        ranges_to_remove: Vec<Range<Anchor>>,
20208        cx: &mut Context<Self>,
20209    ) {
20210        let snapshot = self.buffer().read(cx).snapshot(cx);
20211        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20212        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20213        row_highlights.retain(|highlight| {
20214            while let Some(range_to_remove) = ranges_to_remove.peek() {
20215                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20216                    Ordering::Less | Ordering::Equal => {
20217                        ranges_to_remove.next();
20218                    }
20219                    Ordering::Greater => {
20220                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20221                            Ordering::Less | Ordering::Equal => {
20222                                return false;
20223                            }
20224                            Ordering::Greater => break,
20225                        }
20226                    }
20227                }
20228            }
20229
20230            true
20231        })
20232    }
20233
20234    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20235    pub fn clear_row_highlights<T: 'static>(&mut self) {
20236        self.highlighted_rows.remove(&TypeId::of::<T>());
20237    }
20238
20239    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20240    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20241        self.highlighted_rows
20242            .get(&TypeId::of::<T>())
20243            .map_or(&[] as &[_], |vec| vec.as_slice())
20244            .iter()
20245            .map(|highlight| (highlight.range.clone(), highlight.color))
20246    }
20247
20248    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20249    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20250    /// Allows to ignore certain kinds of highlights.
20251    pub fn highlighted_display_rows(
20252        &self,
20253        window: &mut Window,
20254        cx: &mut App,
20255    ) -> BTreeMap<DisplayRow, LineHighlight> {
20256        let snapshot = self.snapshot(window, cx);
20257        let mut used_highlight_orders = HashMap::default();
20258        self.highlighted_rows
20259            .iter()
20260            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20261            .fold(
20262                BTreeMap::<DisplayRow, LineHighlight>::new(),
20263                |mut unique_rows, highlight| {
20264                    let start = highlight.range.start.to_display_point(&snapshot);
20265                    let end = highlight.range.end.to_display_point(&snapshot);
20266                    let start_row = start.row().0;
20267                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20268                        && end.column() == 0
20269                    {
20270                        end.row().0.saturating_sub(1)
20271                    } else {
20272                        end.row().0
20273                    };
20274                    for row in start_row..=end_row {
20275                        let used_index =
20276                            used_highlight_orders.entry(row).or_insert(highlight.index);
20277                        if highlight.index >= *used_index {
20278                            *used_index = highlight.index;
20279                            unique_rows.insert(
20280                                DisplayRow(row),
20281                                LineHighlight {
20282                                    include_gutter: highlight.options.include_gutter,
20283                                    border: None,
20284                                    background: highlight.color.into(),
20285                                    type_id: Some(highlight.type_id),
20286                                },
20287                            );
20288                        }
20289                    }
20290                    unique_rows
20291                },
20292            )
20293    }
20294
20295    pub fn highlighted_display_row_for_autoscroll(
20296        &self,
20297        snapshot: &DisplaySnapshot,
20298    ) -> Option<DisplayRow> {
20299        self.highlighted_rows
20300            .values()
20301            .flat_map(|highlighted_rows| highlighted_rows.iter())
20302            .filter_map(|highlight| {
20303                if highlight.options.autoscroll {
20304                    Some(highlight.range.start.to_display_point(snapshot).row())
20305                } else {
20306                    None
20307                }
20308            })
20309            .min()
20310    }
20311
20312    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20313        self.highlight_background::<SearchWithinRange>(
20314            ranges,
20315            |colors| colors.colors().editor_document_highlight_read_background,
20316            cx,
20317        )
20318    }
20319
20320    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20321        self.breadcrumb_header = Some(new_header);
20322    }
20323
20324    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20325        self.clear_background_highlights::<SearchWithinRange>(cx);
20326    }
20327
20328    pub fn highlight_background<T: 'static>(
20329        &mut self,
20330        ranges: &[Range<Anchor>],
20331        color_fetcher: fn(&Theme) -> Hsla,
20332        cx: &mut Context<Self>,
20333    ) {
20334        self.background_highlights.insert(
20335            HighlightKey::Type(TypeId::of::<T>()),
20336            (color_fetcher, Arc::from(ranges)),
20337        );
20338        self.scrollbar_marker_state.dirty = true;
20339        cx.notify();
20340    }
20341
20342    pub fn highlight_background_key<T: 'static>(
20343        &mut self,
20344        key: usize,
20345        ranges: &[Range<Anchor>],
20346        color_fetcher: fn(&Theme) -> Hsla,
20347        cx: &mut Context<Self>,
20348    ) {
20349        self.background_highlights.insert(
20350            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20351            (color_fetcher, Arc::from(ranges)),
20352        );
20353        self.scrollbar_marker_state.dirty = true;
20354        cx.notify();
20355    }
20356
20357    pub fn clear_background_highlights<T: 'static>(
20358        &mut self,
20359        cx: &mut Context<Self>,
20360    ) -> Option<BackgroundHighlight> {
20361        let text_highlights = self
20362            .background_highlights
20363            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20364        if !text_highlights.1.is_empty() {
20365            self.scrollbar_marker_state.dirty = true;
20366            cx.notify();
20367        }
20368        Some(text_highlights)
20369    }
20370
20371    pub fn highlight_gutter<T: 'static>(
20372        &mut self,
20373        ranges: impl Into<Vec<Range<Anchor>>>,
20374        color_fetcher: fn(&App) -> Hsla,
20375        cx: &mut Context<Self>,
20376    ) {
20377        self.gutter_highlights
20378            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20379        cx.notify();
20380    }
20381
20382    pub fn clear_gutter_highlights<T: 'static>(
20383        &mut self,
20384        cx: &mut Context<Self>,
20385    ) -> Option<GutterHighlight> {
20386        cx.notify();
20387        self.gutter_highlights.remove(&TypeId::of::<T>())
20388    }
20389
20390    pub fn insert_gutter_highlight<T: 'static>(
20391        &mut self,
20392        range: Range<Anchor>,
20393        color_fetcher: fn(&App) -> Hsla,
20394        cx: &mut Context<Self>,
20395    ) {
20396        let snapshot = self.buffer().read(cx).snapshot(cx);
20397        let mut highlights = self
20398            .gutter_highlights
20399            .remove(&TypeId::of::<T>())
20400            .map(|(_, highlights)| highlights)
20401            .unwrap_or_default();
20402        let ix = highlights.binary_search_by(|highlight| {
20403            Ordering::Equal
20404                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20405                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20406        });
20407        if let Err(ix) = ix {
20408            highlights.insert(ix, range);
20409        }
20410        self.gutter_highlights
20411            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20412    }
20413
20414    pub fn remove_gutter_highlights<T: 'static>(
20415        &mut self,
20416        ranges_to_remove: Vec<Range<Anchor>>,
20417        cx: &mut Context<Self>,
20418    ) {
20419        let snapshot = self.buffer().read(cx).snapshot(cx);
20420        let Some((color_fetcher, mut gutter_highlights)) =
20421            self.gutter_highlights.remove(&TypeId::of::<T>())
20422        else {
20423            return;
20424        };
20425        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20426        gutter_highlights.retain(|highlight| {
20427            while let Some(range_to_remove) = ranges_to_remove.peek() {
20428                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20429                    Ordering::Less | Ordering::Equal => {
20430                        ranges_to_remove.next();
20431                    }
20432                    Ordering::Greater => {
20433                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20434                            Ordering::Less | Ordering::Equal => {
20435                                return false;
20436                            }
20437                            Ordering::Greater => break,
20438                        }
20439                    }
20440                }
20441            }
20442
20443            true
20444        });
20445        self.gutter_highlights
20446            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20447    }
20448
20449    #[cfg(feature = "test-support")]
20450    pub fn all_text_highlights(
20451        &self,
20452        window: &mut Window,
20453        cx: &mut Context<Self>,
20454    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20455        let snapshot = self.snapshot(window, cx);
20456        self.display_map.update(cx, |display_map, _| {
20457            display_map
20458                .all_text_highlights()
20459                .map(|highlight| {
20460                    let (style, ranges) = highlight.as_ref();
20461                    (
20462                        *style,
20463                        ranges
20464                            .iter()
20465                            .map(|range| range.clone().to_display_points(&snapshot))
20466                            .collect(),
20467                    )
20468                })
20469                .collect()
20470        })
20471    }
20472
20473    #[cfg(feature = "test-support")]
20474    pub fn all_text_background_highlights(
20475        &self,
20476        window: &mut Window,
20477        cx: &mut Context<Self>,
20478    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20479        let snapshot = self.snapshot(window, cx);
20480        let buffer = &snapshot.buffer_snapshot();
20481        let start = buffer.anchor_before(0);
20482        let end = buffer.anchor_after(buffer.len());
20483        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20484    }
20485
20486    #[cfg(any(test, feature = "test-support"))]
20487    pub fn sorted_background_highlights_in_range(
20488        &self,
20489        search_range: Range<Anchor>,
20490        display_snapshot: &DisplaySnapshot,
20491        theme: &Theme,
20492    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20493        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20494        res.sort_by(|a, b| {
20495            a.0.start
20496                .cmp(&b.0.start)
20497                .then_with(|| a.0.end.cmp(&b.0.end))
20498                .then_with(|| a.1.cmp(&b.1))
20499        });
20500        res
20501    }
20502
20503    #[cfg(feature = "test-support")]
20504    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20505        let snapshot = self.buffer().read(cx).snapshot(cx);
20506
20507        let highlights = self
20508            .background_highlights
20509            .get(&HighlightKey::Type(TypeId::of::<
20510                items::BufferSearchHighlights,
20511            >()));
20512
20513        if let Some((_color, ranges)) = highlights {
20514            ranges
20515                .iter()
20516                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20517                .collect_vec()
20518        } else {
20519            vec![]
20520        }
20521    }
20522
20523    fn document_highlights_for_position<'a>(
20524        &'a self,
20525        position: Anchor,
20526        buffer: &'a MultiBufferSnapshot,
20527    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20528        let read_highlights = self
20529            .background_highlights
20530            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20531            .map(|h| &h.1);
20532        let write_highlights = self
20533            .background_highlights
20534            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20535            .map(|h| &h.1);
20536        let left_position = position.bias_left(buffer);
20537        let right_position = position.bias_right(buffer);
20538        read_highlights
20539            .into_iter()
20540            .chain(write_highlights)
20541            .flat_map(move |ranges| {
20542                let start_ix = match ranges.binary_search_by(|probe| {
20543                    let cmp = probe.end.cmp(&left_position, buffer);
20544                    if cmp.is_ge() {
20545                        Ordering::Greater
20546                    } else {
20547                        Ordering::Less
20548                    }
20549                }) {
20550                    Ok(i) | Err(i) => i,
20551                };
20552
20553                ranges[start_ix..]
20554                    .iter()
20555                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20556            })
20557    }
20558
20559    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20560        self.background_highlights
20561            .get(&HighlightKey::Type(TypeId::of::<T>()))
20562            .is_some_and(|(_, highlights)| !highlights.is_empty())
20563    }
20564
20565    /// Returns all background highlights for a given range.
20566    ///
20567    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20568    pub fn background_highlights_in_range(
20569        &self,
20570        search_range: Range<Anchor>,
20571        display_snapshot: &DisplaySnapshot,
20572        theme: &Theme,
20573    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20574        let mut results = Vec::new();
20575        for (color_fetcher, ranges) in self.background_highlights.values() {
20576            let color = color_fetcher(theme);
20577            let start_ix = match ranges.binary_search_by(|probe| {
20578                let cmp = probe
20579                    .end
20580                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20581                if cmp.is_gt() {
20582                    Ordering::Greater
20583                } else {
20584                    Ordering::Less
20585                }
20586            }) {
20587                Ok(i) | Err(i) => i,
20588            };
20589            for range in &ranges[start_ix..] {
20590                if range
20591                    .start
20592                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20593                    .is_ge()
20594                {
20595                    break;
20596                }
20597
20598                let start = range.start.to_display_point(display_snapshot);
20599                let end = range.end.to_display_point(display_snapshot);
20600                results.push((start..end, color))
20601            }
20602        }
20603        results
20604    }
20605
20606    pub fn gutter_highlights_in_range(
20607        &self,
20608        search_range: Range<Anchor>,
20609        display_snapshot: &DisplaySnapshot,
20610        cx: &App,
20611    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20612        let mut results = Vec::new();
20613        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20614            let color = color_fetcher(cx);
20615            let start_ix = match ranges.binary_search_by(|probe| {
20616                let cmp = probe
20617                    .end
20618                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20619                if cmp.is_gt() {
20620                    Ordering::Greater
20621                } else {
20622                    Ordering::Less
20623                }
20624            }) {
20625                Ok(i) | Err(i) => i,
20626            };
20627            for range in &ranges[start_ix..] {
20628                if range
20629                    .start
20630                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20631                    .is_ge()
20632                {
20633                    break;
20634                }
20635
20636                let start = range.start.to_display_point(display_snapshot);
20637                let end = range.end.to_display_point(display_snapshot);
20638                results.push((start..end, color))
20639            }
20640        }
20641        results
20642    }
20643
20644    /// Get the text ranges corresponding to the redaction query
20645    pub fn redacted_ranges(
20646        &self,
20647        search_range: Range<Anchor>,
20648        display_snapshot: &DisplaySnapshot,
20649        cx: &App,
20650    ) -> Vec<Range<DisplayPoint>> {
20651        display_snapshot
20652            .buffer_snapshot()
20653            .redacted_ranges(search_range, |file| {
20654                if let Some(file) = file {
20655                    file.is_private()
20656                        && EditorSettings::get(
20657                            Some(SettingsLocation {
20658                                worktree_id: file.worktree_id(cx),
20659                                path: file.path().as_ref(),
20660                            }),
20661                            cx,
20662                        )
20663                        .redact_private_values
20664                } else {
20665                    false
20666                }
20667            })
20668            .map(|range| {
20669                range.start.to_display_point(display_snapshot)
20670                    ..range.end.to_display_point(display_snapshot)
20671            })
20672            .collect()
20673    }
20674
20675    pub fn highlight_text_key<T: 'static>(
20676        &mut self,
20677        key: usize,
20678        ranges: Vec<Range<Anchor>>,
20679        style: HighlightStyle,
20680        cx: &mut Context<Self>,
20681    ) {
20682        self.display_map.update(cx, |map, _| {
20683            map.highlight_text(
20684                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20685                ranges,
20686                style,
20687            );
20688        });
20689        cx.notify();
20690    }
20691
20692    pub fn highlight_text<T: 'static>(
20693        &mut self,
20694        ranges: Vec<Range<Anchor>>,
20695        style: HighlightStyle,
20696        cx: &mut Context<Self>,
20697    ) {
20698        self.display_map.update(cx, |map, _| {
20699            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20700        });
20701        cx.notify();
20702    }
20703
20704    pub(crate) fn highlight_inlays<T: 'static>(
20705        &mut self,
20706        highlights: Vec<InlayHighlight>,
20707        style: HighlightStyle,
20708        cx: &mut Context<Self>,
20709    ) {
20710        self.display_map.update(cx, |map, _| {
20711            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20712        });
20713        cx.notify();
20714    }
20715
20716    pub fn text_highlights<'a, T: 'static>(
20717        &'a self,
20718        cx: &'a App,
20719    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20720        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20721    }
20722
20723    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20724        let cleared = self
20725            .display_map
20726            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20727        if cleared {
20728            cx.notify();
20729        }
20730    }
20731
20732    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20733        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20734            && self.focus_handle.is_focused(window)
20735    }
20736
20737    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20738        self.show_cursor_when_unfocused = is_enabled;
20739        cx.notify();
20740    }
20741
20742    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20743        cx.notify();
20744    }
20745
20746    fn on_debug_session_event(
20747        &mut self,
20748        _session: Entity<Session>,
20749        event: &SessionEvent,
20750        cx: &mut Context<Self>,
20751    ) {
20752        if let SessionEvent::InvalidateInlineValue = event {
20753            self.refresh_inline_values(cx);
20754        }
20755    }
20756
20757    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20758        let Some(project) = self.project.clone() else {
20759            return;
20760        };
20761
20762        if !self.inline_value_cache.enabled {
20763            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20764            self.splice_inlays(&inlays, Vec::new(), cx);
20765            return;
20766        }
20767
20768        let current_execution_position = self
20769            .highlighted_rows
20770            .get(&TypeId::of::<ActiveDebugLine>())
20771            .and_then(|lines| lines.last().map(|line| line.range.end));
20772
20773        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20774            let inline_values = editor
20775                .update(cx, |editor, cx| {
20776                    let Some(current_execution_position) = current_execution_position else {
20777                        return Some(Task::ready(Ok(Vec::new())));
20778                    };
20779
20780                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20781                        let snapshot = buffer.snapshot(cx);
20782
20783                        let excerpt = snapshot.excerpt_containing(
20784                            current_execution_position..current_execution_position,
20785                        )?;
20786
20787                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20788                    })?;
20789
20790                    let range =
20791                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20792
20793                    project.inline_values(buffer, range, cx)
20794                })
20795                .ok()
20796                .flatten()?
20797                .await
20798                .context("refreshing debugger inlays")
20799                .log_err()?;
20800
20801            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20802
20803            for (buffer_id, inline_value) in inline_values
20804                .into_iter()
20805                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20806            {
20807                buffer_inline_values
20808                    .entry(buffer_id)
20809                    .or_default()
20810                    .push(inline_value);
20811            }
20812
20813            editor
20814                .update(cx, |editor, cx| {
20815                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20816                    let mut new_inlays = Vec::default();
20817
20818                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20819                        let buffer_id = buffer_snapshot.remote_id();
20820                        buffer_inline_values
20821                            .get(&buffer_id)
20822                            .into_iter()
20823                            .flatten()
20824                            .for_each(|hint| {
20825                                let inlay = Inlay::debugger(
20826                                    post_inc(&mut editor.next_inlay_id),
20827                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20828                                    hint.text(),
20829                                );
20830                                if !inlay.text().chars().contains(&'\n') {
20831                                    new_inlays.push(inlay);
20832                                }
20833                            });
20834                    }
20835
20836                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20837                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20838
20839                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20840                })
20841                .ok()?;
20842            Some(())
20843        });
20844    }
20845
20846    fn on_buffer_event(
20847        &mut self,
20848        multibuffer: &Entity<MultiBuffer>,
20849        event: &multi_buffer::Event,
20850        window: &mut Window,
20851        cx: &mut Context<Self>,
20852    ) {
20853        match event {
20854            multi_buffer::Event::Edited {
20855                singleton_buffer_edited,
20856                edited_buffer,
20857            } => {
20858                self.scrollbar_marker_state.dirty = true;
20859                self.active_indent_guides_state.dirty = true;
20860                self.refresh_active_diagnostics(cx);
20861                self.refresh_code_actions(window, cx);
20862                self.refresh_selected_text_highlights(true, window, cx);
20863                self.refresh_single_line_folds(window, cx);
20864                refresh_matching_bracket_highlights(self, cx);
20865                if self.has_active_edit_prediction() {
20866                    self.update_visible_edit_prediction(window, cx);
20867                }
20868                if let Some(project) = self.project.as_ref()
20869                    && let Some(edited_buffer) = edited_buffer
20870                {
20871                    project.update(cx, |project, cx| {
20872                        self.registered_buffers
20873                            .entry(edited_buffer.read(cx).remote_id())
20874                            .or_insert_with(|| {
20875                                project.register_buffer_with_language_servers(edited_buffer, cx)
20876                            });
20877                    });
20878                }
20879                cx.emit(EditorEvent::BufferEdited);
20880                cx.emit(SearchEvent::MatchesInvalidated);
20881
20882                if let Some(buffer) = edited_buffer {
20883                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20884                }
20885
20886                if *singleton_buffer_edited {
20887                    if let Some(buffer) = edited_buffer
20888                        && buffer.read(cx).file().is_none()
20889                    {
20890                        cx.emit(EditorEvent::TitleChanged);
20891                    }
20892                    if let Some(project) = &self.project {
20893                        #[allow(clippy::mutable_key_type)]
20894                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20895                            multibuffer
20896                                .all_buffers()
20897                                .into_iter()
20898                                .filter_map(|buffer| {
20899                                    buffer.update(cx, |buffer, cx| {
20900                                        let language = buffer.language()?;
20901                                        let should_discard = project.update(cx, |project, cx| {
20902                                            project.is_local()
20903                                                && !project.has_language_servers_for(buffer, cx)
20904                                        });
20905                                        should_discard.not().then_some(language.clone())
20906                                    })
20907                                })
20908                                .collect::<HashSet<_>>()
20909                        });
20910                        if !languages_affected.is_empty() {
20911                            self.refresh_inlay_hints(
20912                                InlayHintRefreshReason::BufferEdited(languages_affected),
20913                                cx,
20914                            );
20915                        }
20916                    }
20917                }
20918
20919                let Some(project) = &self.project else { return };
20920                let (telemetry, is_via_ssh) = {
20921                    let project = project.read(cx);
20922                    let telemetry = project.client().telemetry().clone();
20923                    let is_via_ssh = project.is_via_remote_server();
20924                    (telemetry, is_via_ssh)
20925                };
20926                refresh_linked_ranges(self, window, cx);
20927                telemetry.log_edit_event("editor", is_via_ssh);
20928            }
20929            multi_buffer::Event::ExcerptsAdded {
20930                buffer,
20931                predecessor,
20932                excerpts,
20933            } => {
20934                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20935                let buffer_id = buffer.read(cx).remote_id();
20936                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20937                    && let Some(project) = &self.project
20938                {
20939                    update_uncommitted_diff_for_buffer(
20940                        cx.entity(),
20941                        project,
20942                        [buffer.clone()],
20943                        self.buffer.clone(),
20944                        cx,
20945                    )
20946                    .detach();
20947                }
20948                if self.active_diagnostics != ActiveDiagnostic::All {
20949                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20950                }
20951                cx.emit(EditorEvent::ExcerptsAdded {
20952                    buffer: buffer.clone(),
20953                    predecessor: *predecessor,
20954                    excerpts: excerpts.clone(),
20955                });
20956                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20957            }
20958            multi_buffer::Event::ExcerptsRemoved {
20959                ids,
20960                removed_buffer_ids,
20961            } => {
20962                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20963                let buffer = self.buffer.read(cx);
20964                self.registered_buffers
20965                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20966                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20967                cx.emit(EditorEvent::ExcerptsRemoved {
20968                    ids: ids.clone(),
20969                    removed_buffer_ids: removed_buffer_ids.clone(),
20970                });
20971            }
20972            multi_buffer::Event::ExcerptsEdited {
20973                excerpt_ids,
20974                buffer_ids,
20975            } => {
20976                self.display_map.update(cx, |map, cx| {
20977                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20978                });
20979                cx.emit(EditorEvent::ExcerptsEdited {
20980                    ids: excerpt_ids.clone(),
20981                });
20982            }
20983            multi_buffer::Event::ExcerptsExpanded { ids } => {
20984                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20985                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20986            }
20987            multi_buffer::Event::Reparsed(buffer_id) => {
20988                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20989                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20990
20991                cx.emit(EditorEvent::Reparsed(*buffer_id));
20992            }
20993            multi_buffer::Event::DiffHunksToggled => {
20994                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20995            }
20996            multi_buffer::Event::LanguageChanged(buffer_id) => {
20997                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20998                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20999                cx.emit(EditorEvent::Reparsed(*buffer_id));
21000                cx.notify();
21001            }
21002            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21003            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21004            multi_buffer::Event::FileHandleChanged
21005            | multi_buffer::Event::Reloaded
21006            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21007            multi_buffer::Event::DiagnosticsUpdated => {
21008                self.update_diagnostics_state(window, cx);
21009            }
21010            _ => {}
21011        };
21012    }
21013
21014    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21015        if !self.diagnostics_enabled() {
21016            return;
21017        }
21018        self.refresh_active_diagnostics(cx);
21019        self.refresh_inline_diagnostics(true, window, cx);
21020        self.scrollbar_marker_state.dirty = true;
21021        cx.notify();
21022    }
21023
21024    pub fn start_temporary_diff_override(&mut self) {
21025        self.load_diff_task.take();
21026        self.temporary_diff_override = true;
21027    }
21028
21029    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21030        self.temporary_diff_override = false;
21031        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21032        self.buffer.update(cx, |buffer, cx| {
21033            buffer.set_all_diff_hunks_collapsed(cx);
21034        });
21035
21036        if let Some(project) = self.project.clone() {
21037            self.load_diff_task = Some(
21038                update_uncommitted_diff_for_buffer(
21039                    cx.entity(),
21040                    &project,
21041                    self.buffer.read(cx).all_buffers(),
21042                    self.buffer.clone(),
21043                    cx,
21044                )
21045                .shared(),
21046            );
21047        }
21048    }
21049
21050    fn on_display_map_changed(
21051        &mut self,
21052        _: Entity<DisplayMap>,
21053        _: &mut Window,
21054        cx: &mut Context<Self>,
21055    ) {
21056        cx.notify();
21057    }
21058
21059    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21060        if self.diagnostics_enabled() {
21061            let new_severity = EditorSettings::get_global(cx)
21062                .diagnostics_max_severity
21063                .unwrap_or(DiagnosticSeverity::Hint);
21064            self.set_max_diagnostics_severity(new_severity, cx);
21065        }
21066        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21067        self.update_edit_prediction_settings(cx);
21068        self.refresh_edit_prediction(true, false, window, cx);
21069        self.refresh_inline_values(cx);
21070        self.refresh_inlay_hints(
21071            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21072                self.selections.newest_anchor().head(),
21073                &self.buffer.read(cx).snapshot(cx),
21074                cx,
21075            )),
21076            cx,
21077        );
21078
21079        let old_cursor_shape = self.cursor_shape;
21080        let old_show_breadcrumbs = self.show_breadcrumbs;
21081
21082        {
21083            let editor_settings = EditorSettings::get_global(cx);
21084            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21085            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21086            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21087            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21088        }
21089
21090        if old_cursor_shape != self.cursor_shape {
21091            cx.emit(EditorEvent::CursorShapeChanged);
21092        }
21093
21094        if old_show_breadcrumbs != self.show_breadcrumbs {
21095            cx.emit(EditorEvent::BreadcrumbsChanged);
21096        }
21097
21098        let project_settings = ProjectSettings::get_global(cx);
21099        self.serialize_dirty_buffers =
21100            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21101
21102        if self.mode.is_full() {
21103            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21104            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21105            if self.show_inline_diagnostics != show_inline_diagnostics {
21106                self.show_inline_diagnostics = show_inline_diagnostics;
21107                self.refresh_inline_diagnostics(false, window, cx);
21108            }
21109
21110            if self.git_blame_inline_enabled != inline_blame_enabled {
21111                self.toggle_git_blame_inline_internal(false, window, cx);
21112            }
21113
21114            let minimap_settings = EditorSettings::get_global(cx).minimap;
21115            if self.minimap_visibility != MinimapVisibility::Disabled {
21116                if self.minimap_visibility.settings_visibility()
21117                    != minimap_settings.minimap_enabled()
21118                {
21119                    self.set_minimap_visibility(
21120                        MinimapVisibility::for_mode(self.mode(), cx),
21121                        window,
21122                        cx,
21123                    );
21124                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21125                    minimap_entity.update(cx, |minimap_editor, cx| {
21126                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21127                    })
21128                }
21129            }
21130        }
21131
21132        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21133            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21134        }) {
21135            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
21136                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21137            }
21138            self.refresh_colors(false, None, window, cx);
21139        }
21140
21141        cx.notify();
21142    }
21143
21144    pub fn set_searchable(&mut self, searchable: bool) {
21145        self.searchable = searchable;
21146    }
21147
21148    pub fn searchable(&self) -> bool {
21149        self.searchable
21150    }
21151
21152    fn open_proposed_changes_editor(
21153        &mut self,
21154        _: &OpenProposedChangesEditor,
21155        window: &mut Window,
21156        cx: &mut Context<Self>,
21157    ) {
21158        let Some(workspace) = self.workspace() else {
21159            cx.propagate();
21160            return;
21161        };
21162
21163        let selections = self.selections.all::<usize>(cx);
21164        let multi_buffer = self.buffer.read(cx);
21165        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21166        let mut new_selections_by_buffer = HashMap::default();
21167        for selection in selections {
21168            for (buffer, range, _) in
21169                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
21170            {
21171                let mut range = range.to_point(buffer);
21172                range.start.column = 0;
21173                range.end.column = buffer.line_len(range.end.row);
21174                new_selections_by_buffer
21175                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
21176                    .or_insert(Vec::new())
21177                    .push(range)
21178            }
21179        }
21180
21181        let proposed_changes_buffers = new_selections_by_buffer
21182            .into_iter()
21183            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
21184            .collect::<Vec<_>>();
21185        let proposed_changes_editor = cx.new(|cx| {
21186            ProposedChangesEditor::new(
21187                "Proposed changes",
21188                proposed_changes_buffers,
21189                self.project.clone(),
21190                window,
21191                cx,
21192            )
21193        });
21194
21195        window.defer(cx, move |window, cx| {
21196            workspace.update(cx, |workspace, cx| {
21197                workspace.active_pane().update(cx, |pane, cx| {
21198                    pane.add_item(
21199                        Box::new(proposed_changes_editor),
21200                        true,
21201                        true,
21202                        None,
21203                        window,
21204                        cx,
21205                    );
21206                });
21207            });
21208        });
21209    }
21210
21211    pub fn open_excerpts_in_split(
21212        &mut self,
21213        _: &OpenExcerptsSplit,
21214        window: &mut Window,
21215        cx: &mut Context<Self>,
21216    ) {
21217        self.open_excerpts_common(None, true, window, cx)
21218    }
21219
21220    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21221        self.open_excerpts_common(None, false, window, cx)
21222    }
21223
21224    fn open_excerpts_common(
21225        &mut self,
21226        jump_data: Option<JumpData>,
21227        split: bool,
21228        window: &mut Window,
21229        cx: &mut Context<Self>,
21230    ) {
21231        let Some(workspace) = self.workspace() else {
21232            cx.propagate();
21233            return;
21234        };
21235
21236        if self.buffer.read(cx).is_singleton() {
21237            cx.propagate();
21238            return;
21239        }
21240
21241        let mut new_selections_by_buffer = HashMap::default();
21242        match &jump_data {
21243            Some(JumpData::MultiBufferPoint {
21244                excerpt_id,
21245                position,
21246                anchor,
21247                line_offset_from_top,
21248            }) => {
21249                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21250                if let Some(buffer) = multi_buffer_snapshot
21251                    .buffer_id_for_excerpt(*excerpt_id)
21252                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21253                {
21254                    let buffer_snapshot = buffer.read(cx).snapshot();
21255                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21256                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21257                    } else {
21258                        buffer_snapshot.clip_point(*position, Bias::Left)
21259                    };
21260                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21261                    new_selections_by_buffer.insert(
21262                        buffer,
21263                        (
21264                            vec![jump_to_offset..jump_to_offset],
21265                            Some(*line_offset_from_top),
21266                        ),
21267                    );
21268                }
21269            }
21270            Some(JumpData::MultiBufferRow {
21271                row,
21272                line_offset_from_top,
21273            }) => {
21274                let point = MultiBufferPoint::new(row.0, 0);
21275                if let Some((buffer, buffer_point, _)) =
21276                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21277                {
21278                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21279                    new_selections_by_buffer
21280                        .entry(buffer)
21281                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21282                        .0
21283                        .push(buffer_offset..buffer_offset)
21284                }
21285            }
21286            None => {
21287                let selections = self.selections.all::<usize>(cx);
21288                let multi_buffer = self.buffer.read(cx);
21289                for selection in selections {
21290                    for (snapshot, range, _, anchor) in multi_buffer
21291                        .snapshot(cx)
21292                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21293                    {
21294                        if let Some(anchor) = anchor {
21295                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21296                            else {
21297                                continue;
21298                            };
21299                            let offset = text::ToOffset::to_offset(
21300                                &anchor.text_anchor,
21301                                &buffer_handle.read(cx).snapshot(),
21302                            );
21303                            let range = offset..offset;
21304                            new_selections_by_buffer
21305                                .entry(buffer_handle)
21306                                .or_insert((Vec::new(), None))
21307                                .0
21308                                .push(range)
21309                        } else {
21310                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21311                            else {
21312                                continue;
21313                            };
21314                            new_selections_by_buffer
21315                                .entry(buffer_handle)
21316                                .or_insert((Vec::new(), None))
21317                                .0
21318                                .push(range)
21319                        }
21320                    }
21321                }
21322            }
21323        }
21324
21325        new_selections_by_buffer
21326            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21327
21328        if new_selections_by_buffer.is_empty() {
21329            return;
21330        }
21331
21332        // We defer the pane interaction because we ourselves are a workspace item
21333        // and activating a new item causes the pane to call a method on us reentrantly,
21334        // which panics if we're on the stack.
21335        window.defer(cx, move |window, cx| {
21336            workspace.update(cx, |workspace, cx| {
21337                let pane = if split {
21338                    workspace.adjacent_pane(window, cx)
21339                } else {
21340                    workspace.active_pane().clone()
21341                };
21342
21343                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21344                    let editor = buffer
21345                        .read(cx)
21346                        .file()
21347                        .is_none()
21348                        .then(|| {
21349                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21350                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21351                            // Instead, we try to activate the existing editor in the pane first.
21352                            let (editor, pane_item_index) =
21353                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21354                                    let editor = item.downcast::<Editor>()?;
21355                                    let singleton_buffer =
21356                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21357                                    if singleton_buffer == buffer {
21358                                        Some((editor, i))
21359                                    } else {
21360                                        None
21361                                    }
21362                                })?;
21363                            pane.update(cx, |pane, cx| {
21364                                pane.activate_item(pane_item_index, true, true, window, cx)
21365                            });
21366                            Some(editor)
21367                        })
21368                        .flatten()
21369                        .unwrap_or_else(|| {
21370                            workspace.open_project_item::<Self>(
21371                                pane.clone(),
21372                                buffer,
21373                                true,
21374                                true,
21375                                window,
21376                                cx,
21377                            )
21378                        });
21379
21380                    editor.update(cx, |editor, cx| {
21381                        let autoscroll = match scroll_offset {
21382                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21383                            None => Autoscroll::newest(),
21384                        };
21385                        let nav_history = editor.nav_history.take();
21386                        editor.change_selections(
21387                            SelectionEffects::scroll(autoscroll),
21388                            window,
21389                            cx,
21390                            |s| {
21391                                s.select_ranges(ranges);
21392                            },
21393                        );
21394                        editor.nav_history = nav_history;
21395                    });
21396                }
21397            })
21398        });
21399    }
21400
21401    // For now, don't allow opening excerpts in buffers that aren't backed by
21402    // regular project files.
21403    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21404        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21405    }
21406
21407    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21408        let snapshot = self.buffer.read(cx).read(cx);
21409        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21410        Some(
21411            ranges
21412                .iter()
21413                .map(move |range| {
21414                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21415                })
21416                .collect(),
21417        )
21418    }
21419
21420    fn selection_replacement_ranges(
21421        &self,
21422        range: Range<OffsetUtf16>,
21423        cx: &mut App,
21424    ) -> Vec<Range<OffsetUtf16>> {
21425        let selections = self.selections.all::<OffsetUtf16>(cx);
21426        let newest_selection = selections
21427            .iter()
21428            .max_by_key(|selection| selection.id)
21429            .unwrap();
21430        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21431        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21432        let snapshot = self.buffer.read(cx).read(cx);
21433        selections
21434            .into_iter()
21435            .map(|mut selection| {
21436                selection.start.0 =
21437                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21438                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21439                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21440                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21441            })
21442            .collect()
21443    }
21444
21445    fn report_editor_event(
21446        &self,
21447        reported_event: ReportEditorEvent,
21448        file_extension: Option<String>,
21449        cx: &App,
21450    ) {
21451        if cfg!(any(test, feature = "test-support")) {
21452            return;
21453        }
21454
21455        let Some(project) = &self.project else { return };
21456
21457        // If None, we are in a file without an extension
21458        let file = self
21459            .buffer
21460            .read(cx)
21461            .as_singleton()
21462            .and_then(|b| b.read(cx).file());
21463        let file_extension = file_extension.or(file
21464            .as_ref()
21465            .and_then(|file| Path::new(file.file_name(cx)).extension())
21466            .and_then(|e| e.to_str())
21467            .map(|a| a.to_string()));
21468
21469        let vim_mode = vim_enabled(cx);
21470
21471        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21472        let copilot_enabled = edit_predictions_provider
21473            == language::language_settings::EditPredictionProvider::Copilot;
21474        let copilot_enabled_for_language = self
21475            .buffer
21476            .read(cx)
21477            .language_settings(cx)
21478            .show_edit_predictions;
21479
21480        let project = project.read(cx);
21481        let event_type = reported_event.event_type();
21482
21483        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21484            telemetry::event!(
21485                event_type,
21486                type = if auto_saved {"autosave"} else {"manual"},
21487                file_extension,
21488                vim_mode,
21489                copilot_enabled,
21490                copilot_enabled_for_language,
21491                edit_predictions_provider,
21492                is_via_ssh = project.is_via_remote_server(),
21493            );
21494        } else {
21495            telemetry::event!(
21496                event_type,
21497                file_extension,
21498                vim_mode,
21499                copilot_enabled,
21500                copilot_enabled_for_language,
21501                edit_predictions_provider,
21502                is_via_ssh = project.is_via_remote_server(),
21503            );
21504        };
21505    }
21506
21507    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21508    /// with each line being an array of {text, highlight} objects.
21509    fn copy_highlight_json(
21510        &mut self,
21511        _: &CopyHighlightJson,
21512        window: &mut Window,
21513        cx: &mut Context<Self>,
21514    ) {
21515        #[derive(Serialize)]
21516        struct Chunk<'a> {
21517            text: String,
21518            highlight: Option<&'a str>,
21519        }
21520
21521        let snapshot = self.buffer.read(cx).snapshot(cx);
21522        let range = self
21523            .selected_text_range(false, window, cx)
21524            .and_then(|selection| {
21525                if selection.range.is_empty() {
21526                    None
21527                } else {
21528                    Some(selection.range)
21529                }
21530            })
21531            .unwrap_or_else(|| 0..snapshot.len());
21532
21533        let chunks = snapshot.chunks(range, true);
21534        let mut lines = Vec::new();
21535        let mut line: VecDeque<Chunk> = VecDeque::new();
21536
21537        let Some(style) = self.style.as_ref() else {
21538            return;
21539        };
21540
21541        for chunk in chunks {
21542            let highlight = chunk
21543                .syntax_highlight_id
21544                .and_then(|id| id.name(&style.syntax));
21545            let mut chunk_lines = chunk.text.split('\n').peekable();
21546            while let Some(text) = chunk_lines.next() {
21547                let mut merged_with_last_token = false;
21548                if let Some(last_token) = line.back_mut()
21549                    && last_token.highlight == highlight
21550                {
21551                    last_token.text.push_str(text);
21552                    merged_with_last_token = true;
21553                }
21554
21555                if !merged_with_last_token {
21556                    line.push_back(Chunk {
21557                        text: text.into(),
21558                        highlight,
21559                    });
21560                }
21561
21562                if chunk_lines.peek().is_some() {
21563                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21564                        line.pop_front();
21565                    }
21566                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21567                        line.pop_back();
21568                    }
21569
21570                    lines.push(mem::take(&mut line));
21571                }
21572            }
21573        }
21574
21575        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21576            return;
21577        };
21578        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21579    }
21580
21581    pub fn open_context_menu(
21582        &mut self,
21583        _: &OpenContextMenu,
21584        window: &mut Window,
21585        cx: &mut Context<Self>,
21586    ) {
21587        self.request_autoscroll(Autoscroll::newest(), cx);
21588        let position = self.selections.newest_display(cx).start;
21589        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21590    }
21591
21592    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21593        &self.inlay_hint_cache
21594    }
21595
21596    pub fn replay_insert_event(
21597        &mut self,
21598        text: &str,
21599        relative_utf16_range: Option<Range<isize>>,
21600        window: &mut Window,
21601        cx: &mut Context<Self>,
21602    ) {
21603        if !self.input_enabled {
21604            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21605            return;
21606        }
21607        if let Some(relative_utf16_range) = relative_utf16_range {
21608            let selections = self.selections.all::<OffsetUtf16>(cx);
21609            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21610                let new_ranges = selections.into_iter().map(|range| {
21611                    let start = OffsetUtf16(
21612                        range
21613                            .head()
21614                            .0
21615                            .saturating_add_signed(relative_utf16_range.start),
21616                    );
21617                    let end = OffsetUtf16(
21618                        range
21619                            .head()
21620                            .0
21621                            .saturating_add_signed(relative_utf16_range.end),
21622                    );
21623                    start..end
21624                });
21625                s.select_ranges(new_ranges);
21626            });
21627        }
21628
21629        self.handle_input(text, window, cx);
21630    }
21631
21632    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21633        let Some(provider) = self.semantics_provider.as_ref() else {
21634            return false;
21635        };
21636
21637        let mut supports = false;
21638        self.buffer().update(cx, |this, cx| {
21639            this.for_each_buffer(|buffer| {
21640                supports |= provider.supports_inlay_hints(buffer, cx);
21641            });
21642        });
21643
21644        supports
21645    }
21646
21647    pub fn is_focused(&self, window: &Window) -> bool {
21648        self.focus_handle.is_focused(window)
21649    }
21650
21651    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21652        cx.emit(EditorEvent::Focused);
21653
21654        if let Some(descendant) = self
21655            .last_focused_descendant
21656            .take()
21657            .and_then(|descendant| descendant.upgrade())
21658        {
21659            window.focus(&descendant);
21660        } else {
21661            if let Some(blame) = self.blame.as_ref() {
21662                blame.update(cx, GitBlame::focus)
21663            }
21664
21665            self.blink_manager.update(cx, BlinkManager::enable);
21666            self.show_cursor_names(window, cx);
21667            self.buffer.update(cx, |buffer, cx| {
21668                buffer.finalize_last_transaction(cx);
21669                if self.leader_id.is_none() {
21670                    buffer.set_active_selections(
21671                        &self.selections.disjoint_anchors_arc(),
21672                        self.selections.line_mode(),
21673                        self.cursor_shape,
21674                        cx,
21675                    );
21676                }
21677            });
21678        }
21679    }
21680
21681    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21682        cx.emit(EditorEvent::FocusedIn)
21683    }
21684
21685    fn handle_focus_out(
21686        &mut self,
21687        event: FocusOutEvent,
21688        _window: &mut Window,
21689        cx: &mut Context<Self>,
21690    ) {
21691        if event.blurred != self.focus_handle {
21692            self.last_focused_descendant = Some(event.blurred);
21693        }
21694        self.selection_drag_state = SelectionDragState::None;
21695        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21696    }
21697
21698    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21699        self.blink_manager.update(cx, BlinkManager::disable);
21700        self.buffer
21701            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21702
21703        if let Some(blame) = self.blame.as_ref() {
21704            blame.update(cx, GitBlame::blur)
21705        }
21706        if !self.hover_state.focused(window, cx) {
21707            hide_hover(self, cx);
21708        }
21709        if !self
21710            .context_menu
21711            .borrow()
21712            .as_ref()
21713            .is_some_and(|context_menu| context_menu.focused(window, cx))
21714        {
21715            self.hide_context_menu(window, cx);
21716        }
21717        self.take_active_edit_prediction(cx);
21718        cx.emit(EditorEvent::Blurred);
21719        cx.notify();
21720    }
21721
21722    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21723        let mut pending: String = window
21724            .pending_input_keystrokes()
21725            .into_iter()
21726            .flatten()
21727            .filter_map(|keystroke| {
21728                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21729                    keystroke.key_char.clone()
21730                } else {
21731                    None
21732                }
21733            })
21734            .collect();
21735
21736        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21737            pending = "".to_string();
21738        }
21739
21740        let existing_pending = self
21741            .text_highlights::<PendingInput>(cx)
21742            .map(|(_, ranges)| ranges.to_vec());
21743        if existing_pending.is_none() && pending.is_empty() {
21744            return;
21745        }
21746        let transaction =
21747            self.transact(window, cx, |this, window, cx| {
21748                let selections = this.selections.all::<usize>(cx);
21749                let edits = selections
21750                    .iter()
21751                    .map(|selection| (selection.end..selection.end, pending.clone()));
21752                this.edit(edits, cx);
21753                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21754                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21755                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21756                    }));
21757                });
21758                if let Some(existing_ranges) = existing_pending {
21759                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21760                    this.edit(edits, cx);
21761                }
21762            });
21763
21764        let snapshot = self.snapshot(window, cx);
21765        let ranges = self
21766            .selections
21767            .all::<usize>(cx)
21768            .into_iter()
21769            .map(|selection| {
21770                snapshot.buffer_snapshot().anchor_after(selection.end)
21771                    ..snapshot
21772                        .buffer_snapshot()
21773                        .anchor_before(selection.end + pending.len())
21774            })
21775            .collect();
21776
21777        if pending.is_empty() {
21778            self.clear_highlights::<PendingInput>(cx);
21779        } else {
21780            self.highlight_text::<PendingInput>(
21781                ranges,
21782                HighlightStyle {
21783                    underline: Some(UnderlineStyle {
21784                        thickness: px(1.),
21785                        color: None,
21786                        wavy: false,
21787                    }),
21788                    ..Default::default()
21789                },
21790                cx,
21791            );
21792        }
21793
21794        self.ime_transaction = self.ime_transaction.or(transaction);
21795        if let Some(transaction) = self.ime_transaction {
21796            self.buffer.update(cx, |buffer, cx| {
21797                buffer.group_until_transaction(transaction, cx);
21798            });
21799        }
21800
21801        if self.text_highlights::<PendingInput>(cx).is_none() {
21802            self.ime_transaction.take();
21803        }
21804    }
21805
21806    pub fn register_action_renderer(
21807        &mut self,
21808        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21809    ) -> Subscription {
21810        let id = self.next_editor_action_id.post_inc();
21811        self.editor_actions
21812            .borrow_mut()
21813            .insert(id, Box::new(listener));
21814
21815        let editor_actions = self.editor_actions.clone();
21816        Subscription::new(move || {
21817            editor_actions.borrow_mut().remove(&id);
21818        })
21819    }
21820
21821    pub fn register_action<A: Action>(
21822        &mut self,
21823        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21824    ) -> Subscription {
21825        let id = self.next_editor_action_id.post_inc();
21826        let listener = Arc::new(listener);
21827        self.editor_actions.borrow_mut().insert(
21828            id,
21829            Box::new(move |_, window, _| {
21830                let listener = listener.clone();
21831                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21832                    let action = action.downcast_ref().unwrap();
21833                    if phase == DispatchPhase::Bubble {
21834                        listener(action, window, cx)
21835                    }
21836                })
21837            }),
21838        );
21839
21840        let editor_actions = self.editor_actions.clone();
21841        Subscription::new(move || {
21842            editor_actions.borrow_mut().remove(&id);
21843        })
21844    }
21845
21846    pub fn file_header_size(&self) -> u32 {
21847        FILE_HEADER_HEIGHT
21848    }
21849
21850    pub fn restore(
21851        &mut self,
21852        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21853        window: &mut Window,
21854        cx: &mut Context<Self>,
21855    ) {
21856        let workspace = self.workspace();
21857        let project = self.project();
21858        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21859            let mut tasks = Vec::new();
21860            for (buffer_id, changes) in revert_changes {
21861                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21862                    buffer.update(cx, |buffer, cx| {
21863                        buffer.edit(
21864                            changes
21865                                .into_iter()
21866                                .map(|(range, text)| (range, text.to_string())),
21867                            None,
21868                            cx,
21869                        );
21870                    });
21871
21872                    if let Some(project) =
21873                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21874                    {
21875                        project.update(cx, |project, cx| {
21876                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21877                        })
21878                    }
21879                }
21880            }
21881            tasks
21882        });
21883        cx.spawn_in(window, async move |_, cx| {
21884            for (buffer, task) in save_tasks {
21885                let result = task.await;
21886                if result.is_err() {
21887                    let Some(path) = buffer
21888                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21889                        .ok()
21890                    else {
21891                        continue;
21892                    };
21893                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21894                        let Some(task) = cx
21895                            .update_window_entity(workspace, |workspace, window, cx| {
21896                                workspace
21897                                    .open_path_preview(path, None, false, false, false, window, cx)
21898                            })
21899                            .ok()
21900                        else {
21901                            continue;
21902                        };
21903                        task.await.log_err();
21904                    }
21905                }
21906            }
21907        })
21908        .detach();
21909        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21910            selections.refresh()
21911        });
21912    }
21913
21914    pub fn to_pixel_point(
21915        &self,
21916        source: multi_buffer::Anchor,
21917        editor_snapshot: &EditorSnapshot,
21918        window: &mut Window,
21919    ) -> Option<gpui::Point<Pixels>> {
21920        let source_point = source.to_display_point(editor_snapshot);
21921        self.display_to_pixel_point(source_point, editor_snapshot, window)
21922    }
21923
21924    pub fn display_to_pixel_point(
21925        &self,
21926        source: DisplayPoint,
21927        editor_snapshot: &EditorSnapshot,
21928        window: &mut Window,
21929    ) -> Option<gpui::Point<Pixels>> {
21930        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21931        let text_layout_details = self.text_layout_details(window);
21932        let scroll_top = text_layout_details
21933            .scroll_anchor
21934            .scroll_position(editor_snapshot)
21935            .y;
21936
21937        if source.row().as_f64() < scroll_top.floor() {
21938            return None;
21939        }
21940        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21941        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21942        Some(gpui::Point::new(source_x, source_y))
21943    }
21944
21945    pub fn has_visible_completions_menu(&self) -> bool {
21946        !self.edit_prediction_preview_is_active()
21947            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21948                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21949            })
21950    }
21951
21952    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21953        if self.mode.is_minimap() {
21954            return;
21955        }
21956        self.addons
21957            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21958    }
21959
21960    pub fn unregister_addon<T: Addon>(&mut self) {
21961        self.addons.remove(&std::any::TypeId::of::<T>());
21962    }
21963
21964    pub fn addon<T: Addon>(&self) -> Option<&T> {
21965        let type_id = std::any::TypeId::of::<T>();
21966        self.addons
21967            .get(&type_id)
21968            .and_then(|item| item.to_any().downcast_ref::<T>())
21969    }
21970
21971    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21972        let type_id = std::any::TypeId::of::<T>();
21973        self.addons
21974            .get_mut(&type_id)
21975            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21976    }
21977
21978    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21979        let text_layout_details = self.text_layout_details(window);
21980        let style = &text_layout_details.editor_style;
21981        let font_id = window.text_system().resolve_font(&style.text.font());
21982        let font_size = style.text.font_size.to_pixels(window.rem_size());
21983        let line_height = style.text.line_height_in_pixels(window.rem_size());
21984        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21985        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21986
21987        CharacterDimensions {
21988            em_width,
21989            em_advance,
21990            line_height,
21991        }
21992    }
21993
21994    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21995        self.load_diff_task.clone()
21996    }
21997
21998    fn read_metadata_from_db(
21999        &mut self,
22000        item_id: u64,
22001        workspace_id: WorkspaceId,
22002        window: &mut Window,
22003        cx: &mut Context<Editor>,
22004    ) {
22005        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22006            && !self.mode.is_minimap()
22007            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22008        {
22009            let buffer_snapshot = OnceCell::new();
22010
22011            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22012                && !folds.is_empty()
22013            {
22014                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22015                self.fold_ranges(
22016                    folds
22017                        .into_iter()
22018                        .map(|(start, end)| {
22019                            snapshot.clip_offset(start, Bias::Left)
22020                                ..snapshot.clip_offset(end, Bias::Right)
22021                        })
22022                        .collect(),
22023                    false,
22024                    window,
22025                    cx,
22026                );
22027            }
22028
22029            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22030                && !selections.is_empty()
22031            {
22032                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22033                // skip adding the initial selection to selection history
22034                self.selection_history.mode = SelectionHistoryMode::Skipping;
22035                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22036                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22037                        snapshot.clip_offset(start, Bias::Left)
22038                            ..snapshot.clip_offset(end, Bias::Right)
22039                    }));
22040                });
22041                self.selection_history.mode = SelectionHistoryMode::Normal;
22042            };
22043        }
22044
22045        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22046    }
22047
22048    fn update_lsp_data(
22049        &mut self,
22050        ignore_cache: bool,
22051        for_buffer: Option<BufferId>,
22052        window: &mut Window,
22053        cx: &mut Context<'_, Self>,
22054    ) {
22055        self.pull_diagnostics(for_buffer, window, cx);
22056        self.refresh_colors(ignore_cache, for_buffer, window, cx);
22057    }
22058}
22059
22060fn edit_for_markdown_paste<'a>(
22061    buffer: &MultiBufferSnapshot,
22062    range: Range<usize>,
22063    to_insert: &'a str,
22064    url: Option<url::Url>,
22065) -> (Range<usize>, Cow<'a, str>) {
22066    if url.is_none() {
22067        return (range, Cow::Borrowed(to_insert));
22068    };
22069
22070    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22071
22072    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22073        Cow::Borrowed(to_insert)
22074    } else {
22075        Cow::Owned(format!("[{old_text}]({to_insert})"))
22076    };
22077    (range, new_text)
22078}
22079
22080fn vim_enabled(cx: &App) -> bool {
22081    vim_mode_setting::VimModeSetting::try_get(cx)
22082        .map(|vim_mode| vim_mode.0)
22083        .unwrap_or(false)
22084}
22085
22086fn process_completion_for_edit(
22087    completion: &Completion,
22088    intent: CompletionIntent,
22089    buffer: &Entity<Buffer>,
22090    cursor_position: &text::Anchor,
22091    cx: &mut Context<Editor>,
22092) -> CompletionEdit {
22093    let buffer = buffer.read(cx);
22094    let buffer_snapshot = buffer.snapshot();
22095    let (snippet, new_text) = if completion.is_snippet() {
22096        let mut snippet_source = completion.new_text.clone();
22097        // Workaround for typescript language server issues so that methods don't expand within
22098        // strings and functions with type expressions. The previous point is used because the query
22099        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22100        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22101        let previous_point = if previous_point.column > 0 {
22102            cursor_position.to_previous_offset(&buffer_snapshot)
22103        } else {
22104            cursor_position.to_offset(&buffer_snapshot)
22105        };
22106        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22107            && scope.prefers_label_for_snippet_in_completion()
22108            && let Some(label) = completion.label()
22109            && matches!(
22110                completion.kind(),
22111                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22112            )
22113        {
22114            snippet_source = label;
22115        }
22116        match Snippet::parse(&snippet_source).log_err() {
22117            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22118            None => (None, completion.new_text.clone()),
22119        }
22120    } else {
22121        (None, completion.new_text.clone())
22122    };
22123
22124    let mut range_to_replace = {
22125        let replace_range = &completion.replace_range;
22126        if let CompletionSource::Lsp {
22127            insert_range: Some(insert_range),
22128            ..
22129        } = &completion.source
22130        {
22131            debug_assert_eq!(
22132                insert_range.start, replace_range.start,
22133                "insert_range and replace_range should start at the same position"
22134            );
22135            debug_assert!(
22136                insert_range
22137                    .start
22138                    .cmp(cursor_position, &buffer_snapshot)
22139                    .is_le(),
22140                "insert_range should start before or at cursor position"
22141            );
22142            debug_assert!(
22143                replace_range
22144                    .start
22145                    .cmp(cursor_position, &buffer_snapshot)
22146                    .is_le(),
22147                "replace_range should start before or at cursor position"
22148            );
22149
22150            let should_replace = match intent {
22151                CompletionIntent::CompleteWithInsert => false,
22152                CompletionIntent::CompleteWithReplace => true,
22153                CompletionIntent::Complete | CompletionIntent::Compose => {
22154                    let insert_mode =
22155                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22156                            .completions
22157                            .lsp_insert_mode;
22158                    match insert_mode {
22159                        LspInsertMode::Insert => false,
22160                        LspInsertMode::Replace => true,
22161                        LspInsertMode::ReplaceSubsequence => {
22162                            let mut text_to_replace = buffer.chars_for_range(
22163                                buffer.anchor_before(replace_range.start)
22164                                    ..buffer.anchor_after(replace_range.end),
22165                            );
22166                            let mut current_needle = text_to_replace.next();
22167                            for haystack_ch in completion.label.text.chars() {
22168                                if let Some(needle_ch) = current_needle
22169                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22170                                {
22171                                    current_needle = text_to_replace.next();
22172                                }
22173                            }
22174                            current_needle.is_none()
22175                        }
22176                        LspInsertMode::ReplaceSuffix => {
22177                            if replace_range
22178                                .end
22179                                .cmp(cursor_position, &buffer_snapshot)
22180                                .is_gt()
22181                            {
22182                                let range_after_cursor = *cursor_position..replace_range.end;
22183                                let text_after_cursor = buffer
22184                                    .text_for_range(
22185                                        buffer.anchor_before(range_after_cursor.start)
22186                                            ..buffer.anchor_after(range_after_cursor.end),
22187                                    )
22188                                    .collect::<String>()
22189                                    .to_ascii_lowercase();
22190                                completion
22191                                    .label
22192                                    .text
22193                                    .to_ascii_lowercase()
22194                                    .ends_with(&text_after_cursor)
22195                            } else {
22196                                true
22197                            }
22198                        }
22199                    }
22200                }
22201            };
22202
22203            if should_replace {
22204                replace_range.clone()
22205            } else {
22206                insert_range.clone()
22207            }
22208        } else {
22209            replace_range.clone()
22210        }
22211    };
22212
22213    if range_to_replace
22214        .end
22215        .cmp(cursor_position, &buffer_snapshot)
22216        .is_lt()
22217    {
22218        range_to_replace.end = *cursor_position;
22219    }
22220
22221    CompletionEdit {
22222        new_text,
22223        replace_range: range_to_replace.to_offset(buffer),
22224        snippet,
22225    }
22226}
22227
22228struct CompletionEdit {
22229    new_text: String,
22230    replace_range: Range<usize>,
22231    snippet: Option<Snippet>,
22232}
22233
22234fn insert_extra_newline_brackets(
22235    buffer: &MultiBufferSnapshot,
22236    range: Range<usize>,
22237    language: &language::LanguageScope,
22238) -> bool {
22239    let leading_whitespace_len = buffer
22240        .reversed_chars_at(range.start)
22241        .take_while(|c| c.is_whitespace() && *c != '\n')
22242        .map(|c| c.len_utf8())
22243        .sum::<usize>();
22244    let trailing_whitespace_len = buffer
22245        .chars_at(range.end)
22246        .take_while(|c| c.is_whitespace() && *c != '\n')
22247        .map(|c| c.len_utf8())
22248        .sum::<usize>();
22249    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22250
22251    language.brackets().any(|(pair, enabled)| {
22252        let pair_start = pair.start.trim_end();
22253        let pair_end = pair.end.trim_start();
22254
22255        enabled
22256            && pair.newline
22257            && buffer.contains_str_at(range.end, pair_end)
22258            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22259    })
22260}
22261
22262fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22263    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22264        [(buffer, range, _)] => (*buffer, range.clone()),
22265        _ => return false,
22266    };
22267    let pair = {
22268        let mut result: Option<BracketMatch> = None;
22269
22270        for pair in buffer
22271            .all_bracket_ranges(range.clone())
22272            .filter(move |pair| {
22273                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22274            })
22275        {
22276            let len = pair.close_range.end - pair.open_range.start;
22277
22278            if let Some(existing) = &result {
22279                let existing_len = existing.close_range.end - existing.open_range.start;
22280                if len > existing_len {
22281                    continue;
22282                }
22283            }
22284
22285            result = Some(pair);
22286        }
22287
22288        result
22289    };
22290    let Some(pair) = pair else {
22291        return false;
22292    };
22293    pair.newline_only
22294        && buffer
22295            .chars_for_range(pair.open_range.end..range.start)
22296            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22297            .all(|c| c.is_whitespace() && c != '\n')
22298}
22299
22300fn update_uncommitted_diff_for_buffer(
22301    editor: Entity<Editor>,
22302    project: &Entity<Project>,
22303    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22304    buffer: Entity<MultiBuffer>,
22305    cx: &mut App,
22306) -> Task<()> {
22307    let mut tasks = Vec::new();
22308    project.update(cx, |project, cx| {
22309        for buffer in buffers {
22310            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22311                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22312            }
22313        }
22314    });
22315    cx.spawn(async move |cx| {
22316        let diffs = future::join_all(tasks).await;
22317        if editor
22318            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22319            .unwrap_or(false)
22320        {
22321            return;
22322        }
22323
22324        buffer
22325            .update(cx, |buffer, cx| {
22326                for diff in diffs.into_iter().flatten() {
22327                    buffer.add_diff(diff, cx);
22328                }
22329            })
22330            .ok();
22331    })
22332}
22333
22334fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22335    let tab_size = tab_size.get() as usize;
22336    let mut width = offset;
22337
22338    for ch in text.chars() {
22339        width += if ch == '\t' {
22340            tab_size - (width % tab_size)
22341        } else {
22342            1
22343        };
22344    }
22345
22346    width - offset
22347}
22348
22349#[cfg(test)]
22350mod tests {
22351    use super::*;
22352
22353    #[test]
22354    fn test_string_size_with_expanded_tabs() {
22355        let nz = |val| NonZeroU32::new(val).unwrap();
22356        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22357        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22358        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22359        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22360        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22361        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22362        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22363        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22364    }
22365}
22366
22367/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22368struct WordBreakingTokenizer<'a> {
22369    input: &'a str,
22370}
22371
22372impl<'a> WordBreakingTokenizer<'a> {
22373    fn new(input: &'a str) -> Self {
22374        Self { input }
22375    }
22376}
22377
22378fn is_char_ideographic(ch: char) -> bool {
22379    use unicode_script::Script::*;
22380    use unicode_script::UnicodeScript;
22381    matches!(ch.script(), Han | Tangut | Yi)
22382}
22383
22384fn is_grapheme_ideographic(text: &str) -> bool {
22385    text.chars().any(is_char_ideographic)
22386}
22387
22388fn is_grapheme_whitespace(text: &str) -> bool {
22389    text.chars().any(|x| x.is_whitespace())
22390}
22391
22392fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22393    text.chars()
22394        .next()
22395        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22396}
22397
22398#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22399enum WordBreakToken<'a> {
22400    Word { token: &'a str, grapheme_len: usize },
22401    InlineWhitespace { token: &'a str, grapheme_len: usize },
22402    Newline,
22403}
22404
22405impl<'a> Iterator for WordBreakingTokenizer<'a> {
22406    /// Yields a span, the count of graphemes in the token, and whether it was
22407    /// whitespace. Note that it also breaks at word boundaries.
22408    type Item = WordBreakToken<'a>;
22409
22410    fn next(&mut self) -> Option<Self::Item> {
22411        use unicode_segmentation::UnicodeSegmentation;
22412        if self.input.is_empty() {
22413            return None;
22414        }
22415
22416        let mut iter = self.input.graphemes(true).peekable();
22417        let mut offset = 0;
22418        let mut grapheme_len = 0;
22419        if let Some(first_grapheme) = iter.next() {
22420            let is_newline = first_grapheme == "\n";
22421            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22422            offset += first_grapheme.len();
22423            grapheme_len += 1;
22424            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22425                if let Some(grapheme) = iter.peek().copied()
22426                    && should_stay_with_preceding_ideograph(grapheme)
22427                {
22428                    offset += grapheme.len();
22429                    grapheme_len += 1;
22430                }
22431            } else {
22432                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22433                let mut next_word_bound = words.peek().copied();
22434                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22435                    next_word_bound = words.next();
22436                }
22437                while let Some(grapheme) = iter.peek().copied() {
22438                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22439                        break;
22440                    };
22441                    if is_grapheme_whitespace(grapheme) != is_whitespace
22442                        || (grapheme == "\n") != is_newline
22443                    {
22444                        break;
22445                    };
22446                    offset += grapheme.len();
22447                    grapheme_len += 1;
22448                    iter.next();
22449                }
22450            }
22451            let token = &self.input[..offset];
22452            self.input = &self.input[offset..];
22453            if token == "\n" {
22454                Some(WordBreakToken::Newline)
22455            } else if is_whitespace {
22456                Some(WordBreakToken::InlineWhitespace {
22457                    token,
22458                    grapheme_len,
22459                })
22460            } else {
22461                Some(WordBreakToken::Word {
22462                    token,
22463                    grapheme_len,
22464                })
22465            }
22466        } else {
22467            None
22468        }
22469    }
22470}
22471
22472#[test]
22473fn test_word_breaking_tokenizer() {
22474    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22475        ("", &[]),
22476        ("  ", &[whitespace("  ", 2)]),
22477        ("Ʒ", &[word("Ʒ", 1)]),
22478        ("Ǽ", &[word("Ǽ", 1)]),
22479        ("", &[word("", 1)]),
22480        ("⋑⋑", &[word("⋑⋑", 2)]),
22481        (
22482            "原理,进而",
22483            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22484        ),
22485        (
22486            "hello world",
22487            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22488        ),
22489        (
22490            "hello, world",
22491            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22492        ),
22493        (
22494            "  hello world",
22495            &[
22496                whitespace("  ", 2),
22497                word("hello", 5),
22498                whitespace(" ", 1),
22499                word("world", 5),
22500            ],
22501        ),
22502        (
22503            "这是什么 \n 钢笔",
22504            &[
22505                word("", 1),
22506                word("", 1),
22507                word("", 1),
22508                word("", 1),
22509                whitespace(" ", 1),
22510                newline(),
22511                whitespace(" ", 1),
22512                word("", 1),
22513                word("", 1),
22514            ],
22515        ),
22516        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22517    ];
22518
22519    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22520        WordBreakToken::Word {
22521            token,
22522            grapheme_len,
22523        }
22524    }
22525
22526    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22527        WordBreakToken::InlineWhitespace {
22528            token,
22529            grapheme_len,
22530        }
22531    }
22532
22533    fn newline() -> WordBreakToken<'static> {
22534        WordBreakToken::Newline
22535    }
22536
22537    for (input, result) in tests {
22538        assert_eq!(
22539            WordBreakingTokenizer::new(input)
22540                .collect::<Vec<_>>()
22541                .as_slice(),
22542            *result,
22543        );
22544    }
22545}
22546
22547fn wrap_with_prefix(
22548    first_line_prefix: String,
22549    subsequent_lines_prefix: String,
22550    unwrapped_text: String,
22551    wrap_column: usize,
22552    tab_size: NonZeroU32,
22553    preserve_existing_whitespace: bool,
22554) -> String {
22555    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22556    let subsequent_lines_prefix_len =
22557        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22558    let mut wrapped_text = String::new();
22559    let mut current_line = first_line_prefix;
22560    let mut is_first_line = true;
22561
22562    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22563    let mut current_line_len = first_line_prefix_len;
22564    let mut in_whitespace = false;
22565    for token in tokenizer {
22566        let have_preceding_whitespace = in_whitespace;
22567        match token {
22568            WordBreakToken::Word {
22569                token,
22570                grapheme_len,
22571            } => {
22572                in_whitespace = false;
22573                let current_prefix_len = if is_first_line {
22574                    first_line_prefix_len
22575                } else {
22576                    subsequent_lines_prefix_len
22577                };
22578                if current_line_len + grapheme_len > wrap_column
22579                    && current_line_len != current_prefix_len
22580                {
22581                    wrapped_text.push_str(current_line.trim_end());
22582                    wrapped_text.push('\n');
22583                    is_first_line = false;
22584                    current_line = subsequent_lines_prefix.clone();
22585                    current_line_len = subsequent_lines_prefix_len;
22586                }
22587                current_line.push_str(token);
22588                current_line_len += grapheme_len;
22589            }
22590            WordBreakToken::InlineWhitespace {
22591                mut token,
22592                mut grapheme_len,
22593            } => {
22594                in_whitespace = true;
22595                if have_preceding_whitespace && !preserve_existing_whitespace {
22596                    continue;
22597                }
22598                if !preserve_existing_whitespace {
22599                    // Keep a single whitespace grapheme as-is
22600                    if let Some(first) =
22601                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22602                    {
22603                        token = first;
22604                    } else {
22605                        token = " ";
22606                    }
22607                    grapheme_len = 1;
22608                }
22609                let current_prefix_len = if is_first_line {
22610                    first_line_prefix_len
22611                } else {
22612                    subsequent_lines_prefix_len
22613                };
22614                if current_line_len + grapheme_len > wrap_column {
22615                    wrapped_text.push_str(current_line.trim_end());
22616                    wrapped_text.push('\n');
22617                    is_first_line = false;
22618                    current_line = subsequent_lines_prefix.clone();
22619                    current_line_len = subsequent_lines_prefix_len;
22620                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22621                    current_line.push_str(token);
22622                    current_line_len += grapheme_len;
22623                }
22624            }
22625            WordBreakToken::Newline => {
22626                in_whitespace = true;
22627                let current_prefix_len = if is_first_line {
22628                    first_line_prefix_len
22629                } else {
22630                    subsequent_lines_prefix_len
22631                };
22632                if preserve_existing_whitespace {
22633                    wrapped_text.push_str(current_line.trim_end());
22634                    wrapped_text.push('\n');
22635                    is_first_line = false;
22636                    current_line = subsequent_lines_prefix.clone();
22637                    current_line_len = subsequent_lines_prefix_len;
22638                } else if have_preceding_whitespace {
22639                    continue;
22640                } else if current_line_len + 1 > wrap_column
22641                    && current_line_len != current_prefix_len
22642                {
22643                    wrapped_text.push_str(current_line.trim_end());
22644                    wrapped_text.push('\n');
22645                    is_first_line = false;
22646                    current_line = subsequent_lines_prefix.clone();
22647                    current_line_len = subsequent_lines_prefix_len;
22648                } else if current_line_len != current_prefix_len {
22649                    current_line.push(' ');
22650                    current_line_len += 1;
22651                }
22652            }
22653        }
22654    }
22655
22656    if !current_line.is_empty() {
22657        wrapped_text.push_str(&current_line);
22658    }
22659    wrapped_text
22660}
22661
22662#[test]
22663fn test_wrap_with_prefix() {
22664    assert_eq!(
22665        wrap_with_prefix(
22666            "# ".to_string(),
22667            "# ".to_string(),
22668            "abcdefg".to_string(),
22669            4,
22670            NonZeroU32::new(4).unwrap(),
22671            false,
22672        ),
22673        "# abcdefg"
22674    );
22675    assert_eq!(
22676        wrap_with_prefix(
22677            "".to_string(),
22678            "".to_string(),
22679            "\thello world".to_string(),
22680            8,
22681            NonZeroU32::new(4).unwrap(),
22682            false,
22683        ),
22684        "hello\nworld"
22685    );
22686    assert_eq!(
22687        wrap_with_prefix(
22688            "// ".to_string(),
22689            "// ".to_string(),
22690            "xx \nyy zz aa bb cc".to_string(),
22691            12,
22692            NonZeroU32::new(4).unwrap(),
22693            false,
22694        ),
22695        "// xx yy zz\n// aa bb cc"
22696    );
22697    assert_eq!(
22698        wrap_with_prefix(
22699            String::new(),
22700            String::new(),
22701            "这是什么 \n 钢笔".to_string(),
22702            3,
22703            NonZeroU32::new(4).unwrap(),
22704            false,
22705        ),
22706        "这是什\n么 钢\n"
22707    );
22708    assert_eq!(
22709        wrap_with_prefix(
22710            String::new(),
22711            String::new(),
22712            format!("foo{}bar", '\u{2009}'), // thin space
22713            80,
22714            NonZeroU32::new(4).unwrap(),
22715            false,
22716        ),
22717        format!("foo{}bar", '\u{2009}')
22718    );
22719}
22720
22721pub trait CollaborationHub {
22722    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22723    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22724    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22725}
22726
22727impl CollaborationHub for Entity<Project> {
22728    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22729        self.read(cx).collaborators()
22730    }
22731
22732    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22733        self.read(cx).user_store().read(cx).participant_indices()
22734    }
22735
22736    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22737        let this = self.read(cx);
22738        let user_ids = this.collaborators().values().map(|c| c.user_id);
22739        this.user_store().read(cx).participant_names(user_ids, cx)
22740    }
22741}
22742
22743pub trait SemanticsProvider {
22744    fn hover(
22745        &self,
22746        buffer: &Entity<Buffer>,
22747        position: text::Anchor,
22748        cx: &mut App,
22749    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22750
22751    fn inline_values(
22752        &self,
22753        buffer_handle: Entity<Buffer>,
22754        range: Range<text::Anchor>,
22755        cx: &mut App,
22756    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22757
22758    fn inlay_hints(
22759        &self,
22760        buffer_handle: Entity<Buffer>,
22761        range: Range<text::Anchor>,
22762        cx: &mut App,
22763    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22764
22765    fn resolve_inlay_hint(
22766        &self,
22767        hint: InlayHint,
22768        buffer_handle: Entity<Buffer>,
22769        server_id: LanguageServerId,
22770        cx: &mut App,
22771    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22772
22773    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22774
22775    fn document_highlights(
22776        &self,
22777        buffer: &Entity<Buffer>,
22778        position: text::Anchor,
22779        cx: &mut App,
22780    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22781
22782    fn definitions(
22783        &self,
22784        buffer: &Entity<Buffer>,
22785        position: text::Anchor,
22786        kind: GotoDefinitionKind,
22787        cx: &mut App,
22788    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22789
22790    fn range_for_rename(
22791        &self,
22792        buffer: &Entity<Buffer>,
22793        position: text::Anchor,
22794        cx: &mut App,
22795    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22796
22797    fn perform_rename(
22798        &self,
22799        buffer: &Entity<Buffer>,
22800        position: text::Anchor,
22801        new_name: String,
22802        cx: &mut App,
22803    ) -> Option<Task<Result<ProjectTransaction>>>;
22804}
22805
22806pub trait CompletionProvider {
22807    fn completions(
22808        &self,
22809        excerpt_id: ExcerptId,
22810        buffer: &Entity<Buffer>,
22811        buffer_position: text::Anchor,
22812        trigger: CompletionContext,
22813        window: &mut Window,
22814        cx: &mut Context<Editor>,
22815    ) -> Task<Result<Vec<CompletionResponse>>>;
22816
22817    fn resolve_completions(
22818        &self,
22819        _buffer: Entity<Buffer>,
22820        _completion_indices: Vec<usize>,
22821        _completions: Rc<RefCell<Box<[Completion]>>>,
22822        _cx: &mut Context<Editor>,
22823    ) -> Task<Result<bool>> {
22824        Task::ready(Ok(false))
22825    }
22826
22827    fn apply_additional_edits_for_completion(
22828        &self,
22829        _buffer: Entity<Buffer>,
22830        _completions: Rc<RefCell<Box<[Completion]>>>,
22831        _completion_index: usize,
22832        _push_to_history: bool,
22833        _cx: &mut Context<Editor>,
22834    ) -> Task<Result<Option<language::Transaction>>> {
22835        Task::ready(Ok(None))
22836    }
22837
22838    fn is_completion_trigger(
22839        &self,
22840        buffer: &Entity<Buffer>,
22841        position: language::Anchor,
22842        text: &str,
22843        trigger_in_words: bool,
22844        menu_is_open: bool,
22845        cx: &mut Context<Editor>,
22846    ) -> bool;
22847
22848    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22849
22850    fn sort_completions(&self) -> bool {
22851        true
22852    }
22853
22854    fn filter_completions(&self) -> bool {
22855        true
22856    }
22857}
22858
22859pub trait CodeActionProvider {
22860    fn id(&self) -> Arc<str>;
22861
22862    fn code_actions(
22863        &self,
22864        buffer: &Entity<Buffer>,
22865        range: Range<text::Anchor>,
22866        window: &mut Window,
22867        cx: &mut App,
22868    ) -> Task<Result<Vec<CodeAction>>>;
22869
22870    fn apply_code_action(
22871        &self,
22872        buffer_handle: Entity<Buffer>,
22873        action: CodeAction,
22874        excerpt_id: ExcerptId,
22875        push_to_history: bool,
22876        window: &mut Window,
22877        cx: &mut App,
22878    ) -> Task<Result<ProjectTransaction>>;
22879}
22880
22881impl CodeActionProvider for Entity<Project> {
22882    fn id(&self) -> Arc<str> {
22883        "project".into()
22884    }
22885
22886    fn code_actions(
22887        &self,
22888        buffer: &Entity<Buffer>,
22889        range: Range<text::Anchor>,
22890        _window: &mut Window,
22891        cx: &mut App,
22892    ) -> Task<Result<Vec<CodeAction>>> {
22893        self.update(cx, |project, cx| {
22894            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22895            let code_actions = project.code_actions(buffer, range, None, cx);
22896            cx.background_spawn(async move {
22897                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22898                Ok(code_lens_actions
22899                    .context("code lens fetch")?
22900                    .into_iter()
22901                    .flatten()
22902                    .chain(
22903                        code_actions
22904                            .context("code action fetch")?
22905                            .into_iter()
22906                            .flatten(),
22907                    )
22908                    .collect())
22909            })
22910        })
22911    }
22912
22913    fn apply_code_action(
22914        &self,
22915        buffer_handle: Entity<Buffer>,
22916        action: CodeAction,
22917        _excerpt_id: ExcerptId,
22918        push_to_history: bool,
22919        _window: &mut Window,
22920        cx: &mut App,
22921    ) -> Task<Result<ProjectTransaction>> {
22922        self.update(cx, |project, cx| {
22923            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22924        })
22925    }
22926}
22927
22928fn snippet_completions(
22929    project: &Project,
22930    buffer: &Entity<Buffer>,
22931    buffer_position: text::Anchor,
22932    cx: &mut App,
22933) -> Task<Result<CompletionResponse>> {
22934    let languages = buffer.read(cx).languages_at(buffer_position);
22935    let snippet_store = project.snippets().read(cx);
22936
22937    let scopes: Vec<_> = languages
22938        .iter()
22939        .filter_map(|language| {
22940            let language_name = language.lsp_id();
22941            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22942
22943            if snippets.is_empty() {
22944                None
22945            } else {
22946                Some((language.default_scope(), snippets))
22947            }
22948        })
22949        .collect();
22950
22951    if scopes.is_empty() {
22952        return Task::ready(Ok(CompletionResponse {
22953            completions: vec![],
22954            display_options: CompletionDisplayOptions::default(),
22955            is_incomplete: false,
22956        }));
22957    }
22958
22959    let snapshot = buffer.read(cx).text_snapshot();
22960    let executor = cx.background_executor().clone();
22961
22962    cx.background_spawn(async move {
22963        let mut is_incomplete = false;
22964        let mut completions: Vec<Completion> = Vec::new();
22965        for (scope, snippets) in scopes.into_iter() {
22966            let classifier =
22967                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22968
22969            const MAX_WORD_PREFIX_LEN: usize = 128;
22970            let last_word: String = snapshot
22971                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22972                .take(MAX_WORD_PREFIX_LEN)
22973                .take_while(|c| classifier.is_word(*c))
22974                .collect::<String>()
22975                .chars()
22976                .rev()
22977                .collect();
22978
22979            if last_word.is_empty() {
22980                return Ok(CompletionResponse {
22981                    completions: vec![],
22982                    display_options: CompletionDisplayOptions::default(),
22983                    is_incomplete: true,
22984                });
22985            }
22986
22987            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22988            let to_lsp = |point: &text::Anchor| {
22989                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22990                point_to_lsp(end)
22991            };
22992            let lsp_end = to_lsp(&buffer_position);
22993
22994            let candidates = snippets
22995                .iter()
22996                .enumerate()
22997                .flat_map(|(ix, snippet)| {
22998                    snippet
22999                        .prefix
23000                        .iter()
23001                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23002                })
23003                .collect::<Vec<StringMatchCandidate>>();
23004
23005            const MAX_RESULTS: usize = 100;
23006            let mut matches = fuzzy::match_strings(
23007                &candidates,
23008                &last_word,
23009                last_word.chars().any(|c| c.is_uppercase()),
23010                true,
23011                MAX_RESULTS,
23012                &Default::default(),
23013                executor.clone(),
23014            )
23015            .await;
23016
23017            if matches.len() >= MAX_RESULTS {
23018                is_incomplete = true;
23019            }
23020
23021            // Remove all candidates where the query's start does not match the start of any word in the candidate
23022            if let Some(query_start) = last_word.chars().next() {
23023                matches.retain(|string_match| {
23024                    split_words(&string_match.string).any(|word| {
23025                        // Check that the first codepoint of the word as lowercase matches the first
23026                        // codepoint of the query as lowercase
23027                        word.chars()
23028                            .flat_map(|codepoint| codepoint.to_lowercase())
23029                            .zip(query_start.to_lowercase())
23030                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23031                    })
23032                });
23033            }
23034
23035            let matched_strings = matches
23036                .into_iter()
23037                .map(|m| m.string)
23038                .collect::<HashSet<_>>();
23039
23040            completions.extend(snippets.iter().filter_map(|snippet| {
23041                let matching_prefix = snippet
23042                    .prefix
23043                    .iter()
23044                    .find(|prefix| matched_strings.contains(*prefix))?;
23045                let start = as_offset - last_word.len();
23046                let start = snapshot.anchor_before(start);
23047                let range = start..buffer_position;
23048                let lsp_start = to_lsp(&start);
23049                let lsp_range = lsp::Range {
23050                    start: lsp_start,
23051                    end: lsp_end,
23052                };
23053                Some(Completion {
23054                    replace_range: range,
23055                    new_text: snippet.body.clone(),
23056                    source: CompletionSource::Lsp {
23057                        insert_range: None,
23058                        server_id: LanguageServerId(usize::MAX),
23059                        resolved: true,
23060                        lsp_completion: Box::new(lsp::CompletionItem {
23061                            label: snippet.prefix.first().unwrap().clone(),
23062                            kind: Some(CompletionItemKind::SNIPPET),
23063                            label_details: snippet.description.as_ref().map(|description| {
23064                                lsp::CompletionItemLabelDetails {
23065                                    detail: Some(description.clone()),
23066                                    description: None,
23067                                }
23068                            }),
23069                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23070                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23071                                lsp::InsertReplaceEdit {
23072                                    new_text: snippet.body.clone(),
23073                                    insert: lsp_range,
23074                                    replace: lsp_range,
23075                                },
23076                            )),
23077                            filter_text: Some(snippet.body.clone()),
23078                            sort_text: Some(char::MAX.to_string()),
23079                            ..lsp::CompletionItem::default()
23080                        }),
23081                        lsp_defaults: None,
23082                    },
23083                    label: CodeLabel {
23084                        text: matching_prefix.clone(),
23085                        runs: Vec::new(),
23086                        filter_range: 0..matching_prefix.len(),
23087                    },
23088                    icon_path: None,
23089                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23090                        single_line: snippet.name.clone().into(),
23091                        plain_text: snippet
23092                            .description
23093                            .clone()
23094                            .map(|description| description.into()),
23095                    }),
23096                    insert_text_mode: None,
23097                    confirm: None,
23098                })
23099            }))
23100        }
23101
23102        Ok(CompletionResponse {
23103            completions,
23104            display_options: CompletionDisplayOptions::default(),
23105            is_incomplete,
23106        })
23107    })
23108}
23109
23110impl CompletionProvider for Entity<Project> {
23111    fn completions(
23112        &self,
23113        _excerpt_id: ExcerptId,
23114        buffer: &Entity<Buffer>,
23115        buffer_position: text::Anchor,
23116        options: CompletionContext,
23117        _window: &mut Window,
23118        cx: &mut Context<Editor>,
23119    ) -> Task<Result<Vec<CompletionResponse>>> {
23120        self.update(cx, |project, cx| {
23121            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23122            let project_completions = project.completions(buffer, buffer_position, options, cx);
23123            cx.background_spawn(async move {
23124                let mut responses = project_completions.await?;
23125                let snippets = snippets.await?;
23126                if !snippets.completions.is_empty() {
23127                    responses.push(snippets);
23128                }
23129                Ok(responses)
23130            })
23131        })
23132    }
23133
23134    fn resolve_completions(
23135        &self,
23136        buffer: Entity<Buffer>,
23137        completion_indices: Vec<usize>,
23138        completions: Rc<RefCell<Box<[Completion]>>>,
23139        cx: &mut Context<Editor>,
23140    ) -> Task<Result<bool>> {
23141        self.update(cx, |project, cx| {
23142            project.lsp_store().update(cx, |lsp_store, cx| {
23143                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23144            })
23145        })
23146    }
23147
23148    fn apply_additional_edits_for_completion(
23149        &self,
23150        buffer: Entity<Buffer>,
23151        completions: Rc<RefCell<Box<[Completion]>>>,
23152        completion_index: usize,
23153        push_to_history: bool,
23154        cx: &mut Context<Editor>,
23155    ) -> Task<Result<Option<language::Transaction>>> {
23156        self.update(cx, |project, cx| {
23157            project.lsp_store().update(cx, |lsp_store, cx| {
23158                lsp_store.apply_additional_edits_for_completion(
23159                    buffer,
23160                    completions,
23161                    completion_index,
23162                    push_to_history,
23163                    cx,
23164                )
23165            })
23166        })
23167    }
23168
23169    fn is_completion_trigger(
23170        &self,
23171        buffer: &Entity<Buffer>,
23172        position: language::Anchor,
23173        text: &str,
23174        trigger_in_words: bool,
23175        menu_is_open: bool,
23176        cx: &mut Context<Editor>,
23177    ) -> bool {
23178        let mut chars = text.chars();
23179        let char = if let Some(char) = chars.next() {
23180            char
23181        } else {
23182            return false;
23183        };
23184        if chars.next().is_some() {
23185            return false;
23186        }
23187
23188        let buffer = buffer.read(cx);
23189        let snapshot = buffer.snapshot();
23190        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23191            return false;
23192        }
23193        let classifier = snapshot
23194            .char_classifier_at(position)
23195            .scope_context(Some(CharScopeContext::Completion));
23196        if trigger_in_words && classifier.is_word(char) {
23197            return true;
23198        }
23199
23200        buffer.completion_triggers().contains(text)
23201    }
23202}
23203
23204impl SemanticsProvider for Entity<Project> {
23205    fn hover(
23206        &self,
23207        buffer: &Entity<Buffer>,
23208        position: text::Anchor,
23209        cx: &mut App,
23210    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23211        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23212    }
23213
23214    fn document_highlights(
23215        &self,
23216        buffer: &Entity<Buffer>,
23217        position: text::Anchor,
23218        cx: &mut App,
23219    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23220        Some(self.update(cx, |project, cx| {
23221            project.document_highlights(buffer, position, cx)
23222        }))
23223    }
23224
23225    fn definitions(
23226        &self,
23227        buffer: &Entity<Buffer>,
23228        position: text::Anchor,
23229        kind: GotoDefinitionKind,
23230        cx: &mut App,
23231    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23232        Some(self.update(cx, |project, cx| match kind {
23233            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23234            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23235            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23236            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23237        }))
23238    }
23239
23240    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23241        self.update(cx, |project, cx| {
23242            if project
23243                .active_debug_session(cx)
23244                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23245            {
23246                return true;
23247            }
23248
23249            buffer.update(cx, |buffer, cx| {
23250                project.any_language_server_supports_inlay_hints(buffer, cx)
23251            })
23252        })
23253    }
23254
23255    fn inline_values(
23256        &self,
23257        buffer_handle: Entity<Buffer>,
23258        range: Range<text::Anchor>,
23259        cx: &mut App,
23260    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23261        self.update(cx, |project, cx| {
23262            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23263
23264            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23265        })
23266    }
23267
23268    fn inlay_hints(
23269        &self,
23270        buffer_handle: Entity<Buffer>,
23271        range: Range<text::Anchor>,
23272        cx: &mut App,
23273    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23274        Some(self.update(cx, |project, cx| {
23275            project.inlay_hints(buffer_handle, range, cx)
23276        }))
23277    }
23278
23279    fn resolve_inlay_hint(
23280        &self,
23281        hint: InlayHint,
23282        buffer_handle: Entity<Buffer>,
23283        server_id: LanguageServerId,
23284        cx: &mut App,
23285    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23286        Some(self.update(cx, |project, cx| {
23287            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23288        }))
23289    }
23290
23291    fn range_for_rename(
23292        &self,
23293        buffer: &Entity<Buffer>,
23294        position: text::Anchor,
23295        cx: &mut App,
23296    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23297        Some(self.update(cx, |project, cx| {
23298            let buffer = buffer.clone();
23299            let task = project.prepare_rename(buffer.clone(), position, cx);
23300            cx.spawn(async move |_, cx| {
23301                Ok(match task.await? {
23302                    PrepareRenameResponse::Success(range) => Some(range),
23303                    PrepareRenameResponse::InvalidPosition => None,
23304                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23305                        // Fallback on using TreeSitter info to determine identifier range
23306                        buffer.read_with(cx, |buffer, _| {
23307                            let snapshot = buffer.snapshot();
23308                            let (range, kind) = snapshot.surrounding_word(position, None);
23309                            if kind != Some(CharKind::Word) {
23310                                return None;
23311                            }
23312                            Some(
23313                                snapshot.anchor_before(range.start)
23314                                    ..snapshot.anchor_after(range.end),
23315                            )
23316                        })?
23317                    }
23318                })
23319            })
23320        }))
23321    }
23322
23323    fn perform_rename(
23324        &self,
23325        buffer: &Entity<Buffer>,
23326        position: text::Anchor,
23327        new_name: String,
23328        cx: &mut App,
23329    ) -> Option<Task<Result<ProjectTransaction>>> {
23330        Some(self.update(cx, |project, cx| {
23331            project.perform_rename(buffer.clone(), position, new_name, cx)
23332        }))
23333    }
23334}
23335
23336fn inlay_hint_settings(
23337    location: Anchor,
23338    snapshot: &MultiBufferSnapshot,
23339    cx: &mut Context<Editor>,
23340) -> InlayHintSettings {
23341    let file = snapshot.file_at(location);
23342    let language = snapshot.language_at(location).map(|l| l.name());
23343    language_settings(language, file, cx).inlay_hints
23344}
23345
23346fn consume_contiguous_rows(
23347    contiguous_row_selections: &mut Vec<Selection<Point>>,
23348    selection: &Selection<Point>,
23349    display_map: &DisplaySnapshot,
23350    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23351) -> (MultiBufferRow, MultiBufferRow) {
23352    contiguous_row_selections.push(selection.clone());
23353    let start_row = starting_row(selection, display_map);
23354    let mut end_row = ending_row(selection, display_map);
23355
23356    while let Some(next_selection) = selections.peek() {
23357        if next_selection.start.row <= end_row.0 {
23358            end_row = ending_row(next_selection, display_map);
23359            contiguous_row_selections.push(selections.next().unwrap().clone());
23360        } else {
23361            break;
23362        }
23363    }
23364    (start_row, end_row)
23365}
23366
23367fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23368    if selection.start.column > 0 {
23369        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23370    } else {
23371        MultiBufferRow(selection.start.row)
23372    }
23373}
23374
23375fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23376    if next_selection.end.column > 0 || next_selection.is_empty() {
23377        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23378    } else {
23379        MultiBufferRow(next_selection.end.row)
23380    }
23381}
23382
23383impl EditorSnapshot {
23384    pub fn remote_selections_in_range<'a>(
23385        &'a self,
23386        range: &'a Range<Anchor>,
23387        collaboration_hub: &dyn CollaborationHub,
23388        cx: &'a App,
23389    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23390        let participant_names = collaboration_hub.user_names(cx);
23391        let participant_indices = collaboration_hub.user_participant_indices(cx);
23392        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23393        let collaborators_by_replica_id = collaborators_by_peer_id
23394            .values()
23395            .map(|collaborator| (collaborator.replica_id, collaborator))
23396            .collect::<HashMap<_, _>>();
23397        self.buffer_snapshot()
23398            .selections_in_range(range, false)
23399            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23400                if replica_id == AGENT_REPLICA_ID {
23401                    Some(RemoteSelection {
23402                        replica_id,
23403                        selection,
23404                        cursor_shape,
23405                        line_mode,
23406                        collaborator_id: CollaboratorId::Agent,
23407                        user_name: Some("Agent".into()),
23408                        color: cx.theme().players().agent(),
23409                    })
23410                } else {
23411                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23412                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23413                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23414                    Some(RemoteSelection {
23415                        replica_id,
23416                        selection,
23417                        cursor_shape,
23418                        line_mode,
23419                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23420                        user_name,
23421                        color: if let Some(index) = participant_index {
23422                            cx.theme().players().color_for_participant(index.0)
23423                        } else {
23424                            cx.theme().players().absent()
23425                        },
23426                    })
23427                }
23428            })
23429    }
23430
23431    pub fn hunks_for_ranges(
23432        &self,
23433        ranges: impl IntoIterator<Item = Range<Point>>,
23434    ) -> Vec<MultiBufferDiffHunk> {
23435        let mut hunks = Vec::new();
23436        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23437            HashMap::default();
23438        for query_range in ranges {
23439            let query_rows =
23440                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23441            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23442                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23443            ) {
23444                // Include deleted hunks that are adjacent to the query range, because
23445                // otherwise they would be missed.
23446                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23447                if hunk.status().is_deleted() {
23448                    intersects_range |= hunk.row_range.start == query_rows.end;
23449                    intersects_range |= hunk.row_range.end == query_rows.start;
23450                }
23451                if intersects_range {
23452                    if !processed_buffer_rows
23453                        .entry(hunk.buffer_id)
23454                        .or_default()
23455                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23456                    {
23457                        continue;
23458                    }
23459                    hunks.push(hunk);
23460                }
23461            }
23462        }
23463
23464        hunks
23465    }
23466
23467    fn display_diff_hunks_for_rows<'a>(
23468        &'a self,
23469        display_rows: Range<DisplayRow>,
23470        folded_buffers: &'a HashSet<BufferId>,
23471    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23472        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23473        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23474
23475        self.buffer_snapshot()
23476            .diff_hunks_in_range(buffer_start..buffer_end)
23477            .filter_map(|hunk| {
23478                if folded_buffers.contains(&hunk.buffer_id) {
23479                    return None;
23480                }
23481
23482                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23483                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23484
23485                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23486                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23487
23488                let display_hunk = if hunk_display_start.column() != 0 {
23489                    DisplayDiffHunk::Folded {
23490                        display_row: hunk_display_start.row(),
23491                    }
23492                } else {
23493                    let mut end_row = hunk_display_end.row();
23494                    if hunk_display_end.column() > 0 {
23495                        end_row.0 += 1;
23496                    }
23497                    let is_created_file = hunk.is_created_file();
23498                    DisplayDiffHunk::Unfolded {
23499                        status: hunk.status(),
23500                        diff_base_byte_range: hunk.diff_base_byte_range,
23501                        display_row_range: hunk_display_start.row()..end_row,
23502                        multi_buffer_range: Anchor::range_in_buffer(
23503                            hunk.excerpt_id,
23504                            hunk.buffer_id,
23505                            hunk.buffer_range,
23506                        ),
23507                        is_created_file,
23508                    }
23509                };
23510
23511                Some(display_hunk)
23512            })
23513    }
23514
23515    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23516        self.display_snapshot
23517            .buffer_snapshot()
23518            .language_at(position)
23519    }
23520
23521    pub fn is_focused(&self) -> bool {
23522        self.is_focused
23523    }
23524
23525    pub fn placeholder_text(&self) -> Option<String> {
23526        self.placeholder_display_snapshot
23527            .as_ref()
23528            .map(|display_map| display_map.text())
23529    }
23530
23531    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23532        self.scroll_anchor.scroll_position(&self.display_snapshot)
23533    }
23534
23535    fn gutter_dimensions(
23536        &self,
23537        font_id: FontId,
23538        font_size: Pixels,
23539        max_line_number_width: Pixels,
23540        cx: &App,
23541    ) -> Option<GutterDimensions> {
23542        if !self.show_gutter {
23543            return None;
23544        }
23545
23546        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23547        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23548
23549        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23550            matches!(
23551                ProjectSettings::get_global(cx).git.git_gutter,
23552                GitGutterSetting::TrackedFiles
23553            )
23554        });
23555        let gutter_settings = EditorSettings::get_global(cx).gutter;
23556        let show_line_numbers = self
23557            .show_line_numbers
23558            .unwrap_or(gutter_settings.line_numbers);
23559        let line_gutter_width = if show_line_numbers {
23560            // Avoid flicker-like gutter resizes when the line number gains another digit by
23561            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23562            let min_width_for_number_on_gutter =
23563                ch_advance * gutter_settings.min_line_number_digits as f32;
23564            max_line_number_width.max(min_width_for_number_on_gutter)
23565        } else {
23566            0.0.into()
23567        };
23568
23569        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23570        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23571
23572        let git_blame_entries_width =
23573            self.git_blame_gutter_max_author_length
23574                .map(|max_author_length| {
23575                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23576                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23577
23578                    /// The number of characters to dedicate to gaps and margins.
23579                    const SPACING_WIDTH: usize = 4;
23580
23581                    let max_char_count = max_author_length.min(renderer.max_author_length())
23582                        + ::git::SHORT_SHA_LENGTH
23583                        + MAX_RELATIVE_TIMESTAMP.len()
23584                        + SPACING_WIDTH;
23585
23586                    ch_advance * max_char_count
23587                });
23588
23589        let is_singleton = self.buffer_snapshot().is_singleton();
23590
23591        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23592        left_padding += if !is_singleton {
23593            ch_width * 4.0
23594        } else if show_runnables || show_breakpoints {
23595            ch_width * 3.0
23596        } else if show_git_gutter && show_line_numbers {
23597            ch_width * 2.0
23598        } else if show_git_gutter || show_line_numbers {
23599            ch_width
23600        } else {
23601            px(0.)
23602        };
23603
23604        let shows_folds = is_singleton && gutter_settings.folds;
23605
23606        let right_padding = if shows_folds && show_line_numbers {
23607            ch_width * 4.0
23608        } else if shows_folds || (!is_singleton && show_line_numbers) {
23609            ch_width * 3.0
23610        } else if show_line_numbers {
23611            ch_width
23612        } else {
23613            px(0.)
23614        };
23615
23616        Some(GutterDimensions {
23617            left_padding,
23618            right_padding,
23619            width: line_gutter_width + left_padding + right_padding,
23620            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23621            git_blame_entries_width,
23622        })
23623    }
23624
23625    pub fn render_crease_toggle(
23626        &self,
23627        buffer_row: MultiBufferRow,
23628        row_contains_cursor: bool,
23629        editor: Entity<Editor>,
23630        window: &mut Window,
23631        cx: &mut App,
23632    ) -> Option<AnyElement> {
23633        let folded = self.is_line_folded(buffer_row);
23634        let mut is_foldable = false;
23635
23636        if let Some(crease) = self
23637            .crease_snapshot
23638            .query_row(buffer_row, self.buffer_snapshot())
23639        {
23640            is_foldable = true;
23641            match crease {
23642                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23643                    if let Some(render_toggle) = render_toggle {
23644                        let toggle_callback =
23645                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23646                                if folded {
23647                                    editor.update(cx, |editor, cx| {
23648                                        editor.fold_at(buffer_row, window, cx)
23649                                    });
23650                                } else {
23651                                    editor.update(cx, |editor, cx| {
23652                                        editor.unfold_at(buffer_row, window, cx)
23653                                    });
23654                                }
23655                            });
23656                        return Some((render_toggle)(
23657                            buffer_row,
23658                            folded,
23659                            toggle_callback,
23660                            window,
23661                            cx,
23662                        ));
23663                    }
23664                }
23665            }
23666        }
23667
23668        is_foldable |= self.starts_indent(buffer_row);
23669
23670        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23671            Some(
23672                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23673                    .toggle_state(folded)
23674                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23675                        if folded {
23676                            this.unfold_at(buffer_row, window, cx);
23677                        } else {
23678                            this.fold_at(buffer_row, window, cx);
23679                        }
23680                    }))
23681                    .into_any_element(),
23682            )
23683        } else {
23684            None
23685        }
23686    }
23687
23688    pub fn render_crease_trailer(
23689        &self,
23690        buffer_row: MultiBufferRow,
23691        window: &mut Window,
23692        cx: &mut App,
23693    ) -> Option<AnyElement> {
23694        let folded = self.is_line_folded(buffer_row);
23695        if let Crease::Inline { render_trailer, .. } = self
23696            .crease_snapshot
23697            .query_row(buffer_row, self.buffer_snapshot())?
23698        {
23699            let render_trailer = render_trailer.as_ref()?;
23700            Some(render_trailer(buffer_row, folded, window, cx))
23701        } else {
23702            None
23703        }
23704    }
23705}
23706
23707impl Deref for EditorSnapshot {
23708    type Target = DisplaySnapshot;
23709
23710    fn deref(&self) -> &Self::Target {
23711        &self.display_snapshot
23712    }
23713}
23714
23715#[derive(Clone, Debug, PartialEq, Eq)]
23716pub enum EditorEvent {
23717    InputIgnored {
23718        text: Arc<str>,
23719    },
23720    InputHandled {
23721        utf16_range_to_replace: Option<Range<isize>>,
23722        text: Arc<str>,
23723    },
23724    ExcerptsAdded {
23725        buffer: Entity<Buffer>,
23726        predecessor: ExcerptId,
23727        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23728    },
23729    ExcerptsRemoved {
23730        ids: Vec<ExcerptId>,
23731        removed_buffer_ids: Vec<BufferId>,
23732    },
23733    BufferFoldToggled {
23734        ids: Vec<ExcerptId>,
23735        folded: bool,
23736    },
23737    ExcerptsEdited {
23738        ids: Vec<ExcerptId>,
23739    },
23740    ExcerptsExpanded {
23741        ids: Vec<ExcerptId>,
23742    },
23743    BufferEdited,
23744    Edited {
23745        transaction_id: clock::Lamport,
23746    },
23747    Reparsed(BufferId),
23748    Focused,
23749    FocusedIn,
23750    Blurred,
23751    DirtyChanged,
23752    Saved,
23753    TitleChanged,
23754    SelectionsChanged {
23755        local: bool,
23756    },
23757    ScrollPositionChanged {
23758        local: bool,
23759        autoscroll: bool,
23760    },
23761    TransactionUndone {
23762        transaction_id: clock::Lamport,
23763    },
23764    TransactionBegun {
23765        transaction_id: clock::Lamport,
23766    },
23767    CursorShapeChanged,
23768    BreadcrumbsChanged,
23769    PushedToNavHistory {
23770        anchor: Anchor,
23771        is_deactivate: bool,
23772    },
23773}
23774
23775impl EventEmitter<EditorEvent> for Editor {}
23776
23777impl Focusable for Editor {
23778    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23779        self.focus_handle.clone()
23780    }
23781}
23782
23783impl Render for Editor {
23784    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23785        let settings = ThemeSettings::get_global(cx);
23786
23787        let mut text_style = match self.mode {
23788            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23789                color: cx.theme().colors().editor_foreground,
23790                font_family: settings.ui_font.family.clone(),
23791                font_features: settings.ui_font.features.clone(),
23792                font_fallbacks: settings.ui_font.fallbacks.clone(),
23793                font_size: rems(0.875).into(),
23794                font_weight: settings.ui_font.weight,
23795                line_height: relative(settings.buffer_line_height.value()),
23796                ..Default::default()
23797            },
23798            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23799                color: cx.theme().colors().editor_foreground,
23800                font_family: settings.buffer_font.family.clone(),
23801                font_features: settings.buffer_font.features.clone(),
23802                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23803                font_size: settings.buffer_font_size(cx).into(),
23804                font_weight: settings.buffer_font.weight,
23805                line_height: relative(settings.buffer_line_height.value()),
23806                ..Default::default()
23807            },
23808        };
23809        if let Some(text_style_refinement) = &self.text_style_refinement {
23810            text_style.refine(text_style_refinement)
23811        }
23812
23813        let background = match self.mode {
23814            EditorMode::SingleLine => cx.theme().system().transparent,
23815            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23816            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23817            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23818        };
23819
23820        EditorElement::new(
23821            &cx.entity(),
23822            EditorStyle {
23823                background,
23824                border: cx.theme().colors().border,
23825                local_player: cx.theme().players().local(),
23826                text: text_style,
23827                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23828                syntax: cx.theme().syntax().clone(),
23829                status: cx.theme().status().clone(),
23830                inlay_hints_style: make_inlay_hints_style(cx),
23831                edit_prediction_styles: make_suggestion_styles(cx),
23832                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23833                show_underlines: self.diagnostics_enabled(),
23834            },
23835        )
23836    }
23837}
23838
23839impl EntityInputHandler for Editor {
23840    fn text_for_range(
23841        &mut self,
23842        range_utf16: Range<usize>,
23843        adjusted_range: &mut Option<Range<usize>>,
23844        _: &mut Window,
23845        cx: &mut Context<Self>,
23846    ) -> Option<String> {
23847        let snapshot = self.buffer.read(cx).read(cx);
23848        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23849        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23850        if (start.0..end.0) != range_utf16 {
23851            adjusted_range.replace(start.0..end.0);
23852        }
23853        Some(snapshot.text_for_range(start..end).collect())
23854    }
23855
23856    fn selected_text_range(
23857        &mut self,
23858        ignore_disabled_input: bool,
23859        _: &mut Window,
23860        cx: &mut Context<Self>,
23861    ) -> Option<UTF16Selection> {
23862        // Prevent the IME menu from appearing when holding down an alphabetic key
23863        // while input is disabled.
23864        if !ignore_disabled_input && !self.input_enabled {
23865            return None;
23866        }
23867
23868        let selection = self.selections.newest::<OffsetUtf16>(cx);
23869        let range = selection.range();
23870
23871        Some(UTF16Selection {
23872            range: range.start.0..range.end.0,
23873            reversed: selection.reversed,
23874        })
23875    }
23876
23877    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23878        let snapshot = self.buffer.read(cx).read(cx);
23879        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23880        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23881    }
23882
23883    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23884        self.clear_highlights::<InputComposition>(cx);
23885        self.ime_transaction.take();
23886    }
23887
23888    fn replace_text_in_range(
23889        &mut self,
23890        range_utf16: Option<Range<usize>>,
23891        text: &str,
23892        window: &mut Window,
23893        cx: &mut Context<Self>,
23894    ) {
23895        if !self.input_enabled {
23896            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23897            return;
23898        }
23899
23900        self.transact(window, cx, |this, window, cx| {
23901            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23902                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23903                Some(this.selection_replacement_ranges(range_utf16, cx))
23904            } else {
23905                this.marked_text_ranges(cx)
23906            };
23907
23908            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23909                let newest_selection_id = this.selections.newest_anchor().id;
23910                this.selections
23911                    .all::<OffsetUtf16>(cx)
23912                    .iter()
23913                    .zip(ranges_to_replace.iter())
23914                    .find_map(|(selection, range)| {
23915                        if selection.id == newest_selection_id {
23916                            Some(
23917                                (range.start.0 as isize - selection.head().0 as isize)
23918                                    ..(range.end.0 as isize - selection.head().0 as isize),
23919                            )
23920                        } else {
23921                            None
23922                        }
23923                    })
23924            });
23925
23926            cx.emit(EditorEvent::InputHandled {
23927                utf16_range_to_replace: range_to_replace,
23928                text: text.into(),
23929            });
23930
23931            if let Some(new_selected_ranges) = new_selected_ranges {
23932                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23933                    selections.select_ranges(new_selected_ranges)
23934                });
23935                this.backspace(&Default::default(), window, cx);
23936            }
23937
23938            this.handle_input(text, window, cx);
23939        });
23940
23941        if let Some(transaction) = self.ime_transaction {
23942            self.buffer.update(cx, |buffer, cx| {
23943                buffer.group_until_transaction(transaction, cx);
23944            });
23945        }
23946
23947        self.unmark_text(window, cx);
23948    }
23949
23950    fn replace_and_mark_text_in_range(
23951        &mut self,
23952        range_utf16: Option<Range<usize>>,
23953        text: &str,
23954        new_selected_range_utf16: Option<Range<usize>>,
23955        window: &mut Window,
23956        cx: &mut Context<Self>,
23957    ) {
23958        if !self.input_enabled {
23959            return;
23960        }
23961
23962        let transaction = self.transact(window, cx, |this, window, cx| {
23963            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23964                let snapshot = this.buffer.read(cx).read(cx);
23965                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23966                    for marked_range in &mut marked_ranges {
23967                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23968                        marked_range.start.0 += relative_range_utf16.start;
23969                        marked_range.start =
23970                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23971                        marked_range.end =
23972                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23973                    }
23974                }
23975                Some(marked_ranges)
23976            } else if let Some(range_utf16) = range_utf16 {
23977                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23978                Some(this.selection_replacement_ranges(range_utf16, cx))
23979            } else {
23980                None
23981            };
23982
23983            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23984                let newest_selection_id = this.selections.newest_anchor().id;
23985                this.selections
23986                    .all::<OffsetUtf16>(cx)
23987                    .iter()
23988                    .zip(ranges_to_replace.iter())
23989                    .find_map(|(selection, range)| {
23990                        if selection.id == newest_selection_id {
23991                            Some(
23992                                (range.start.0 as isize - selection.head().0 as isize)
23993                                    ..(range.end.0 as isize - selection.head().0 as isize),
23994                            )
23995                        } else {
23996                            None
23997                        }
23998                    })
23999            });
24000
24001            cx.emit(EditorEvent::InputHandled {
24002                utf16_range_to_replace: range_to_replace,
24003                text: text.into(),
24004            });
24005
24006            if let Some(ranges) = ranges_to_replace {
24007                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24008                    s.select_ranges(ranges)
24009                });
24010            }
24011
24012            let marked_ranges = {
24013                let snapshot = this.buffer.read(cx).read(cx);
24014                this.selections
24015                    .disjoint_anchors_arc()
24016                    .iter()
24017                    .map(|selection| {
24018                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24019                    })
24020                    .collect::<Vec<_>>()
24021            };
24022
24023            if text.is_empty() {
24024                this.unmark_text(window, cx);
24025            } else {
24026                this.highlight_text::<InputComposition>(
24027                    marked_ranges.clone(),
24028                    HighlightStyle {
24029                        underline: Some(UnderlineStyle {
24030                            thickness: px(1.),
24031                            color: None,
24032                            wavy: false,
24033                        }),
24034                        ..Default::default()
24035                    },
24036                    cx,
24037                );
24038            }
24039
24040            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24041            let use_autoclose = this.use_autoclose;
24042            let use_auto_surround = this.use_auto_surround;
24043            this.set_use_autoclose(false);
24044            this.set_use_auto_surround(false);
24045            this.handle_input(text, window, cx);
24046            this.set_use_autoclose(use_autoclose);
24047            this.set_use_auto_surround(use_auto_surround);
24048
24049            if let Some(new_selected_range) = new_selected_range_utf16 {
24050                let snapshot = this.buffer.read(cx).read(cx);
24051                let new_selected_ranges = marked_ranges
24052                    .into_iter()
24053                    .map(|marked_range| {
24054                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24055                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24056                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24057                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24058                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24059                    })
24060                    .collect::<Vec<_>>();
24061
24062                drop(snapshot);
24063                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24064                    selections.select_ranges(new_selected_ranges)
24065                });
24066            }
24067        });
24068
24069        self.ime_transaction = self.ime_transaction.or(transaction);
24070        if let Some(transaction) = self.ime_transaction {
24071            self.buffer.update(cx, |buffer, cx| {
24072                buffer.group_until_transaction(transaction, cx);
24073            });
24074        }
24075
24076        if self.text_highlights::<InputComposition>(cx).is_none() {
24077            self.ime_transaction.take();
24078        }
24079    }
24080
24081    fn bounds_for_range(
24082        &mut self,
24083        range_utf16: Range<usize>,
24084        element_bounds: gpui::Bounds<Pixels>,
24085        window: &mut Window,
24086        cx: &mut Context<Self>,
24087    ) -> Option<gpui::Bounds<Pixels>> {
24088        let text_layout_details = self.text_layout_details(window);
24089        let CharacterDimensions {
24090            em_width,
24091            em_advance,
24092            line_height,
24093        } = self.character_dimensions(window);
24094
24095        let snapshot = self.snapshot(window, cx);
24096        let scroll_position = snapshot.scroll_position();
24097        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24098
24099        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24100        let x = Pixels::from(
24101            ScrollOffset::from(
24102                snapshot.x_for_display_point(start, &text_layout_details)
24103                    + self.gutter_dimensions.full_width(),
24104            ) - scroll_left,
24105        );
24106        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24107
24108        Some(Bounds {
24109            origin: element_bounds.origin + point(x, y),
24110            size: size(em_width, line_height),
24111        })
24112    }
24113
24114    fn character_index_for_point(
24115        &mut self,
24116        point: gpui::Point<Pixels>,
24117        _window: &mut Window,
24118        _cx: &mut Context<Self>,
24119    ) -> Option<usize> {
24120        let position_map = self.last_position_map.as_ref()?;
24121        if !position_map.text_hitbox.contains(&point) {
24122            return None;
24123        }
24124        let display_point = position_map.point_for_position(point).previous_valid;
24125        let anchor = position_map
24126            .snapshot
24127            .display_point_to_anchor(display_point, Bias::Left);
24128        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24129        Some(utf16_offset.0)
24130    }
24131}
24132
24133trait SelectionExt {
24134    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24135    fn spanned_rows(
24136        &self,
24137        include_end_if_at_line_start: bool,
24138        map: &DisplaySnapshot,
24139    ) -> Range<MultiBufferRow>;
24140}
24141
24142impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24143    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24144        let start = self
24145            .start
24146            .to_point(map.buffer_snapshot())
24147            .to_display_point(map);
24148        let end = self
24149            .end
24150            .to_point(map.buffer_snapshot())
24151            .to_display_point(map);
24152        if self.reversed {
24153            end..start
24154        } else {
24155            start..end
24156        }
24157    }
24158
24159    fn spanned_rows(
24160        &self,
24161        include_end_if_at_line_start: bool,
24162        map: &DisplaySnapshot,
24163    ) -> Range<MultiBufferRow> {
24164        let start = self.start.to_point(map.buffer_snapshot());
24165        let mut end = self.end.to_point(map.buffer_snapshot());
24166        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24167            end.row -= 1;
24168        }
24169
24170        let buffer_start = map.prev_line_boundary(start).0;
24171        let buffer_end = map.next_line_boundary(end).0;
24172        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24173    }
24174}
24175
24176impl<T: InvalidationRegion> InvalidationStack<T> {
24177    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24178    where
24179        S: Clone + ToOffset,
24180    {
24181        while let Some(region) = self.last() {
24182            let all_selections_inside_invalidation_ranges =
24183                if selections.len() == region.ranges().len() {
24184                    selections
24185                        .iter()
24186                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24187                        .all(|(selection, invalidation_range)| {
24188                            let head = selection.head().to_offset(buffer);
24189                            invalidation_range.start <= head && invalidation_range.end >= head
24190                        })
24191                } else {
24192                    false
24193                };
24194
24195            if all_selections_inside_invalidation_ranges {
24196                break;
24197            } else {
24198                self.pop();
24199            }
24200        }
24201    }
24202}
24203
24204impl<T> Default for InvalidationStack<T> {
24205    fn default() -> Self {
24206        Self(Default::default())
24207    }
24208}
24209
24210impl<T> Deref for InvalidationStack<T> {
24211    type Target = Vec<T>;
24212
24213    fn deref(&self) -> &Self::Target {
24214        &self.0
24215    }
24216}
24217
24218impl<T> DerefMut for InvalidationStack<T> {
24219    fn deref_mut(&mut self) -> &mut Self::Target {
24220        &mut self.0
24221    }
24222}
24223
24224impl InvalidationRegion for SnippetState {
24225    fn ranges(&self) -> &[Range<Anchor>] {
24226        &self.ranges[self.active_index]
24227    }
24228}
24229
24230fn edit_prediction_edit_text(
24231    current_snapshot: &BufferSnapshot,
24232    edits: &[(Range<Anchor>, String)],
24233    edit_preview: &EditPreview,
24234    include_deletions: bool,
24235    cx: &App,
24236) -> HighlightedText {
24237    let edits = edits
24238        .iter()
24239        .map(|(anchor, text)| {
24240            (
24241                anchor.start.text_anchor..anchor.end.text_anchor,
24242                text.clone(),
24243            )
24244        })
24245        .collect::<Vec<_>>();
24246
24247    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24248}
24249
24250fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24251    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24252    // Just show the raw edit text with basic styling
24253    let mut text = String::new();
24254    let mut highlights = Vec::new();
24255
24256    let insertion_highlight_style = HighlightStyle {
24257        color: Some(cx.theme().colors().text),
24258        ..Default::default()
24259    };
24260
24261    for (_, edit_text) in edits {
24262        let start_offset = text.len();
24263        text.push_str(edit_text);
24264        let end_offset = text.len();
24265
24266        if start_offset < end_offset {
24267            highlights.push((start_offset..end_offset, insertion_highlight_style));
24268        }
24269    }
24270
24271    HighlightedText {
24272        text: text.into(),
24273        highlights,
24274    }
24275}
24276
24277pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24278    match severity {
24279        lsp::DiagnosticSeverity::ERROR => colors.error,
24280        lsp::DiagnosticSeverity::WARNING => colors.warning,
24281        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24282        lsp::DiagnosticSeverity::HINT => colors.info,
24283        _ => colors.ignored,
24284    }
24285}
24286
24287pub fn styled_runs_for_code_label<'a>(
24288    label: &'a CodeLabel,
24289    syntax_theme: &'a theme::SyntaxTheme,
24290) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24291    let fade_out = HighlightStyle {
24292        fade_out: Some(0.35),
24293        ..Default::default()
24294    };
24295
24296    let mut prev_end = label.filter_range.end;
24297    label
24298        .runs
24299        .iter()
24300        .enumerate()
24301        .flat_map(move |(ix, (range, highlight_id))| {
24302            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24303                style
24304            } else {
24305                return Default::default();
24306            };
24307            let muted_style = style.highlight(fade_out);
24308
24309            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24310            if range.start >= label.filter_range.end {
24311                if range.start > prev_end {
24312                    runs.push((prev_end..range.start, fade_out));
24313                }
24314                runs.push((range.clone(), muted_style));
24315            } else if range.end <= label.filter_range.end {
24316                runs.push((range.clone(), style));
24317            } else {
24318                runs.push((range.start..label.filter_range.end, style));
24319                runs.push((label.filter_range.end..range.end, muted_style));
24320            }
24321            prev_end = cmp::max(prev_end, range.end);
24322
24323            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24324                runs.push((prev_end..label.text.len(), fade_out));
24325            }
24326
24327            runs
24328        })
24329}
24330
24331pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24332    let mut prev_index = 0;
24333    let mut prev_codepoint: Option<char> = None;
24334    text.char_indices()
24335        .chain([(text.len(), '\0')])
24336        .filter_map(move |(index, codepoint)| {
24337            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24338            let is_boundary = index == text.len()
24339                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24340                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24341            if is_boundary {
24342                let chunk = &text[prev_index..index];
24343                prev_index = index;
24344                Some(chunk)
24345            } else {
24346                None
24347            }
24348        })
24349}
24350
24351pub trait RangeToAnchorExt: Sized {
24352    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24353
24354    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24355        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24356        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24357    }
24358}
24359
24360impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24361    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24362        let start_offset = self.start.to_offset(snapshot);
24363        let end_offset = self.end.to_offset(snapshot);
24364        if start_offset == end_offset {
24365            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24366        } else {
24367            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24368        }
24369    }
24370}
24371
24372pub trait RowExt {
24373    fn as_f64(&self) -> f64;
24374
24375    fn next_row(&self) -> Self;
24376
24377    fn previous_row(&self) -> Self;
24378
24379    fn minus(&self, other: Self) -> u32;
24380}
24381
24382impl RowExt for DisplayRow {
24383    fn as_f64(&self) -> f64 {
24384        self.0 as _
24385    }
24386
24387    fn next_row(&self) -> Self {
24388        Self(self.0 + 1)
24389    }
24390
24391    fn previous_row(&self) -> Self {
24392        Self(self.0.saturating_sub(1))
24393    }
24394
24395    fn minus(&self, other: Self) -> u32 {
24396        self.0 - other.0
24397    }
24398}
24399
24400impl RowExt for MultiBufferRow {
24401    fn as_f64(&self) -> f64 {
24402        self.0 as _
24403    }
24404
24405    fn next_row(&self) -> Self {
24406        Self(self.0 + 1)
24407    }
24408
24409    fn previous_row(&self) -> Self {
24410        Self(self.0.saturating_sub(1))
24411    }
24412
24413    fn minus(&self, other: Self) -> u32 {
24414        self.0 - other.0
24415    }
24416}
24417
24418trait RowRangeExt {
24419    type Row;
24420
24421    fn len(&self) -> usize;
24422
24423    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24424}
24425
24426impl RowRangeExt for Range<MultiBufferRow> {
24427    type Row = MultiBufferRow;
24428
24429    fn len(&self) -> usize {
24430        (self.end.0 - self.start.0) as usize
24431    }
24432
24433    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24434        (self.start.0..self.end.0).map(MultiBufferRow)
24435    }
24436}
24437
24438impl RowRangeExt for Range<DisplayRow> {
24439    type Row = DisplayRow;
24440
24441    fn len(&self) -> usize {
24442        (self.end.0 - self.start.0) as usize
24443    }
24444
24445    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24446        (self.start.0..self.end.0).map(DisplayRow)
24447    }
24448}
24449
24450/// If select range has more than one line, we
24451/// just point the cursor to range.start.
24452fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24453    if range.start.row == range.end.row {
24454        range
24455    } else {
24456        range.start..range.start
24457    }
24458}
24459pub struct KillRing(ClipboardItem);
24460impl Global for KillRing {}
24461
24462const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24463
24464enum BreakpointPromptEditAction {
24465    Log,
24466    Condition,
24467    HitCondition,
24468}
24469
24470struct BreakpointPromptEditor {
24471    pub(crate) prompt: Entity<Editor>,
24472    editor: WeakEntity<Editor>,
24473    breakpoint_anchor: Anchor,
24474    breakpoint: Breakpoint,
24475    edit_action: BreakpointPromptEditAction,
24476    block_ids: HashSet<CustomBlockId>,
24477    editor_margins: Arc<Mutex<EditorMargins>>,
24478    _subscriptions: Vec<Subscription>,
24479}
24480
24481impl BreakpointPromptEditor {
24482    const MAX_LINES: u8 = 4;
24483
24484    fn new(
24485        editor: WeakEntity<Editor>,
24486        breakpoint_anchor: Anchor,
24487        breakpoint: Breakpoint,
24488        edit_action: BreakpointPromptEditAction,
24489        window: &mut Window,
24490        cx: &mut Context<Self>,
24491    ) -> Self {
24492        let base_text = match edit_action {
24493            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24494            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24495            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24496        }
24497        .map(|msg| msg.to_string())
24498        .unwrap_or_default();
24499
24500        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24501        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24502
24503        let prompt = cx.new(|cx| {
24504            let mut prompt = Editor::new(
24505                EditorMode::AutoHeight {
24506                    min_lines: 1,
24507                    max_lines: Some(Self::MAX_LINES as usize),
24508                },
24509                buffer,
24510                None,
24511                window,
24512                cx,
24513            );
24514            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24515            prompt.set_show_cursor_when_unfocused(false, cx);
24516            prompt.set_placeholder_text(
24517                match edit_action {
24518                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24519                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24520                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24521                },
24522                window,
24523                cx,
24524            );
24525
24526            prompt
24527        });
24528
24529        Self {
24530            prompt,
24531            editor,
24532            breakpoint_anchor,
24533            breakpoint,
24534            edit_action,
24535            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24536            block_ids: Default::default(),
24537            _subscriptions: vec![],
24538        }
24539    }
24540
24541    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24542        self.block_ids.extend(block_ids)
24543    }
24544
24545    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24546        if let Some(editor) = self.editor.upgrade() {
24547            let message = self
24548                .prompt
24549                .read(cx)
24550                .buffer
24551                .read(cx)
24552                .as_singleton()
24553                .expect("A multi buffer in breakpoint prompt isn't possible")
24554                .read(cx)
24555                .as_rope()
24556                .to_string();
24557
24558            editor.update(cx, |editor, cx| {
24559                editor.edit_breakpoint_at_anchor(
24560                    self.breakpoint_anchor,
24561                    self.breakpoint.clone(),
24562                    match self.edit_action {
24563                        BreakpointPromptEditAction::Log => {
24564                            BreakpointEditAction::EditLogMessage(message.into())
24565                        }
24566                        BreakpointPromptEditAction::Condition => {
24567                            BreakpointEditAction::EditCondition(message.into())
24568                        }
24569                        BreakpointPromptEditAction::HitCondition => {
24570                            BreakpointEditAction::EditHitCondition(message.into())
24571                        }
24572                    },
24573                    cx,
24574                );
24575
24576                editor.remove_blocks(self.block_ids.clone(), None, cx);
24577                cx.focus_self(window);
24578            });
24579        }
24580    }
24581
24582    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24583        self.editor
24584            .update(cx, |editor, cx| {
24585                editor.remove_blocks(self.block_ids.clone(), None, cx);
24586                window.focus(&editor.focus_handle);
24587            })
24588            .log_err();
24589    }
24590
24591    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24592        let settings = ThemeSettings::get_global(cx);
24593        let text_style = TextStyle {
24594            color: if self.prompt.read(cx).read_only(cx) {
24595                cx.theme().colors().text_disabled
24596            } else {
24597                cx.theme().colors().text
24598            },
24599            font_family: settings.buffer_font.family.clone(),
24600            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24601            font_size: settings.buffer_font_size(cx).into(),
24602            font_weight: settings.buffer_font.weight,
24603            line_height: relative(settings.buffer_line_height.value()),
24604            ..Default::default()
24605        };
24606        EditorElement::new(
24607            &self.prompt,
24608            EditorStyle {
24609                background: cx.theme().colors().editor_background,
24610                local_player: cx.theme().players().local(),
24611                text: text_style,
24612                ..Default::default()
24613            },
24614        )
24615    }
24616}
24617
24618impl Render for BreakpointPromptEditor {
24619    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24620        let editor_margins = *self.editor_margins.lock();
24621        let gutter_dimensions = editor_margins.gutter;
24622        h_flex()
24623            .key_context("Editor")
24624            .bg(cx.theme().colors().editor_background)
24625            .border_y_1()
24626            .border_color(cx.theme().status().info_border)
24627            .size_full()
24628            .py(window.line_height() / 2.5)
24629            .on_action(cx.listener(Self::confirm))
24630            .on_action(cx.listener(Self::cancel))
24631            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24632            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24633    }
24634}
24635
24636impl Focusable for BreakpointPromptEditor {
24637    fn focus_handle(&self, cx: &App) -> FocusHandle {
24638        self.prompt.focus_handle(cx)
24639    }
24640}
24641
24642fn all_edits_insertions_or_deletions(
24643    edits: &Vec<(Range<Anchor>, String)>,
24644    snapshot: &MultiBufferSnapshot,
24645) -> bool {
24646    let mut all_insertions = true;
24647    let mut all_deletions = true;
24648
24649    for (range, new_text) in edits.iter() {
24650        let range_is_empty = range.to_offset(snapshot).is_empty();
24651        let text_is_empty = new_text.is_empty();
24652
24653        if range_is_empty != text_is_empty {
24654            if range_is_empty {
24655                all_deletions = false;
24656            } else {
24657                all_insertions = false;
24658            }
24659        } else {
24660            return false;
24661        }
24662
24663        if !all_insertions && !all_deletions {
24664            return false;
24665        }
24666    }
24667    all_insertions || all_deletions
24668}
24669
24670struct MissingEditPredictionKeybindingTooltip;
24671
24672impl Render for MissingEditPredictionKeybindingTooltip {
24673    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24674        ui::tooltip_container(cx, |container, cx| {
24675            container
24676                .flex_shrink_0()
24677                .max_w_80()
24678                .min_h(rems_from_px(124.))
24679                .justify_between()
24680                .child(
24681                    v_flex()
24682                        .flex_1()
24683                        .text_ui_sm(cx)
24684                        .child(Label::new("Conflict with Accept Keybinding"))
24685                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24686                )
24687                .child(
24688                    h_flex()
24689                        .pb_1()
24690                        .gap_1()
24691                        .items_end()
24692                        .w_full()
24693                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24694                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24695                        }))
24696                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24697                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24698                        })),
24699                )
24700        })
24701    }
24702}
24703
24704#[derive(Debug, Clone, Copy, PartialEq)]
24705pub struct LineHighlight {
24706    pub background: Background,
24707    pub border: Option<gpui::Hsla>,
24708    pub include_gutter: bool,
24709    pub type_id: Option<TypeId>,
24710}
24711
24712struct LineManipulationResult {
24713    pub new_text: String,
24714    pub line_count_before: usize,
24715    pub line_count_after: usize,
24716}
24717
24718fn render_diff_hunk_controls(
24719    row: u32,
24720    status: &DiffHunkStatus,
24721    hunk_range: Range<Anchor>,
24722    is_created_file: bool,
24723    line_height: Pixels,
24724    editor: &Entity<Editor>,
24725    _window: &mut Window,
24726    cx: &mut App,
24727) -> AnyElement {
24728    h_flex()
24729        .h(line_height)
24730        .mr_1()
24731        .gap_1()
24732        .px_0p5()
24733        .pb_1()
24734        .border_x_1()
24735        .border_b_1()
24736        .border_color(cx.theme().colors().border_variant)
24737        .rounded_b_lg()
24738        .bg(cx.theme().colors().editor_background)
24739        .gap_1()
24740        .block_mouse_except_scroll()
24741        .shadow_md()
24742        .child(if status.has_secondary_hunk() {
24743            Button::new(("stage", row as u64), "Stage")
24744                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24745                .tooltip({
24746                    let focus_handle = editor.focus_handle(cx);
24747                    move |window, cx| {
24748                        Tooltip::for_action_in(
24749                            "Stage Hunk",
24750                            &::git::ToggleStaged,
24751                            &focus_handle,
24752                            window,
24753                            cx,
24754                        )
24755                    }
24756                })
24757                .on_click({
24758                    let editor = editor.clone();
24759                    move |_event, _window, cx| {
24760                        editor.update(cx, |editor, cx| {
24761                            editor.stage_or_unstage_diff_hunks(
24762                                true,
24763                                vec![hunk_range.start..hunk_range.start],
24764                                cx,
24765                            );
24766                        });
24767                    }
24768                })
24769        } else {
24770            Button::new(("unstage", row as u64), "Unstage")
24771                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24772                .tooltip({
24773                    let focus_handle = editor.focus_handle(cx);
24774                    move |window, cx| {
24775                        Tooltip::for_action_in(
24776                            "Unstage Hunk",
24777                            &::git::ToggleStaged,
24778                            &focus_handle,
24779                            window,
24780                            cx,
24781                        )
24782                    }
24783                })
24784                .on_click({
24785                    let editor = editor.clone();
24786                    move |_event, _window, cx| {
24787                        editor.update(cx, |editor, cx| {
24788                            editor.stage_or_unstage_diff_hunks(
24789                                false,
24790                                vec![hunk_range.start..hunk_range.start],
24791                                cx,
24792                            );
24793                        });
24794                    }
24795                })
24796        })
24797        .child(
24798            Button::new(("restore", row as u64), "Restore")
24799                .tooltip({
24800                    let focus_handle = editor.focus_handle(cx);
24801                    move |window, cx| {
24802                        Tooltip::for_action_in(
24803                            "Restore Hunk",
24804                            &::git::Restore,
24805                            &focus_handle,
24806                            window,
24807                            cx,
24808                        )
24809                    }
24810                })
24811                .on_click({
24812                    let editor = editor.clone();
24813                    move |_event, window, cx| {
24814                        editor.update(cx, |editor, cx| {
24815                            let snapshot = editor.snapshot(window, cx);
24816                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24817                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24818                        });
24819                    }
24820                })
24821                .disabled(is_created_file),
24822        )
24823        .when(
24824            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24825            |el| {
24826                el.child(
24827                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24828                        .shape(IconButtonShape::Square)
24829                        .icon_size(IconSize::Small)
24830                        // .disabled(!has_multiple_hunks)
24831                        .tooltip({
24832                            let focus_handle = editor.focus_handle(cx);
24833                            move |window, cx| {
24834                                Tooltip::for_action_in(
24835                                    "Next Hunk",
24836                                    &GoToHunk,
24837                                    &focus_handle,
24838                                    window,
24839                                    cx,
24840                                )
24841                            }
24842                        })
24843                        .on_click({
24844                            let editor = editor.clone();
24845                            move |_event, window, cx| {
24846                                editor.update(cx, |editor, cx| {
24847                                    let snapshot = editor.snapshot(window, cx);
24848                                    let position =
24849                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24850                                    editor.go_to_hunk_before_or_after_position(
24851                                        &snapshot,
24852                                        position,
24853                                        Direction::Next,
24854                                        window,
24855                                        cx,
24856                                    );
24857                                    editor.expand_selected_diff_hunks(cx);
24858                                });
24859                            }
24860                        }),
24861                )
24862                .child(
24863                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24864                        .shape(IconButtonShape::Square)
24865                        .icon_size(IconSize::Small)
24866                        // .disabled(!has_multiple_hunks)
24867                        .tooltip({
24868                            let focus_handle = editor.focus_handle(cx);
24869                            move |window, cx| {
24870                                Tooltip::for_action_in(
24871                                    "Previous Hunk",
24872                                    &GoToPreviousHunk,
24873                                    &focus_handle,
24874                                    window,
24875                                    cx,
24876                                )
24877                            }
24878                        })
24879                        .on_click({
24880                            let editor = editor.clone();
24881                            move |_event, window, cx| {
24882                                editor.update(cx, |editor, cx| {
24883                                    let snapshot = editor.snapshot(window, cx);
24884                                    let point =
24885                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24886                                    editor.go_to_hunk_before_or_after_position(
24887                                        &snapshot,
24888                                        point,
24889                                        Direction::Prev,
24890                                        window,
24891                                        cx,
24892                                    );
24893                                    editor.expand_selected_diff_hunks(cx);
24894                                });
24895                            }
24896                        }),
24897                )
24898            },
24899        )
24900        .into_any_element()
24901}
24902
24903pub fn multibuffer_context_lines(cx: &App) -> u32 {
24904    EditorSettings::try_get(cx)
24905        .map(|settings| settings.excerpt_context_lines)
24906        .unwrap_or(2)
24907        .min(32)
24908}