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, window, 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        self.begin_selection(position, false, click_count, window, cx);
 3518
 3519        let position = position.to_offset(&display_map, Bias::Left);
 3520        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3521
 3522        let mut pending_selection = self
 3523            .selections
 3524            .pending_anchor()
 3525            .cloned()
 3526            .expect("extend_selection not called with pending selection");
 3527        if position >= tail {
 3528            pending_selection.start = tail_anchor;
 3529        } else {
 3530            pending_selection.end = tail_anchor;
 3531            pending_selection.reversed = true;
 3532        }
 3533
 3534        let mut pending_mode = self.selections.pending_mode().unwrap();
 3535        match &mut pending_mode {
 3536            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3537            _ => {}
 3538        }
 3539
 3540        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3541            SelectionEffects::scroll(Autoscroll::fit())
 3542        } else {
 3543            SelectionEffects::no_scroll()
 3544        };
 3545
 3546        self.change_selections(effects, window, cx, |s| {
 3547            s.set_pending(pending_selection.clone(), pending_mode)
 3548        });
 3549    }
 3550
 3551    fn begin_selection(
 3552        &mut self,
 3553        position: DisplayPoint,
 3554        add: bool,
 3555        click_count: usize,
 3556        window: &mut Window,
 3557        cx: &mut Context<Self>,
 3558    ) {
 3559        if !self.focus_handle.is_focused(window) {
 3560            self.last_focused_descendant = None;
 3561            window.focus(&self.focus_handle);
 3562        }
 3563
 3564        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3565        let buffer = display_map.buffer_snapshot();
 3566        let position = display_map.clip_point(position, Bias::Left);
 3567
 3568        let start;
 3569        let end;
 3570        let mode;
 3571        let mut auto_scroll;
 3572        match click_count {
 3573            1 => {
 3574                start = buffer.anchor_before(position.to_point(&display_map));
 3575                end = start;
 3576                mode = SelectMode::Character;
 3577                auto_scroll = true;
 3578            }
 3579            2 => {
 3580                let position = display_map
 3581                    .clip_point(position, Bias::Left)
 3582                    .to_offset(&display_map, Bias::Left);
 3583                let (range, _) = buffer.surrounding_word(position, None);
 3584                start = buffer.anchor_before(range.start);
 3585                end = buffer.anchor_before(range.end);
 3586                mode = SelectMode::Word(start..end);
 3587                auto_scroll = true;
 3588            }
 3589            3 => {
 3590                let position = display_map
 3591                    .clip_point(position, Bias::Left)
 3592                    .to_point(&display_map);
 3593                let line_start = display_map.prev_line_boundary(position).0;
 3594                let next_line_start = buffer.clip_point(
 3595                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3596                    Bias::Left,
 3597                );
 3598                start = buffer.anchor_before(line_start);
 3599                end = buffer.anchor_before(next_line_start);
 3600                mode = SelectMode::Line(start..end);
 3601                auto_scroll = true;
 3602            }
 3603            _ => {
 3604                start = buffer.anchor_before(0);
 3605                end = buffer.anchor_before(buffer.len());
 3606                mode = SelectMode::All;
 3607                auto_scroll = false;
 3608            }
 3609        }
 3610        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3611
 3612        let point_to_delete: Option<usize> = {
 3613            let selected_points: Vec<Selection<Point>> =
 3614                self.selections.disjoint_in_range(start..end, cx);
 3615
 3616            if !add || click_count > 1 {
 3617                None
 3618            } else if !selected_points.is_empty() {
 3619                Some(selected_points[0].id)
 3620            } else {
 3621                let clicked_point_already_selected =
 3622                    self.selections.disjoint_anchors().iter().find(|selection| {
 3623                        selection.start.to_point(buffer) == start.to_point(buffer)
 3624                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3625                    });
 3626
 3627                clicked_point_already_selected.map(|selection| selection.id)
 3628            }
 3629        };
 3630
 3631        let selections_count = self.selections.count();
 3632        let effects = if auto_scroll {
 3633            SelectionEffects::default()
 3634        } else {
 3635            SelectionEffects::no_scroll()
 3636        };
 3637
 3638        self.change_selections(effects, window, cx, |s| {
 3639            if let Some(point_to_delete) = point_to_delete {
 3640                s.delete(point_to_delete);
 3641
 3642                if selections_count == 1 {
 3643                    s.set_pending_anchor_range(start..end, mode);
 3644                }
 3645            } else {
 3646                if !add {
 3647                    s.clear_disjoint();
 3648                }
 3649
 3650                s.set_pending_anchor_range(start..end, mode);
 3651            }
 3652        });
 3653    }
 3654
 3655    fn begin_columnar_selection(
 3656        &mut self,
 3657        position: DisplayPoint,
 3658        goal_column: u32,
 3659        reset: bool,
 3660        mode: ColumnarMode,
 3661        window: &mut Window,
 3662        cx: &mut Context<Self>,
 3663    ) {
 3664        if !self.focus_handle.is_focused(window) {
 3665            self.last_focused_descendant = None;
 3666            window.focus(&self.focus_handle);
 3667        }
 3668
 3669        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3670
 3671        if reset {
 3672            let pointer_position = display_map
 3673                .buffer_snapshot()
 3674                .anchor_before(position.to_point(&display_map));
 3675
 3676            self.change_selections(
 3677                SelectionEffects::scroll(Autoscroll::newest()),
 3678                window,
 3679                cx,
 3680                |s| {
 3681                    s.clear_disjoint();
 3682                    s.set_pending_anchor_range(
 3683                        pointer_position..pointer_position,
 3684                        SelectMode::Character,
 3685                    );
 3686                },
 3687            );
 3688        };
 3689
 3690        let tail = self.selections.newest::<Point>(cx).tail();
 3691        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3692        self.columnar_selection_state = match mode {
 3693            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3694                selection_tail: selection_anchor,
 3695                display_point: if reset {
 3696                    if position.column() != goal_column {
 3697                        Some(DisplayPoint::new(position.row(), goal_column))
 3698                    } else {
 3699                        None
 3700                    }
 3701                } else {
 3702                    None
 3703                },
 3704            }),
 3705            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3706                selection_tail: selection_anchor,
 3707            }),
 3708        };
 3709
 3710        if !reset {
 3711            self.select_columns(position, goal_column, &display_map, window, cx);
 3712        }
 3713    }
 3714
 3715    fn update_selection(
 3716        &mut self,
 3717        position: DisplayPoint,
 3718        goal_column: u32,
 3719        scroll_delta: gpui::Point<f32>,
 3720        window: &mut Window,
 3721        cx: &mut Context<Self>,
 3722    ) {
 3723        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3724
 3725        if self.columnar_selection_state.is_some() {
 3726            self.select_columns(position, goal_column, &display_map, window, cx);
 3727        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3728            let buffer = display_map.buffer_snapshot();
 3729            let head;
 3730            let tail;
 3731            let mode = self.selections.pending_mode().unwrap();
 3732            match &mode {
 3733                SelectMode::Character => {
 3734                    head = position.to_point(&display_map);
 3735                    tail = pending.tail().to_point(buffer);
 3736                }
 3737                SelectMode::Word(original_range) => {
 3738                    let offset = display_map
 3739                        .clip_point(position, Bias::Left)
 3740                        .to_offset(&display_map, Bias::Left);
 3741                    let original_range = original_range.to_offset(buffer);
 3742
 3743                    let head_offset = if buffer.is_inside_word(offset, None)
 3744                        || original_range.contains(&offset)
 3745                    {
 3746                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3747                        if word_range.start < original_range.start {
 3748                            word_range.start
 3749                        } else {
 3750                            word_range.end
 3751                        }
 3752                    } else {
 3753                        offset
 3754                    };
 3755
 3756                    head = head_offset.to_point(buffer);
 3757                    if head_offset <= original_range.start {
 3758                        tail = original_range.end.to_point(buffer);
 3759                    } else {
 3760                        tail = original_range.start.to_point(buffer);
 3761                    }
 3762                }
 3763                SelectMode::Line(original_range) => {
 3764                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3765
 3766                    let position = display_map
 3767                        .clip_point(position, Bias::Left)
 3768                        .to_point(&display_map);
 3769                    let line_start = display_map.prev_line_boundary(position).0;
 3770                    let next_line_start = buffer.clip_point(
 3771                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3772                        Bias::Left,
 3773                    );
 3774
 3775                    if line_start < original_range.start {
 3776                        head = line_start
 3777                    } else {
 3778                        head = next_line_start
 3779                    }
 3780
 3781                    if head <= original_range.start {
 3782                        tail = original_range.end;
 3783                    } else {
 3784                        tail = original_range.start;
 3785                    }
 3786                }
 3787                SelectMode::All => {
 3788                    return;
 3789                }
 3790            };
 3791
 3792            if head < tail {
 3793                pending.start = buffer.anchor_before(head);
 3794                pending.end = buffer.anchor_before(tail);
 3795                pending.reversed = true;
 3796            } else {
 3797                pending.start = buffer.anchor_before(tail);
 3798                pending.end = buffer.anchor_before(head);
 3799                pending.reversed = false;
 3800            }
 3801
 3802            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3803                s.set_pending(pending.clone(), mode);
 3804            });
 3805        } else {
 3806            log::error!("update_selection dispatched with no pending selection");
 3807            return;
 3808        }
 3809
 3810        self.apply_scroll_delta(scroll_delta, window, cx);
 3811        cx.notify();
 3812    }
 3813
 3814    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3815        self.columnar_selection_state.take();
 3816        if self.selections.pending_anchor().is_some() {
 3817            let selections = self.selections.all::<usize>(cx);
 3818            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3819                s.select(selections);
 3820                s.clear_pending();
 3821            });
 3822        }
 3823    }
 3824
 3825    fn select_columns(
 3826        &mut self,
 3827        head: DisplayPoint,
 3828        goal_column: u32,
 3829        display_map: &DisplaySnapshot,
 3830        window: &mut Window,
 3831        cx: &mut Context<Self>,
 3832    ) {
 3833        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3834            return;
 3835        };
 3836
 3837        let tail = match columnar_state {
 3838            ColumnarSelectionState::FromMouse {
 3839                selection_tail,
 3840                display_point,
 3841            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3842            ColumnarSelectionState::FromSelection { selection_tail } => {
 3843                selection_tail.to_display_point(display_map)
 3844            }
 3845        };
 3846
 3847        let start_row = cmp::min(tail.row(), head.row());
 3848        let end_row = cmp::max(tail.row(), head.row());
 3849        let start_column = cmp::min(tail.column(), goal_column);
 3850        let end_column = cmp::max(tail.column(), goal_column);
 3851        let reversed = start_column < tail.column();
 3852
 3853        let selection_ranges = (start_row.0..=end_row.0)
 3854            .map(DisplayRow)
 3855            .filter_map(|row| {
 3856                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3857                    || start_column <= display_map.line_len(row))
 3858                    && !display_map.is_block_line(row)
 3859                {
 3860                    let start = display_map
 3861                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3862                        .to_point(display_map);
 3863                    let end = display_map
 3864                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3865                        .to_point(display_map);
 3866                    if reversed {
 3867                        Some(end..start)
 3868                    } else {
 3869                        Some(start..end)
 3870                    }
 3871                } else {
 3872                    None
 3873                }
 3874            })
 3875            .collect::<Vec<_>>();
 3876
 3877        let ranges = match columnar_state {
 3878            ColumnarSelectionState::FromMouse { .. } => {
 3879                let mut non_empty_ranges = selection_ranges
 3880                    .iter()
 3881                    .filter(|selection_range| selection_range.start != selection_range.end)
 3882                    .peekable();
 3883                if non_empty_ranges.peek().is_some() {
 3884                    non_empty_ranges.cloned().collect()
 3885                } else {
 3886                    selection_ranges
 3887                }
 3888            }
 3889            _ => selection_ranges,
 3890        };
 3891
 3892        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3893            s.select_ranges(ranges);
 3894        });
 3895        cx.notify();
 3896    }
 3897
 3898    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3899        self.selections
 3900            .all_adjusted(cx)
 3901            .iter()
 3902            .any(|selection| !selection.is_empty())
 3903    }
 3904
 3905    pub fn has_pending_nonempty_selection(&self) -> bool {
 3906        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3907            Some(Selection { start, end, .. }) => start != end,
 3908            None => false,
 3909        };
 3910
 3911        pending_nonempty_selection
 3912            || (self.columnar_selection_state.is_some()
 3913                && self.selections.disjoint_anchors().len() > 1)
 3914    }
 3915
 3916    pub fn has_pending_selection(&self) -> bool {
 3917        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3918    }
 3919
 3920    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3921        self.selection_mark_mode = false;
 3922        self.selection_drag_state = SelectionDragState::None;
 3923
 3924        if self.clear_expanded_diff_hunks(cx) {
 3925            cx.notify();
 3926            return;
 3927        }
 3928        if self.dismiss_menus_and_popups(true, window, cx) {
 3929            return;
 3930        }
 3931
 3932        if self.mode.is_full()
 3933            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3934        {
 3935            return;
 3936        }
 3937
 3938        cx.propagate();
 3939    }
 3940
 3941    pub fn dismiss_menus_and_popups(
 3942        &mut self,
 3943        is_user_requested: bool,
 3944        window: &mut Window,
 3945        cx: &mut Context<Self>,
 3946    ) -> bool {
 3947        if self.take_rename(false, window, cx).is_some() {
 3948            return true;
 3949        }
 3950
 3951        if hide_hover(self, cx) {
 3952            return true;
 3953        }
 3954
 3955        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3956            return true;
 3957        }
 3958
 3959        if self.hide_context_menu(window, cx).is_some() {
 3960            return true;
 3961        }
 3962
 3963        if self.mouse_context_menu.take().is_some() {
 3964            return true;
 3965        }
 3966
 3967        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3968            return true;
 3969        }
 3970
 3971        if self.snippet_stack.pop().is_some() {
 3972            return true;
 3973        }
 3974
 3975        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3976            self.dismiss_diagnostics(cx);
 3977            return true;
 3978        }
 3979
 3980        false
 3981    }
 3982
 3983    fn linked_editing_ranges_for(
 3984        &self,
 3985        selection: Range<text::Anchor>,
 3986        cx: &App,
 3987    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3988        if self.linked_edit_ranges.is_empty() {
 3989            return None;
 3990        }
 3991        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3992            selection.end.buffer_id.and_then(|end_buffer_id| {
 3993                if selection.start.buffer_id != Some(end_buffer_id) {
 3994                    return None;
 3995                }
 3996                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3997                let snapshot = buffer.read(cx).snapshot();
 3998                self.linked_edit_ranges
 3999                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4000                    .map(|ranges| (ranges, snapshot, buffer))
 4001            })?;
 4002        use text::ToOffset as TO;
 4003        // find offset from the start of current range to current cursor position
 4004        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4005
 4006        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4007        let start_difference = start_offset - start_byte_offset;
 4008        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4009        let end_difference = end_offset - start_byte_offset;
 4010        // Current range has associated linked ranges.
 4011        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4012        for range in linked_ranges.iter() {
 4013            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4014            let end_offset = start_offset + end_difference;
 4015            let start_offset = start_offset + start_difference;
 4016            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4017                continue;
 4018            }
 4019            if self.selections.disjoint_anchor_ranges().any(|s| {
 4020                if s.start.buffer_id != selection.start.buffer_id
 4021                    || s.end.buffer_id != selection.end.buffer_id
 4022                {
 4023                    return false;
 4024                }
 4025                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4026                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4027            }) {
 4028                continue;
 4029            }
 4030            let start = buffer_snapshot.anchor_after(start_offset);
 4031            let end = buffer_snapshot.anchor_after(end_offset);
 4032            linked_edits
 4033                .entry(buffer.clone())
 4034                .or_default()
 4035                .push(start..end);
 4036        }
 4037        Some(linked_edits)
 4038    }
 4039
 4040    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4041        let text: Arc<str> = text.into();
 4042
 4043        if self.read_only(cx) {
 4044            return;
 4045        }
 4046
 4047        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4048
 4049        let selections = self.selections.all_adjusted(cx);
 4050        let mut bracket_inserted = false;
 4051        let mut edits = Vec::new();
 4052        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4053        let mut new_selections = Vec::with_capacity(selections.len());
 4054        let mut new_autoclose_regions = Vec::new();
 4055        let snapshot = self.buffer.read(cx).read(cx);
 4056        let mut clear_linked_edit_ranges = false;
 4057
 4058        for (selection, autoclose_region) in
 4059            self.selections_with_autoclose_regions(selections, &snapshot)
 4060        {
 4061            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4062                // Determine if the inserted text matches the opening or closing
 4063                // bracket of any of this language's bracket pairs.
 4064                let mut bracket_pair = None;
 4065                let mut is_bracket_pair_start = false;
 4066                let mut is_bracket_pair_end = false;
 4067                if !text.is_empty() {
 4068                    let mut bracket_pair_matching_end = None;
 4069                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4070                    //  and they are removing the character that triggered IME popup.
 4071                    for (pair, enabled) in scope.brackets() {
 4072                        if !pair.close && !pair.surround {
 4073                            continue;
 4074                        }
 4075
 4076                        if enabled && pair.start.ends_with(text.as_ref()) {
 4077                            let prefix_len = pair.start.len() - text.len();
 4078                            let preceding_text_matches_prefix = prefix_len == 0
 4079                                || (selection.start.column >= (prefix_len as u32)
 4080                                    && snapshot.contains_str_at(
 4081                                        Point::new(
 4082                                            selection.start.row,
 4083                                            selection.start.column - (prefix_len as u32),
 4084                                        ),
 4085                                        &pair.start[..prefix_len],
 4086                                    ));
 4087                            if preceding_text_matches_prefix {
 4088                                bracket_pair = Some(pair.clone());
 4089                                is_bracket_pair_start = true;
 4090                                break;
 4091                            }
 4092                        }
 4093                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4094                        {
 4095                            // take first bracket pair matching end, but don't break in case a later bracket
 4096                            // pair matches start
 4097                            bracket_pair_matching_end = Some(pair.clone());
 4098                        }
 4099                    }
 4100                    if let Some(end) = bracket_pair_matching_end
 4101                        && bracket_pair.is_none()
 4102                    {
 4103                        bracket_pair = Some(end);
 4104                        is_bracket_pair_end = true;
 4105                    }
 4106                }
 4107
 4108                if let Some(bracket_pair) = bracket_pair {
 4109                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4110                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4111                    let auto_surround =
 4112                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4113                    if selection.is_empty() {
 4114                        if is_bracket_pair_start {
 4115                            // If the inserted text is a suffix of an opening bracket and the
 4116                            // selection is preceded by the rest of the opening bracket, then
 4117                            // insert the closing bracket.
 4118                            let following_text_allows_autoclose = snapshot
 4119                                .chars_at(selection.start)
 4120                                .next()
 4121                                .is_none_or(|c| scope.should_autoclose_before(c));
 4122
 4123                            let preceding_text_allows_autoclose = selection.start.column == 0
 4124                                || snapshot
 4125                                    .reversed_chars_at(selection.start)
 4126                                    .next()
 4127                                    .is_none_or(|c| {
 4128                                        bracket_pair.start != bracket_pair.end
 4129                                            || !snapshot
 4130                                                .char_classifier_at(selection.start)
 4131                                                .is_word(c)
 4132                                    });
 4133
 4134                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4135                                && bracket_pair.start.len() == 1
 4136                            {
 4137                                let target = bracket_pair.start.chars().next().unwrap();
 4138                                let current_line_count = snapshot
 4139                                    .reversed_chars_at(selection.start)
 4140                                    .take_while(|&c| c != '\n')
 4141                                    .filter(|&c| c == target)
 4142                                    .count();
 4143                                current_line_count % 2 == 1
 4144                            } else {
 4145                                false
 4146                            };
 4147
 4148                            if autoclose
 4149                                && bracket_pair.close
 4150                                && following_text_allows_autoclose
 4151                                && preceding_text_allows_autoclose
 4152                                && !is_closing_quote
 4153                            {
 4154                                let anchor = snapshot.anchor_before(selection.end);
 4155                                new_selections.push((selection.map(|_| anchor), text.len()));
 4156                                new_autoclose_regions.push((
 4157                                    anchor,
 4158                                    text.len(),
 4159                                    selection.id,
 4160                                    bracket_pair.clone(),
 4161                                ));
 4162                                edits.push((
 4163                                    selection.range(),
 4164                                    format!("{}{}", text, bracket_pair.end).into(),
 4165                                ));
 4166                                bracket_inserted = true;
 4167                                continue;
 4168                            }
 4169                        }
 4170
 4171                        if let Some(region) = autoclose_region {
 4172                            // If the selection is followed by an auto-inserted closing bracket,
 4173                            // then don't insert that closing bracket again; just move the selection
 4174                            // past the closing bracket.
 4175                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4176                                && text.as_ref() == region.pair.end.as_str()
 4177                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4178                            if should_skip {
 4179                                let anchor = snapshot.anchor_after(selection.end);
 4180                                new_selections
 4181                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4182                                continue;
 4183                            }
 4184                        }
 4185
 4186                        let always_treat_brackets_as_autoclosed = snapshot
 4187                            .language_settings_at(selection.start, cx)
 4188                            .always_treat_brackets_as_autoclosed;
 4189                        if always_treat_brackets_as_autoclosed
 4190                            && is_bracket_pair_end
 4191                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4192                        {
 4193                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4194                            // and the inserted text is a closing bracket and the selection is followed
 4195                            // by the closing bracket then move the selection past the closing bracket.
 4196                            let anchor = snapshot.anchor_after(selection.end);
 4197                            new_selections.push((selection.map(|_| anchor), text.len()));
 4198                            continue;
 4199                        }
 4200                    }
 4201                    // If an opening bracket is 1 character long and is typed while
 4202                    // text is selected, then surround that text with the bracket pair.
 4203                    else if auto_surround
 4204                        && bracket_pair.surround
 4205                        && is_bracket_pair_start
 4206                        && bracket_pair.start.chars().count() == 1
 4207                    {
 4208                        edits.push((selection.start..selection.start, text.clone()));
 4209                        edits.push((
 4210                            selection.end..selection.end,
 4211                            bracket_pair.end.as_str().into(),
 4212                        ));
 4213                        bracket_inserted = true;
 4214                        new_selections.push((
 4215                            Selection {
 4216                                id: selection.id,
 4217                                start: snapshot.anchor_after(selection.start),
 4218                                end: snapshot.anchor_before(selection.end),
 4219                                reversed: selection.reversed,
 4220                                goal: selection.goal,
 4221                            },
 4222                            0,
 4223                        ));
 4224                        continue;
 4225                    }
 4226                }
 4227            }
 4228
 4229            if self.auto_replace_emoji_shortcode
 4230                && selection.is_empty()
 4231                && text.as_ref().ends_with(':')
 4232                && let Some(possible_emoji_short_code) =
 4233                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4234                && !possible_emoji_short_code.is_empty()
 4235                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4236            {
 4237                let emoji_shortcode_start = Point::new(
 4238                    selection.start.row,
 4239                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4240                );
 4241
 4242                // Remove shortcode from buffer
 4243                edits.push((
 4244                    emoji_shortcode_start..selection.start,
 4245                    "".to_string().into(),
 4246                ));
 4247                new_selections.push((
 4248                    Selection {
 4249                        id: selection.id,
 4250                        start: snapshot.anchor_after(emoji_shortcode_start),
 4251                        end: snapshot.anchor_before(selection.start),
 4252                        reversed: selection.reversed,
 4253                        goal: selection.goal,
 4254                    },
 4255                    0,
 4256                ));
 4257
 4258                // Insert emoji
 4259                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4260                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4261                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4262
 4263                continue;
 4264            }
 4265
 4266            // If not handling any auto-close operation, then just replace the selected
 4267            // text with the given input and move the selection to the end of the
 4268            // newly inserted text.
 4269            let anchor = snapshot.anchor_after(selection.end);
 4270            if !self.linked_edit_ranges.is_empty() {
 4271                let start_anchor = snapshot.anchor_before(selection.start);
 4272
 4273                let is_word_char = text.chars().next().is_none_or(|char| {
 4274                    let classifier = snapshot
 4275                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4276                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4277                    classifier.is_word(char)
 4278                });
 4279
 4280                if is_word_char {
 4281                    if let Some(ranges) = self
 4282                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4283                    {
 4284                        for (buffer, edits) in ranges {
 4285                            linked_edits
 4286                                .entry(buffer.clone())
 4287                                .or_default()
 4288                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4289                        }
 4290                    }
 4291                } else {
 4292                    clear_linked_edit_ranges = true;
 4293                }
 4294            }
 4295
 4296            new_selections.push((selection.map(|_| anchor), 0));
 4297            edits.push((selection.start..selection.end, text.clone()));
 4298        }
 4299
 4300        drop(snapshot);
 4301
 4302        self.transact(window, cx, |this, window, cx| {
 4303            if clear_linked_edit_ranges {
 4304                this.linked_edit_ranges.clear();
 4305            }
 4306            let initial_buffer_versions =
 4307                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4308
 4309            this.buffer.update(cx, |buffer, cx| {
 4310                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4311            });
 4312            for (buffer, edits) in linked_edits {
 4313                buffer.update(cx, |buffer, cx| {
 4314                    let snapshot = buffer.snapshot();
 4315                    let edits = edits
 4316                        .into_iter()
 4317                        .map(|(range, text)| {
 4318                            use text::ToPoint as TP;
 4319                            let end_point = TP::to_point(&range.end, &snapshot);
 4320                            let start_point = TP::to_point(&range.start, &snapshot);
 4321                            (start_point..end_point, text)
 4322                        })
 4323                        .sorted_by_key(|(range, _)| range.start);
 4324                    buffer.edit(edits, None, cx);
 4325                })
 4326            }
 4327            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4328            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4329            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4330            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4331                .zip(new_selection_deltas)
 4332                .map(|(selection, delta)| Selection {
 4333                    id: selection.id,
 4334                    start: selection.start + delta,
 4335                    end: selection.end + delta,
 4336                    reversed: selection.reversed,
 4337                    goal: SelectionGoal::None,
 4338                })
 4339                .collect::<Vec<_>>();
 4340
 4341            let mut i = 0;
 4342            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4343                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4344                let start = map.buffer_snapshot().anchor_before(position);
 4345                let end = map.buffer_snapshot().anchor_after(position);
 4346                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4347                    match existing_state
 4348                        .range
 4349                        .start
 4350                        .cmp(&start, map.buffer_snapshot())
 4351                    {
 4352                        Ordering::Less => i += 1,
 4353                        Ordering::Greater => break,
 4354                        Ordering::Equal => {
 4355                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4356                                Ordering::Less => i += 1,
 4357                                Ordering::Equal => break,
 4358                                Ordering::Greater => break,
 4359                            }
 4360                        }
 4361                    }
 4362                }
 4363                this.autoclose_regions.insert(
 4364                    i,
 4365                    AutocloseRegion {
 4366                        selection_id,
 4367                        range: start..end,
 4368                        pair,
 4369                    },
 4370                );
 4371            }
 4372
 4373            let had_active_edit_prediction = this.has_active_edit_prediction();
 4374            this.change_selections(
 4375                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4376                window,
 4377                cx,
 4378                |s| s.select(new_selections),
 4379            );
 4380
 4381            if !bracket_inserted
 4382                && let Some(on_type_format_task) =
 4383                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4384            {
 4385                on_type_format_task.detach_and_log_err(cx);
 4386            }
 4387
 4388            let editor_settings = EditorSettings::get_global(cx);
 4389            if bracket_inserted
 4390                && (editor_settings.auto_signature_help
 4391                    || editor_settings.show_signature_help_after_edits)
 4392            {
 4393                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4394            }
 4395
 4396            let trigger_in_words =
 4397                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4398            if this.hard_wrap.is_some() {
 4399                let latest: Range<Point> = this.selections.newest(cx).range();
 4400                if latest.is_empty()
 4401                    && this
 4402                        .buffer()
 4403                        .read(cx)
 4404                        .snapshot(cx)
 4405                        .line_len(MultiBufferRow(latest.start.row))
 4406                        == latest.start.column
 4407                {
 4408                    this.rewrap_impl(
 4409                        RewrapOptions {
 4410                            override_language_settings: true,
 4411                            preserve_existing_whitespace: true,
 4412                        },
 4413                        cx,
 4414                    )
 4415                }
 4416            }
 4417            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4418            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4419            this.refresh_edit_prediction(true, false, window, cx);
 4420            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4421        });
 4422    }
 4423
 4424    fn find_possible_emoji_shortcode_at_position(
 4425        snapshot: &MultiBufferSnapshot,
 4426        position: Point,
 4427    ) -> Option<String> {
 4428        let mut chars = Vec::new();
 4429        let mut found_colon = false;
 4430        for char in snapshot.reversed_chars_at(position).take(100) {
 4431            // Found a possible emoji shortcode in the middle of the buffer
 4432            if found_colon {
 4433                if char.is_whitespace() {
 4434                    chars.reverse();
 4435                    return Some(chars.iter().collect());
 4436                }
 4437                // If the previous character is not a whitespace, we are in the middle of a word
 4438                // and we only want to complete the shortcode if the word is made up of other emojis
 4439                let mut containing_word = String::new();
 4440                for ch in snapshot
 4441                    .reversed_chars_at(position)
 4442                    .skip(chars.len() + 1)
 4443                    .take(100)
 4444                {
 4445                    if ch.is_whitespace() {
 4446                        break;
 4447                    }
 4448                    containing_word.push(ch);
 4449                }
 4450                let containing_word = containing_word.chars().rev().collect::<String>();
 4451                if util::word_consists_of_emojis(containing_word.as_str()) {
 4452                    chars.reverse();
 4453                    return Some(chars.iter().collect());
 4454                }
 4455            }
 4456
 4457            if char.is_whitespace() || !char.is_ascii() {
 4458                return None;
 4459            }
 4460            if char == ':' {
 4461                found_colon = true;
 4462            } else {
 4463                chars.push(char);
 4464            }
 4465        }
 4466        // Found a possible emoji shortcode at the beginning of the buffer
 4467        chars.reverse();
 4468        Some(chars.iter().collect())
 4469    }
 4470
 4471    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4472        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4473        self.transact(window, cx, |this, window, cx| {
 4474            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4475                let selections = this.selections.all::<usize>(cx);
 4476                let multi_buffer = this.buffer.read(cx);
 4477                let buffer = multi_buffer.snapshot(cx);
 4478                selections
 4479                    .iter()
 4480                    .map(|selection| {
 4481                        let start_point = selection.start.to_point(&buffer);
 4482                        let mut existing_indent =
 4483                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4484                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4485                        let start = selection.start;
 4486                        let end = selection.end;
 4487                        let selection_is_empty = start == end;
 4488                        let language_scope = buffer.language_scope_at(start);
 4489                        let (
 4490                            comment_delimiter,
 4491                            doc_delimiter,
 4492                            insert_extra_newline,
 4493                            indent_on_newline,
 4494                            indent_on_extra_newline,
 4495                        ) = if let Some(language) = &language_scope {
 4496                            let mut insert_extra_newline =
 4497                                insert_extra_newline_brackets(&buffer, start..end, language)
 4498                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4499
 4500                            // Comment extension on newline is allowed only for cursor selections
 4501                            let comment_delimiter = maybe!({
 4502                                if !selection_is_empty {
 4503                                    return None;
 4504                                }
 4505
 4506                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4507                                    return None;
 4508                                }
 4509
 4510                                let delimiters = language.line_comment_prefixes();
 4511                                let max_len_of_delimiter =
 4512                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4513                                let (snapshot, range) =
 4514                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4515
 4516                                let num_of_whitespaces = snapshot
 4517                                    .chars_for_range(range.clone())
 4518                                    .take_while(|c| c.is_whitespace())
 4519                                    .count();
 4520                                let comment_candidate = snapshot
 4521                                    .chars_for_range(range.clone())
 4522                                    .skip(num_of_whitespaces)
 4523                                    .take(max_len_of_delimiter)
 4524                                    .collect::<String>();
 4525                                let (delimiter, trimmed_len) = delimiters
 4526                                    .iter()
 4527                                    .filter_map(|delimiter| {
 4528                                        let prefix = delimiter.trim_end();
 4529                                        if comment_candidate.starts_with(prefix) {
 4530                                            Some((delimiter, prefix.len()))
 4531                                        } else {
 4532                                            None
 4533                                        }
 4534                                    })
 4535                                    .max_by_key(|(_, len)| *len)?;
 4536
 4537                                if let Some(BlockCommentConfig {
 4538                                    start: block_start, ..
 4539                                }) = language.block_comment()
 4540                                {
 4541                                    let block_start_trimmed = block_start.trim_end();
 4542                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4543                                        let line_content = snapshot
 4544                                            .chars_for_range(range)
 4545                                            .skip(num_of_whitespaces)
 4546                                            .take(block_start_trimmed.len())
 4547                                            .collect::<String>();
 4548
 4549                                        if line_content.starts_with(block_start_trimmed) {
 4550                                            return None;
 4551                                        }
 4552                                    }
 4553                                }
 4554
 4555                                let cursor_is_placed_after_comment_marker =
 4556                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4557                                if cursor_is_placed_after_comment_marker {
 4558                                    Some(delimiter.clone())
 4559                                } else {
 4560                                    None
 4561                                }
 4562                            });
 4563
 4564                            let mut indent_on_newline = IndentSize::spaces(0);
 4565                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4566
 4567                            let doc_delimiter = maybe!({
 4568                                if !selection_is_empty {
 4569                                    return None;
 4570                                }
 4571
 4572                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4573                                    return None;
 4574                                }
 4575
 4576                                let BlockCommentConfig {
 4577                                    start: start_tag,
 4578                                    end: end_tag,
 4579                                    prefix: delimiter,
 4580                                    tab_size: len,
 4581                                } = language.documentation_comment()?;
 4582                                let is_within_block_comment = buffer
 4583                                    .language_scope_at(start_point)
 4584                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4585                                if !is_within_block_comment {
 4586                                    return None;
 4587                                }
 4588
 4589                                let (snapshot, range) =
 4590                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4591
 4592                                let num_of_whitespaces = snapshot
 4593                                    .chars_for_range(range.clone())
 4594                                    .take_while(|c| c.is_whitespace())
 4595                                    .count();
 4596
 4597                                // 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.
 4598                                let column = start_point.column;
 4599                                let cursor_is_after_start_tag = {
 4600                                    let start_tag_len = start_tag.len();
 4601                                    let start_tag_line = snapshot
 4602                                        .chars_for_range(range.clone())
 4603                                        .skip(num_of_whitespaces)
 4604                                        .take(start_tag_len)
 4605                                        .collect::<String>();
 4606                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4607                                        num_of_whitespaces + start_tag_len <= column as usize
 4608                                    } else {
 4609                                        false
 4610                                    }
 4611                                };
 4612
 4613                                let cursor_is_after_delimiter = {
 4614                                    let delimiter_trim = delimiter.trim_end();
 4615                                    let delimiter_line = snapshot
 4616                                        .chars_for_range(range.clone())
 4617                                        .skip(num_of_whitespaces)
 4618                                        .take(delimiter_trim.len())
 4619                                        .collect::<String>();
 4620                                    if delimiter_line.starts_with(delimiter_trim) {
 4621                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4622                                    } else {
 4623                                        false
 4624                                    }
 4625                                };
 4626
 4627                                let cursor_is_before_end_tag_if_exists = {
 4628                                    let mut char_position = 0u32;
 4629                                    let mut end_tag_offset = None;
 4630
 4631                                    'outer: for chunk in snapshot.text_for_range(range) {
 4632                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4633                                            let chars_before_match =
 4634                                                chunk[..byte_pos].chars().count() as u32;
 4635                                            end_tag_offset =
 4636                                                Some(char_position + chars_before_match);
 4637                                            break 'outer;
 4638                                        }
 4639                                        char_position += chunk.chars().count() as u32;
 4640                                    }
 4641
 4642                                    if let Some(end_tag_offset) = end_tag_offset {
 4643                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4644                                        if cursor_is_after_start_tag {
 4645                                            if cursor_is_before_end_tag {
 4646                                                insert_extra_newline = true;
 4647                                            }
 4648                                            let cursor_is_at_start_of_end_tag =
 4649                                                column == end_tag_offset;
 4650                                            if cursor_is_at_start_of_end_tag {
 4651                                                indent_on_extra_newline.len = *len;
 4652                                            }
 4653                                        }
 4654                                        cursor_is_before_end_tag
 4655                                    } else {
 4656                                        true
 4657                                    }
 4658                                };
 4659
 4660                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4661                                    && cursor_is_before_end_tag_if_exists
 4662                                {
 4663                                    if cursor_is_after_start_tag {
 4664                                        indent_on_newline.len = *len;
 4665                                    }
 4666                                    Some(delimiter.clone())
 4667                                } else {
 4668                                    None
 4669                                }
 4670                            });
 4671
 4672                            (
 4673                                comment_delimiter,
 4674                                doc_delimiter,
 4675                                insert_extra_newline,
 4676                                indent_on_newline,
 4677                                indent_on_extra_newline,
 4678                            )
 4679                        } else {
 4680                            (
 4681                                None,
 4682                                None,
 4683                                false,
 4684                                IndentSize::default(),
 4685                                IndentSize::default(),
 4686                            )
 4687                        };
 4688
 4689                        let prevent_auto_indent = doc_delimiter.is_some();
 4690                        let delimiter = comment_delimiter.or(doc_delimiter);
 4691
 4692                        let capacity_for_delimiter =
 4693                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4694                        let mut new_text = String::with_capacity(
 4695                            1 + capacity_for_delimiter
 4696                                + existing_indent.len as usize
 4697                                + indent_on_newline.len as usize
 4698                                + indent_on_extra_newline.len as usize,
 4699                        );
 4700                        new_text.push('\n');
 4701                        new_text.extend(existing_indent.chars());
 4702                        new_text.extend(indent_on_newline.chars());
 4703
 4704                        if let Some(delimiter) = &delimiter {
 4705                            new_text.push_str(delimiter);
 4706                        }
 4707
 4708                        if insert_extra_newline {
 4709                            new_text.push('\n');
 4710                            new_text.extend(existing_indent.chars());
 4711                            new_text.extend(indent_on_extra_newline.chars());
 4712                        }
 4713
 4714                        let anchor = buffer.anchor_after(end);
 4715                        let new_selection = selection.map(|_| anchor);
 4716                        (
 4717                            ((start..end, new_text), prevent_auto_indent),
 4718                            (insert_extra_newline, new_selection),
 4719                        )
 4720                    })
 4721                    .unzip()
 4722            };
 4723
 4724            let mut auto_indent_edits = Vec::new();
 4725            let mut edits = Vec::new();
 4726            for (edit, prevent_auto_indent) in edits_with_flags {
 4727                if prevent_auto_indent {
 4728                    edits.push(edit);
 4729                } else {
 4730                    auto_indent_edits.push(edit);
 4731                }
 4732            }
 4733            if !edits.is_empty() {
 4734                this.edit(edits, cx);
 4735            }
 4736            if !auto_indent_edits.is_empty() {
 4737                this.edit_with_autoindent(auto_indent_edits, cx);
 4738            }
 4739
 4740            let buffer = this.buffer.read(cx).snapshot(cx);
 4741            let new_selections = selection_info
 4742                .into_iter()
 4743                .map(|(extra_newline_inserted, new_selection)| {
 4744                    let mut cursor = new_selection.end.to_point(&buffer);
 4745                    if extra_newline_inserted {
 4746                        cursor.row -= 1;
 4747                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4748                    }
 4749                    new_selection.map(|_| cursor)
 4750                })
 4751                .collect();
 4752
 4753            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4754            this.refresh_edit_prediction(true, false, window, cx);
 4755        });
 4756    }
 4757
 4758    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4759        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4760
 4761        let buffer = self.buffer.read(cx);
 4762        let snapshot = buffer.snapshot(cx);
 4763
 4764        let mut edits = Vec::new();
 4765        let mut rows = Vec::new();
 4766
 4767        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4768            let cursor = selection.head();
 4769            let row = cursor.row;
 4770
 4771            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4772
 4773            let newline = "\n".to_string();
 4774            edits.push((start_of_line..start_of_line, newline));
 4775
 4776            rows.push(row + rows_inserted as u32);
 4777        }
 4778
 4779        self.transact(window, cx, |editor, window, cx| {
 4780            editor.edit(edits, cx);
 4781
 4782            editor.change_selections(Default::default(), window, cx, |s| {
 4783                let mut index = 0;
 4784                s.move_cursors_with(|map, _, _| {
 4785                    let row = rows[index];
 4786                    index += 1;
 4787
 4788                    let point = Point::new(row, 0);
 4789                    let boundary = map.next_line_boundary(point).1;
 4790                    let clipped = map.clip_point(boundary, Bias::Left);
 4791
 4792                    (clipped, SelectionGoal::None)
 4793                });
 4794            });
 4795
 4796            let mut indent_edits = Vec::new();
 4797            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4798            for row in rows {
 4799                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4800                for (row, indent) in indents {
 4801                    if indent.len == 0 {
 4802                        continue;
 4803                    }
 4804
 4805                    let text = match indent.kind {
 4806                        IndentKind::Space => " ".repeat(indent.len as usize),
 4807                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4808                    };
 4809                    let point = Point::new(row.0, 0);
 4810                    indent_edits.push((point..point, text));
 4811                }
 4812            }
 4813            editor.edit(indent_edits, cx);
 4814        });
 4815    }
 4816
 4817    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4818        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4819
 4820        let buffer = self.buffer.read(cx);
 4821        let snapshot = buffer.snapshot(cx);
 4822
 4823        let mut edits = Vec::new();
 4824        let mut rows = Vec::new();
 4825        let mut rows_inserted = 0;
 4826
 4827        for selection in self.selections.all_adjusted(cx) {
 4828            let cursor = selection.head();
 4829            let row = cursor.row;
 4830
 4831            let point = Point::new(row + 1, 0);
 4832            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4833
 4834            let newline = "\n".to_string();
 4835            edits.push((start_of_line..start_of_line, newline));
 4836
 4837            rows_inserted += 1;
 4838            rows.push(row + rows_inserted);
 4839        }
 4840
 4841        self.transact(window, cx, |editor, window, cx| {
 4842            editor.edit(edits, cx);
 4843
 4844            editor.change_selections(Default::default(), window, cx, |s| {
 4845                let mut index = 0;
 4846                s.move_cursors_with(|map, _, _| {
 4847                    let row = rows[index];
 4848                    index += 1;
 4849
 4850                    let point = Point::new(row, 0);
 4851                    let boundary = map.next_line_boundary(point).1;
 4852                    let clipped = map.clip_point(boundary, Bias::Left);
 4853
 4854                    (clipped, SelectionGoal::None)
 4855                });
 4856            });
 4857
 4858            let mut indent_edits = Vec::new();
 4859            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4860            for row in rows {
 4861                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4862                for (row, indent) in indents {
 4863                    if indent.len == 0 {
 4864                        continue;
 4865                    }
 4866
 4867                    let text = match indent.kind {
 4868                        IndentKind::Space => " ".repeat(indent.len as usize),
 4869                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4870                    };
 4871                    let point = Point::new(row.0, 0);
 4872                    indent_edits.push((point..point, text));
 4873                }
 4874            }
 4875            editor.edit(indent_edits, cx);
 4876        });
 4877    }
 4878
 4879    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4880        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4881            original_indent_columns: Vec::new(),
 4882        });
 4883        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4884    }
 4885
 4886    fn insert_with_autoindent_mode(
 4887        &mut self,
 4888        text: &str,
 4889        autoindent_mode: Option<AutoindentMode>,
 4890        window: &mut Window,
 4891        cx: &mut Context<Self>,
 4892    ) {
 4893        if self.read_only(cx) {
 4894            return;
 4895        }
 4896
 4897        let text: Arc<str> = text.into();
 4898        self.transact(window, cx, |this, window, cx| {
 4899            let old_selections = this.selections.all_adjusted(cx);
 4900            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4901                let anchors = {
 4902                    let snapshot = buffer.read(cx);
 4903                    old_selections
 4904                        .iter()
 4905                        .map(|s| {
 4906                            let anchor = snapshot.anchor_after(s.head());
 4907                            s.map(|_| anchor)
 4908                        })
 4909                        .collect::<Vec<_>>()
 4910                };
 4911                buffer.edit(
 4912                    old_selections
 4913                        .iter()
 4914                        .map(|s| (s.start..s.end, text.clone())),
 4915                    autoindent_mode,
 4916                    cx,
 4917                );
 4918                anchors
 4919            });
 4920
 4921            this.change_selections(Default::default(), window, cx, |s| {
 4922                s.select_anchors(selection_anchors);
 4923            });
 4924
 4925            cx.notify();
 4926        });
 4927    }
 4928
 4929    fn trigger_completion_on_input(
 4930        &mut self,
 4931        text: &str,
 4932        trigger_in_words: bool,
 4933        window: &mut Window,
 4934        cx: &mut Context<Self>,
 4935    ) {
 4936        let completions_source = self
 4937            .context_menu
 4938            .borrow()
 4939            .as_ref()
 4940            .and_then(|menu| match menu {
 4941                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4942                CodeContextMenu::CodeActions(_) => None,
 4943            });
 4944
 4945        match completions_source {
 4946            Some(CompletionsMenuSource::Words { .. }) => {
 4947                self.open_or_update_completions_menu(
 4948                    Some(CompletionsMenuSource::Words {
 4949                        ignore_threshold: false,
 4950                    }),
 4951                    None,
 4952                    window,
 4953                    cx,
 4954                );
 4955            }
 4956            Some(CompletionsMenuSource::Normal)
 4957            | Some(CompletionsMenuSource::SnippetChoices)
 4958            | None
 4959                if self.is_completion_trigger(
 4960                    text,
 4961                    trigger_in_words,
 4962                    completions_source.is_some(),
 4963                    cx,
 4964                ) =>
 4965            {
 4966                self.show_completions(
 4967                    &ShowCompletions {
 4968                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4969                    },
 4970                    window,
 4971                    cx,
 4972                )
 4973            }
 4974            _ => {
 4975                self.hide_context_menu(window, cx);
 4976            }
 4977        }
 4978    }
 4979
 4980    fn is_completion_trigger(
 4981        &self,
 4982        text: &str,
 4983        trigger_in_words: bool,
 4984        menu_is_open: bool,
 4985        cx: &mut Context<Self>,
 4986    ) -> bool {
 4987        let position = self.selections.newest_anchor().head();
 4988        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4989            return false;
 4990        };
 4991
 4992        if let Some(completion_provider) = &self.completion_provider {
 4993            completion_provider.is_completion_trigger(
 4994                &buffer,
 4995                position.text_anchor,
 4996                text,
 4997                trigger_in_words,
 4998                menu_is_open,
 4999                cx,
 5000            )
 5001        } else {
 5002            false
 5003        }
 5004    }
 5005
 5006    /// If any empty selections is touching the start of its innermost containing autoclose
 5007    /// region, expand it to select the brackets.
 5008    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5009        let selections = self.selections.all::<usize>(cx);
 5010        let buffer = self.buffer.read(cx).read(cx);
 5011        let new_selections = self
 5012            .selections_with_autoclose_regions(selections, &buffer)
 5013            .map(|(mut selection, region)| {
 5014                if !selection.is_empty() {
 5015                    return selection;
 5016                }
 5017
 5018                if let Some(region) = region {
 5019                    let mut range = region.range.to_offset(&buffer);
 5020                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5021                        range.start -= region.pair.start.len();
 5022                        if buffer.contains_str_at(range.start, &region.pair.start)
 5023                            && buffer.contains_str_at(range.end, &region.pair.end)
 5024                        {
 5025                            range.end += region.pair.end.len();
 5026                            selection.start = range.start;
 5027                            selection.end = range.end;
 5028
 5029                            return selection;
 5030                        }
 5031                    }
 5032                }
 5033
 5034                let always_treat_brackets_as_autoclosed = buffer
 5035                    .language_settings_at(selection.start, cx)
 5036                    .always_treat_brackets_as_autoclosed;
 5037
 5038                if !always_treat_brackets_as_autoclosed {
 5039                    return selection;
 5040                }
 5041
 5042                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5043                    for (pair, enabled) in scope.brackets() {
 5044                        if !enabled || !pair.close {
 5045                            continue;
 5046                        }
 5047
 5048                        if buffer.contains_str_at(selection.start, &pair.end) {
 5049                            let pair_start_len = pair.start.len();
 5050                            if buffer.contains_str_at(
 5051                                selection.start.saturating_sub(pair_start_len),
 5052                                &pair.start,
 5053                            ) {
 5054                                selection.start -= pair_start_len;
 5055                                selection.end += pair.end.len();
 5056
 5057                                return selection;
 5058                            }
 5059                        }
 5060                    }
 5061                }
 5062
 5063                selection
 5064            })
 5065            .collect();
 5066
 5067        drop(buffer);
 5068        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5069            selections.select(new_selections)
 5070        });
 5071    }
 5072
 5073    /// Iterate the given selections, and for each one, find the smallest surrounding
 5074    /// autoclose region. This uses the ordering of the selections and the autoclose
 5075    /// regions to avoid repeated comparisons.
 5076    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5077        &'a self,
 5078        selections: impl IntoIterator<Item = Selection<D>>,
 5079        buffer: &'a MultiBufferSnapshot,
 5080    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5081        let mut i = 0;
 5082        let mut regions = self.autoclose_regions.as_slice();
 5083        selections.into_iter().map(move |selection| {
 5084            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5085
 5086            let mut enclosing = None;
 5087            while let Some(pair_state) = regions.get(i) {
 5088                if pair_state.range.end.to_offset(buffer) < range.start {
 5089                    regions = &regions[i + 1..];
 5090                    i = 0;
 5091                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5092                    break;
 5093                } else {
 5094                    if pair_state.selection_id == selection.id {
 5095                        enclosing = Some(pair_state);
 5096                    }
 5097                    i += 1;
 5098                }
 5099            }
 5100
 5101            (selection, enclosing)
 5102        })
 5103    }
 5104
 5105    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5106    fn invalidate_autoclose_regions(
 5107        &mut self,
 5108        mut selections: &[Selection<Anchor>],
 5109        buffer: &MultiBufferSnapshot,
 5110    ) {
 5111        self.autoclose_regions.retain(|state| {
 5112            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5113                return false;
 5114            }
 5115
 5116            let mut i = 0;
 5117            while let Some(selection) = selections.get(i) {
 5118                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5119                    selections = &selections[1..];
 5120                    continue;
 5121                }
 5122                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5123                    break;
 5124                }
 5125                if selection.id == state.selection_id {
 5126                    return true;
 5127                } else {
 5128                    i += 1;
 5129                }
 5130            }
 5131            false
 5132        });
 5133    }
 5134
 5135    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5136        let offset = position.to_offset(buffer);
 5137        let (word_range, kind) =
 5138            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5139        if offset > word_range.start && kind == Some(CharKind::Word) {
 5140            Some(
 5141                buffer
 5142                    .text_for_range(word_range.start..offset)
 5143                    .collect::<String>(),
 5144            )
 5145        } else {
 5146            None
 5147        }
 5148    }
 5149
 5150    pub fn toggle_inline_values(
 5151        &mut self,
 5152        _: &ToggleInlineValues,
 5153        _: &mut Window,
 5154        cx: &mut Context<Self>,
 5155    ) {
 5156        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5157
 5158        self.refresh_inline_values(cx);
 5159    }
 5160
 5161    pub fn toggle_inlay_hints(
 5162        &mut self,
 5163        _: &ToggleInlayHints,
 5164        _: &mut Window,
 5165        cx: &mut Context<Self>,
 5166    ) {
 5167        self.refresh_inlay_hints(
 5168            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5169            cx,
 5170        );
 5171    }
 5172
 5173    pub fn inlay_hints_enabled(&self) -> bool {
 5174        self.inlay_hint_cache.enabled
 5175    }
 5176
 5177    pub fn inline_values_enabled(&self) -> bool {
 5178        self.inline_value_cache.enabled
 5179    }
 5180
 5181    #[cfg(any(test, feature = "test-support"))]
 5182    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5183        self.display_map
 5184            .read(cx)
 5185            .current_inlays()
 5186            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5187            .cloned()
 5188            .collect()
 5189    }
 5190
 5191    #[cfg(any(test, feature = "test-support"))]
 5192    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5193        self.display_map
 5194            .read(cx)
 5195            .current_inlays()
 5196            .cloned()
 5197            .collect()
 5198    }
 5199
 5200    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5201        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5202            return;
 5203        }
 5204
 5205        let reason_description = reason.description();
 5206        let ignore_debounce = matches!(
 5207            reason,
 5208            InlayHintRefreshReason::SettingsChange(_)
 5209                | InlayHintRefreshReason::Toggle(_)
 5210                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5211                | InlayHintRefreshReason::ModifiersChanged(_)
 5212        );
 5213        let (invalidate_cache, required_languages) = match reason {
 5214            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5215                match self.inlay_hint_cache.modifiers_override(enabled) {
 5216                    Some(enabled) => {
 5217                        if enabled {
 5218                            (InvalidationStrategy::RefreshRequested, None)
 5219                        } else {
 5220                            self.splice_inlays(
 5221                                &self
 5222                                    .visible_inlay_hints(cx)
 5223                                    .iter()
 5224                                    .map(|inlay| inlay.id)
 5225                                    .collect::<Vec<InlayId>>(),
 5226                                Vec::new(),
 5227                                cx,
 5228                            );
 5229                            return;
 5230                        }
 5231                    }
 5232                    None => return,
 5233                }
 5234            }
 5235            InlayHintRefreshReason::Toggle(enabled) => {
 5236                if self.inlay_hint_cache.toggle(enabled) {
 5237                    if enabled {
 5238                        (InvalidationStrategy::RefreshRequested, None)
 5239                    } else {
 5240                        self.splice_inlays(
 5241                            &self
 5242                                .visible_inlay_hints(cx)
 5243                                .iter()
 5244                                .map(|inlay| inlay.id)
 5245                                .collect::<Vec<InlayId>>(),
 5246                            Vec::new(),
 5247                            cx,
 5248                        );
 5249                        return;
 5250                    }
 5251                } else {
 5252                    return;
 5253                }
 5254            }
 5255            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5256                match self.inlay_hint_cache.update_settings(
 5257                    &self.buffer,
 5258                    new_settings,
 5259                    self.visible_inlay_hints(cx),
 5260                    cx,
 5261                ) {
 5262                    ControlFlow::Break(Some(InlaySplice {
 5263                        to_remove,
 5264                        to_insert,
 5265                    })) => {
 5266                        self.splice_inlays(&to_remove, to_insert, cx);
 5267                        return;
 5268                    }
 5269                    ControlFlow::Break(None) => return,
 5270                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5271                }
 5272            }
 5273            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5274                if let Some(InlaySplice {
 5275                    to_remove,
 5276                    to_insert,
 5277                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5278                {
 5279                    self.splice_inlays(&to_remove, to_insert, cx);
 5280                }
 5281                self.display_map.update(cx, |display_map, _| {
 5282                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5283                });
 5284                return;
 5285            }
 5286            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5287            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5288                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5289            }
 5290            InlayHintRefreshReason::RefreshRequested => {
 5291                (InvalidationStrategy::RefreshRequested, None)
 5292            }
 5293        };
 5294
 5295        if let Some(InlaySplice {
 5296            to_remove,
 5297            to_insert,
 5298        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5299            reason_description,
 5300            self.visible_excerpts(required_languages.as_ref(), cx),
 5301            invalidate_cache,
 5302            ignore_debounce,
 5303            cx,
 5304        ) {
 5305            self.splice_inlays(&to_remove, to_insert, cx);
 5306        }
 5307    }
 5308
 5309    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5310        self.display_map
 5311            .read(cx)
 5312            .current_inlays()
 5313            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5314            .cloned()
 5315            .collect()
 5316    }
 5317
 5318    pub fn visible_excerpts(
 5319        &self,
 5320        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5321        cx: &mut Context<Editor>,
 5322    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5323        let Some(project) = self.project() else {
 5324            return HashMap::default();
 5325        };
 5326        let project = project.read(cx);
 5327        let multi_buffer = self.buffer().read(cx);
 5328        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5329        let multi_buffer_visible_start = self
 5330            .scroll_manager
 5331            .anchor()
 5332            .anchor
 5333            .to_point(&multi_buffer_snapshot);
 5334        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5335            multi_buffer_visible_start
 5336                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5337            Bias::Left,
 5338        );
 5339        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5340        multi_buffer_snapshot
 5341            .range_to_buffer_ranges(multi_buffer_visible_range)
 5342            .into_iter()
 5343            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5344            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5345                let buffer_file = project::File::from_dyn(buffer.file())?;
 5346                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5347                let worktree_entry = buffer_worktree
 5348                    .read(cx)
 5349                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5350                if worktree_entry.is_ignored {
 5351                    return None;
 5352                }
 5353
 5354                let language = buffer.language()?;
 5355                if let Some(restrict_to_languages) = restrict_to_languages
 5356                    && !restrict_to_languages.contains(language)
 5357                {
 5358                    return None;
 5359                }
 5360                Some((
 5361                    excerpt_id,
 5362                    (
 5363                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5364                        buffer.version().clone(),
 5365                        excerpt_visible_range,
 5366                    ),
 5367                ))
 5368            })
 5369            .collect()
 5370    }
 5371
 5372    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5373        TextLayoutDetails {
 5374            text_system: window.text_system().clone(),
 5375            editor_style: self.style.clone().unwrap(),
 5376            rem_size: window.rem_size(),
 5377            scroll_anchor: self.scroll_manager.anchor(),
 5378            visible_rows: self.visible_line_count(),
 5379            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5380        }
 5381    }
 5382
 5383    pub fn splice_inlays(
 5384        &self,
 5385        to_remove: &[InlayId],
 5386        to_insert: Vec<Inlay>,
 5387        cx: &mut Context<Self>,
 5388    ) {
 5389        self.display_map.update(cx, |display_map, cx| {
 5390            display_map.splice_inlays(to_remove, to_insert, cx)
 5391        });
 5392        cx.notify();
 5393    }
 5394
 5395    fn trigger_on_type_formatting(
 5396        &self,
 5397        input: String,
 5398        window: &mut Window,
 5399        cx: &mut Context<Self>,
 5400    ) -> Option<Task<Result<()>>> {
 5401        if input.len() != 1 {
 5402            return None;
 5403        }
 5404
 5405        let project = self.project()?;
 5406        let position = self.selections.newest_anchor().head();
 5407        let (buffer, buffer_position) = self
 5408            .buffer
 5409            .read(cx)
 5410            .text_anchor_for_position(position, cx)?;
 5411
 5412        let settings = language_settings::language_settings(
 5413            buffer
 5414                .read(cx)
 5415                .language_at(buffer_position)
 5416                .map(|l| l.name()),
 5417            buffer.read(cx).file(),
 5418            cx,
 5419        );
 5420        if !settings.use_on_type_format {
 5421            return None;
 5422        }
 5423
 5424        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5425        // hence we do LSP request & edit on host side only — add formats to host's history.
 5426        let push_to_lsp_host_history = true;
 5427        // If this is not the host, append its history with new edits.
 5428        let push_to_client_history = project.read(cx).is_via_collab();
 5429
 5430        let on_type_formatting = project.update(cx, |project, cx| {
 5431            project.on_type_format(
 5432                buffer.clone(),
 5433                buffer_position,
 5434                input,
 5435                push_to_lsp_host_history,
 5436                cx,
 5437            )
 5438        });
 5439        Some(cx.spawn_in(window, async move |editor, cx| {
 5440            if let Some(transaction) = on_type_formatting.await? {
 5441                if push_to_client_history {
 5442                    buffer
 5443                        .update(cx, |buffer, _| {
 5444                            buffer.push_transaction(transaction, Instant::now());
 5445                            buffer.finalize_last_transaction();
 5446                        })
 5447                        .ok();
 5448                }
 5449                editor.update(cx, |editor, cx| {
 5450                    editor.refresh_document_highlights(cx);
 5451                })?;
 5452            }
 5453            Ok(())
 5454        }))
 5455    }
 5456
 5457    pub fn show_word_completions(
 5458        &mut self,
 5459        _: &ShowWordCompletions,
 5460        window: &mut Window,
 5461        cx: &mut Context<Self>,
 5462    ) {
 5463        self.open_or_update_completions_menu(
 5464            Some(CompletionsMenuSource::Words {
 5465                ignore_threshold: true,
 5466            }),
 5467            None,
 5468            window,
 5469            cx,
 5470        );
 5471    }
 5472
 5473    pub fn show_completions(
 5474        &mut self,
 5475        options: &ShowCompletions,
 5476        window: &mut Window,
 5477        cx: &mut Context<Self>,
 5478    ) {
 5479        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5480    }
 5481
 5482    fn open_or_update_completions_menu(
 5483        &mut self,
 5484        requested_source: Option<CompletionsMenuSource>,
 5485        trigger: Option<&str>,
 5486        window: &mut Window,
 5487        cx: &mut Context<Self>,
 5488    ) {
 5489        if self.pending_rename.is_some() {
 5490            return;
 5491        }
 5492
 5493        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5494
 5495        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5496        // inserted and selected. To handle that case, the start of the selection is used so that
 5497        // the menu starts with all choices.
 5498        let position = self
 5499            .selections
 5500            .newest_anchor()
 5501            .start
 5502            .bias_right(&multibuffer_snapshot);
 5503        if position.diff_base_anchor.is_some() {
 5504            return;
 5505        }
 5506        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5507        let Some(buffer) = buffer_position
 5508            .buffer_id
 5509            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5510        else {
 5511            return;
 5512        };
 5513        let buffer_snapshot = buffer.read(cx).snapshot();
 5514
 5515        let query: Option<Arc<String>> =
 5516            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5517                .map(|query| query.into());
 5518
 5519        drop(multibuffer_snapshot);
 5520
 5521        // Hide the current completions menu when query is empty. Without this, cached
 5522        // completions from before the trigger char may be reused (#32774).
 5523        if query.is_none() {
 5524            let menu_is_open = matches!(
 5525                self.context_menu.borrow().as_ref(),
 5526                Some(CodeContextMenu::Completions(_))
 5527            );
 5528            if menu_is_open {
 5529                self.hide_context_menu(window, cx);
 5530            }
 5531        }
 5532
 5533        let mut ignore_word_threshold = false;
 5534        let provider = match requested_source {
 5535            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5536            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5537                ignore_word_threshold = ignore_threshold;
 5538                None
 5539            }
 5540            Some(CompletionsMenuSource::SnippetChoices) => {
 5541                log::error!("bug: SnippetChoices requested_source is not handled");
 5542                None
 5543            }
 5544        };
 5545
 5546        let sort_completions = provider
 5547            .as_ref()
 5548            .is_some_and(|provider| provider.sort_completions());
 5549
 5550        let filter_completions = provider
 5551            .as_ref()
 5552            .is_none_or(|provider| provider.filter_completions());
 5553
 5554        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5555            if filter_completions {
 5556                menu.filter(query.clone(), provider.clone(), window, cx);
 5557            }
 5558            // When `is_incomplete` is false, no need to re-query completions when the current query
 5559            // is a suffix of the initial query.
 5560            if !menu.is_incomplete {
 5561                // If the new query is a suffix of the old query (typing more characters) and
 5562                // the previous result was complete, the existing completions can be filtered.
 5563                //
 5564                // Note that this is always true for snippet completions.
 5565                let query_matches = match (&menu.initial_query, &query) {
 5566                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5567                    (None, _) => true,
 5568                    _ => false,
 5569                };
 5570                if query_matches {
 5571                    let position_matches = if menu.initial_position == position {
 5572                        true
 5573                    } else {
 5574                        let snapshot = self.buffer.read(cx).read(cx);
 5575                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5576                    };
 5577                    if position_matches {
 5578                        return;
 5579                    }
 5580                }
 5581            }
 5582        };
 5583
 5584        let trigger_kind = match trigger {
 5585            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5586                CompletionTriggerKind::TRIGGER_CHARACTER
 5587            }
 5588            _ => CompletionTriggerKind::INVOKED,
 5589        };
 5590        let completion_context = CompletionContext {
 5591            trigger_character: trigger.and_then(|trigger| {
 5592                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5593                    Some(String::from(trigger))
 5594                } else {
 5595                    None
 5596                }
 5597            }),
 5598            trigger_kind,
 5599        };
 5600
 5601        let Anchor {
 5602            excerpt_id: buffer_excerpt_id,
 5603            text_anchor: buffer_position,
 5604            ..
 5605        } = buffer_position;
 5606
 5607        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5608            buffer_snapshot.surrounding_word(buffer_position, None)
 5609        {
 5610            let word_to_exclude = buffer_snapshot
 5611                .text_for_range(word_range.clone())
 5612                .collect::<String>();
 5613            (
 5614                buffer_snapshot.anchor_before(word_range.start)
 5615                    ..buffer_snapshot.anchor_after(buffer_position),
 5616                Some(word_to_exclude),
 5617            )
 5618        } else {
 5619            (buffer_position..buffer_position, None)
 5620        };
 5621
 5622        let language = buffer_snapshot
 5623            .language_at(buffer_position)
 5624            .map(|language| language.name());
 5625
 5626        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5627            .completions
 5628            .clone();
 5629
 5630        let show_completion_documentation = buffer_snapshot
 5631            .settings_at(buffer_position, cx)
 5632            .show_completion_documentation;
 5633
 5634        // The document can be large, so stay in reasonable bounds when searching for words,
 5635        // otherwise completion pop-up might be slow to appear.
 5636        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5637        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5638        let min_word_search = buffer_snapshot.clip_point(
 5639            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5640            Bias::Left,
 5641        );
 5642        let max_word_search = buffer_snapshot.clip_point(
 5643            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5644            Bias::Right,
 5645        );
 5646        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5647            ..buffer_snapshot.point_to_offset(max_word_search);
 5648
 5649        let skip_digits = query
 5650            .as_ref()
 5651            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5652
 5653        let omit_word_completions = !self.word_completions_enabled
 5654            || (!ignore_word_threshold
 5655                && match &query {
 5656                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5657                    None => completion_settings.words_min_length != 0,
 5658                });
 5659
 5660        let (mut words, provider_responses) = match &provider {
 5661            Some(provider) => {
 5662                let provider_responses = provider.completions(
 5663                    buffer_excerpt_id,
 5664                    &buffer,
 5665                    buffer_position,
 5666                    completion_context,
 5667                    window,
 5668                    cx,
 5669                );
 5670
 5671                let words = match (omit_word_completions, completion_settings.words) {
 5672                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5673                        Task::ready(BTreeMap::default())
 5674                    }
 5675                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5676                        .background_spawn(async move {
 5677                            buffer_snapshot.words_in_range(WordsQuery {
 5678                                fuzzy_contents: None,
 5679                                range: word_search_range,
 5680                                skip_digits,
 5681                            })
 5682                        }),
 5683                };
 5684
 5685                (words, provider_responses)
 5686            }
 5687            None => {
 5688                let words = if omit_word_completions {
 5689                    Task::ready(BTreeMap::default())
 5690                } else {
 5691                    cx.background_spawn(async move {
 5692                        buffer_snapshot.words_in_range(WordsQuery {
 5693                            fuzzy_contents: None,
 5694                            range: word_search_range,
 5695                            skip_digits,
 5696                        })
 5697                    })
 5698                };
 5699                (words, Task::ready(Ok(Vec::new())))
 5700            }
 5701        };
 5702
 5703        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5704
 5705        let id = post_inc(&mut self.next_completion_id);
 5706        let task = cx.spawn_in(window, async move |editor, cx| {
 5707            let Ok(()) = editor.update(cx, |this, _| {
 5708                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5709            }) else {
 5710                return;
 5711            };
 5712
 5713            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5714            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5715            let mut completions = Vec::new();
 5716            let mut is_incomplete = false;
 5717            let mut display_options: Option<CompletionDisplayOptions> = None;
 5718            if let Some(provider_responses) = provider_responses.await.log_err()
 5719                && !provider_responses.is_empty()
 5720            {
 5721                for response in provider_responses {
 5722                    completions.extend(response.completions);
 5723                    is_incomplete = is_incomplete || response.is_incomplete;
 5724                    match display_options.as_mut() {
 5725                        None => {
 5726                            display_options = Some(response.display_options);
 5727                        }
 5728                        Some(options) => options.merge(&response.display_options),
 5729                    }
 5730                }
 5731                if completion_settings.words == WordsCompletionMode::Fallback {
 5732                    words = Task::ready(BTreeMap::default());
 5733                }
 5734            }
 5735            let display_options = display_options.unwrap_or_default();
 5736
 5737            let mut words = words.await;
 5738            if let Some(word_to_exclude) = &word_to_exclude {
 5739                words.remove(word_to_exclude);
 5740            }
 5741            for lsp_completion in &completions {
 5742                words.remove(&lsp_completion.new_text);
 5743            }
 5744            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5745                replace_range: word_replace_range.clone(),
 5746                new_text: word.clone(),
 5747                label: CodeLabel::plain(word, None),
 5748                icon_path: None,
 5749                documentation: None,
 5750                source: CompletionSource::BufferWord {
 5751                    word_range,
 5752                    resolved: false,
 5753                },
 5754                insert_text_mode: Some(InsertTextMode::AS_IS),
 5755                confirm: None,
 5756            }));
 5757
 5758            let menu = if completions.is_empty() {
 5759                None
 5760            } else {
 5761                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5762                    let languages = editor
 5763                        .workspace
 5764                        .as_ref()
 5765                        .and_then(|(workspace, _)| workspace.upgrade())
 5766                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5767                    let menu = CompletionsMenu::new(
 5768                        id,
 5769                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5770                        sort_completions,
 5771                        show_completion_documentation,
 5772                        position,
 5773                        query.clone(),
 5774                        is_incomplete,
 5775                        buffer.clone(),
 5776                        completions.into(),
 5777                        display_options,
 5778                        snippet_sort_order,
 5779                        languages,
 5780                        language,
 5781                        cx,
 5782                    );
 5783
 5784                    let query = if filter_completions { query } else { None };
 5785                    let matches_task = if let Some(query) = query {
 5786                        menu.do_async_filtering(query, cx)
 5787                    } else {
 5788                        Task::ready(menu.unfiltered_matches())
 5789                    };
 5790                    (menu, matches_task)
 5791                }) else {
 5792                    return;
 5793                };
 5794
 5795                let matches = matches_task.await;
 5796
 5797                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5798                    // Newer menu already set, so exit.
 5799                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5800                        editor.context_menu.borrow().as_ref()
 5801                        && prev_menu.id > id
 5802                    {
 5803                        return;
 5804                    };
 5805
 5806                    // Only valid to take prev_menu because it the new menu is immediately set
 5807                    // below, or the menu is hidden.
 5808                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5809                        editor.context_menu.borrow_mut().take()
 5810                    {
 5811                        let position_matches =
 5812                            if prev_menu.initial_position == menu.initial_position {
 5813                                true
 5814                            } else {
 5815                                let snapshot = editor.buffer.read(cx).read(cx);
 5816                                prev_menu.initial_position.to_offset(&snapshot)
 5817                                    == menu.initial_position.to_offset(&snapshot)
 5818                            };
 5819                        if position_matches {
 5820                            // Preserve markdown cache before `set_filter_results` because it will
 5821                            // try to populate the documentation cache.
 5822                            menu.preserve_markdown_cache(prev_menu);
 5823                        }
 5824                    };
 5825
 5826                    menu.set_filter_results(matches, provider, window, cx);
 5827                }) else {
 5828                    return;
 5829                };
 5830
 5831                menu.visible().then_some(menu)
 5832            };
 5833
 5834            editor
 5835                .update_in(cx, |editor, window, cx| {
 5836                    if editor.focus_handle.is_focused(window)
 5837                        && let Some(menu) = menu
 5838                    {
 5839                        *editor.context_menu.borrow_mut() =
 5840                            Some(CodeContextMenu::Completions(menu));
 5841
 5842                        crate::hover_popover::hide_hover(editor, cx);
 5843                        if editor.show_edit_predictions_in_menu() {
 5844                            editor.update_visible_edit_prediction(window, cx);
 5845                        } else {
 5846                            editor.discard_edit_prediction(false, cx);
 5847                        }
 5848
 5849                        cx.notify();
 5850                        return;
 5851                    }
 5852
 5853                    if editor.completion_tasks.len() <= 1 {
 5854                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5855                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5856                        // If it was already hidden and we don't show edit predictions in the menu,
 5857                        // we should also show the edit prediction when available.
 5858                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5859                            editor.update_visible_edit_prediction(window, cx);
 5860                        }
 5861                    }
 5862                })
 5863                .ok();
 5864        });
 5865
 5866        self.completion_tasks.push((id, task));
 5867    }
 5868
 5869    #[cfg(feature = "test-support")]
 5870    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5871        let menu = self.context_menu.borrow();
 5872        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5873            let completions = menu.completions.borrow();
 5874            Some(completions.to_vec())
 5875        } else {
 5876            None
 5877        }
 5878    }
 5879
 5880    pub fn with_completions_menu_matching_id<R>(
 5881        &self,
 5882        id: CompletionId,
 5883        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5884    ) -> R {
 5885        let mut context_menu = self.context_menu.borrow_mut();
 5886        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5887            return f(None);
 5888        };
 5889        if completions_menu.id != id {
 5890            return f(None);
 5891        }
 5892        f(Some(completions_menu))
 5893    }
 5894
 5895    pub fn confirm_completion(
 5896        &mut self,
 5897        action: &ConfirmCompletion,
 5898        window: &mut Window,
 5899        cx: &mut Context<Self>,
 5900    ) -> Option<Task<Result<()>>> {
 5901        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5902        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5903    }
 5904
 5905    pub fn confirm_completion_insert(
 5906        &mut self,
 5907        _: &ConfirmCompletionInsert,
 5908        window: &mut Window,
 5909        cx: &mut Context<Self>,
 5910    ) -> Option<Task<Result<()>>> {
 5911        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5912        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5913    }
 5914
 5915    pub fn confirm_completion_replace(
 5916        &mut self,
 5917        _: &ConfirmCompletionReplace,
 5918        window: &mut Window,
 5919        cx: &mut Context<Self>,
 5920    ) -> Option<Task<Result<()>>> {
 5921        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5922        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5923    }
 5924
 5925    pub fn compose_completion(
 5926        &mut self,
 5927        action: &ComposeCompletion,
 5928        window: &mut Window,
 5929        cx: &mut Context<Self>,
 5930    ) -> Option<Task<Result<()>>> {
 5931        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5932        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5933    }
 5934
 5935    fn do_completion(
 5936        &mut self,
 5937        item_ix: Option<usize>,
 5938        intent: CompletionIntent,
 5939        window: &mut Window,
 5940        cx: &mut Context<Editor>,
 5941    ) -> Option<Task<Result<()>>> {
 5942        use language::ToOffset as _;
 5943
 5944        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5945        else {
 5946            return None;
 5947        };
 5948
 5949        let candidate_id = {
 5950            let entries = completions_menu.entries.borrow();
 5951            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5952            if self.show_edit_predictions_in_menu() {
 5953                self.discard_edit_prediction(true, cx);
 5954            }
 5955            mat.candidate_id
 5956        };
 5957
 5958        let completion = completions_menu
 5959            .completions
 5960            .borrow()
 5961            .get(candidate_id)?
 5962            .clone();
 5963        cx.stop_propagation();
 5964
 5965        let buffer_handle = completions_menu.buffer.clone();
 5966
 5967        let CompletionEdit {
 5968            new_text,
 5969            snippet,
 5970            replace_range,
 5971        } = process_completion_for_edit(
 5972            &completion,
 5973            intent,
 5974            &buffer_handle,
 5975            &completions_menu.initial_position.text_anchor,
 5976            cx,
 5977        );
 5978
 5979        let buffer = buffer_handle.read(cx);
 5980        let snapshot = self.buffer.read(cx).snapshot(cx);
 5981        let newest_anchor = self.selections.newest_anchor();
 5982        let replace_range_multibuffer = {
 5983            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5984            let multibuffer_anchor = snapshot
 5985                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5986                .unwrap()
 5987                ..snapshot
 5988                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5989                    .unwrap();
 5990            multibuffer_anchor.start.to_offset(&snapshot)
 5991                ..multibuffer_anchor.end.to_offset(&snapshot)
 5992        };
 5993        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5994            return None;
 5995        }
 5996
 5997        let old_text = buffer
 5998            .text_for_range(replace_range.clone())
 5999            .collect::<String>();
 6000        let lookbehind = newest_anchor
 6001            .start
 6002            .text_anchor
 6003            .to_offset(buffer)
 6004            .saturating_sub(replace_range.start);
 6005        let lookahead = replace_range
 6006            .end
 6007            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6008        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6009        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6010
 6011        let selections = self.selections.all::<usize>(cx);
 6012        let mut ranges = Vec::new();
 6013        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6014
 6015        for selection in &selections {
 6016            let range = if selection.id == newest_anchor.id {
 6017                replace_range_multibuffer.clone()
 6018            } else {
 6019                let mut range = selection.range();
 6020
 6021                // if prefix is present, don't duplicate it
 6022                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6023                    range.start = range.start.saturating_sub(lookbehind);
 6024
 6025                    // if suffix is also present, mimic the newest cursor and replace it
 6026                    if selection.id != newest_anchor.id
 6027                        && snapshot.contains_str_at(range.end, suffix)
 6028                    {
 6029                        range.end += lookahead;
 6030                    }
 6031                }
 6032                range
 6033            };
 6034
 6035            ranges.push(range.clone());
 6036
 6037            if !self.linked_edit_ranges.is_empty() {
 6038                let start_anchor = snapshot.anchor_before(range.start);
 6039                let end_anchor = snapshot.anchor_after(range.end);
 6040                if let Some(ranges) = self
 6041                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6042                {
 6043                    for (buffer, edits) in ranges {
 6044                        linked_edits
 6045                            .entry(buffer.clone())
 6046                            .or_default()
 6047                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6048                    }
 6049                }
 6050            }
 6051        }
 6052
 6053        let common_prefix_len = old_text
 6054            .chars()
 6055            .zip(new_text.chars())
 6056            .take_while(|(a, b)| a == b)
 6057            .map(|(a, _)| a.len_utf8())
 6058            .sum::<usize>();
 6059
 6060        cx.emit(EditorEvent::InputHandled {
 6061            utf16_range_to_replace: None,
 6062            text: new_text[common_prefix_len..].into(),
 6063        });
 6064
 6065        self.transact(window, cx, |editor, window, cx| {
 6066            if let Some(mut snippet) = snippet {
 6067                snippet.text = new_text.to_string();
 6068                editor
 6069                    .insert_snippet(&ranges, snippet, window, cx)
 6070                    .log_err();
 6071            } else {
 6072                editor.buffer.update(cx, |multi_buffer, cx| {
 6073                    let auto_indent = match completion.insert_text_mode {
 6074                        Some(InsertTextMode::AS_IS) => None,
 6075                        _ => editor.autoindent_mode.clone(),
 6076                    };
 6077                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6078                    multi_buffer.edit(edits, auto_indent, cx);
 6079                });
 6080            }
 6081            for (buffer, edits) in linked_edits {
 6082                buffer.update(cx, |buffer, cx| {
 6083                    let snapshot = buffer.snapshot();
 6084                    let edits = edits
 6085                        .into_iter()
 6086                        .map(|(range, text)| {
 6087                            use text::ToPoint as TP;
 6088                            let end_point = TP::to_point(&range.end, &snapshot);
 6089                            let start_point = TP::to_point(&range.start, &snapshot);
 6090                            (start_point..end_point, text)
 6091                        })
 6092                        .sorted_by_key(|(range, _)| range.start);
 6093                    buffer.edit(edits, None, cx);
 6094                })
 6095            }
 6096
 6097            editor.refresh_edit_prediction(true, false, window, cx);
 6098        });
 6099        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6100
 6101        let show_new_completions_on_confirm = completion
 6102            .confirm
 6103            .as_ref()
 6104            .is_some_and(|confirm| confirm(intent, window, cx));
 6105        if show_new_completions_on_confirm {
 6106            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6107        }
 6108
 6109        let provider = self.completion_provider.as_ref()?;
 6110        drop(completion);
 6111        let apply_edits = provider.apply_additional_edits_for_completion(
 6112            buffer_handle,
 6113            completions_menu.completions.clone(),
 6114            candidate_id,
 6115            true,
 6116            cx,
 6117        );
 6118
 6119        let editor_settings = EditorSettings::get_global(cx);
 6120        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6121            // After the code completion is finished, users often want to know what signatures are needed.
 6122            // so we should automatically call signature_help
 6123            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6124        }
 6125
 6126        Some(cx.foreground_executor().spawn(async move {
 6127            apply_edits.await?;
 6128            Ok(())
 6129        }))
 6130    }
 6131
 6132    pub fn toggle_code_actions(
 6133        &mut self,
 6134        action: &ToggleCodeActions,
 6135        window: &mut Window,
 6136        cx: &mut Context<Self>,
 6137    ) {
 6138        let quick_launch = action.quick_launch;
 6139        let mut context_menu = self.context_menu.borrow_mut();
 6140        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6141            if code_actions.deployed_from == action.deployed_from {
 6142                // Toggle if we're selecting the same one
 6143                *context_menu = None;
 6144                cx.notify();
 6145                return;
 6146            } else {
 6147                // Otherwise, clear it and start a new one
 6148                *context_menu = None;
 6149                cx.notify();
 6150            }
 6151        }
 6152        drop(context_menu);
 6153        let snapshot = self.snapshot(window, cx);
 6154        let deployed_from = action.deployed_from.clone();
 6155        let action = action.clone();
 6156        self.completion_tasks.clear();
 6157        self.discard_edit_prediction(false, cx);
 6158
 6159        let multibuffer_point = match &action.deployed_from {
 6160            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6161                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6162            }
 6163            _ => self.selections.newest::<Point>(cx).head(),
 6164        };
 6165        let Some((buffer, buffer_row)) = snapshot
 6166            .buffer_snapshot()
 6167            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6168            .and_then(|(buffer_snapshot, range)| {
 6169                self.buffer()
 6170                    .read(cx)
 6171                    .buffer(buffer_snapshot.remote_id())
 6172                    .map(|buffer| (buffer, range.start.row))
 6173            })
 6174        else {
 6175            return;
 6176        };
 6177        let buffer_id = buffer.read(cx).remote_id();
 6178        let tasks = self
 6179            .tasks
 6180            .get(&(buffer_id, buffer_row))
 6181            .map(|t| Arc::new(t.to_owned()));
 6182
 6183        if !self.focus_handle.is_focused(window) {
 6184            return;
 6185        }
 6186        let project = self.project.clone();
 6187
 6188        let code_actions_task = match deployed_from {
 6189            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6190            _ => self.code_actions(buffer_row, window, cx),
 6191        };
 6192
 6193        let runnable_task = match deployed_from {
 6194            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6195            _ => {
 6196                let mut task_context_task = Task::ready(None);
 6197                if let Some(tasks) = &tasks
 6198                    && let Some(project) = project
 6199                {
 6200                    task_context_task =
 6201                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6202                }
 6203
 6204                cx.spawn_in(window, {
 6205                    let buffer = buffer.clone();
 6206                    async move |editor, cx| {
 6207                        let task_context = task_context_task.await;
 6208
 6209                        let resolved_tasks =
 6210                            tasks
 6211                                .zip(task_context.clone())
 6212                                .map(|(tasks, task_context)| ResolvedTasks {
 6213                                    templates: tasks.resolve(&task_context).collect(),
 6214                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6215                                        multibuffer_point.row,
 6216                                        tasks.column,
 6217                                    )),
 6218                                });
 6219                        let debug_scenarios = editor
 6220                            .update(cx, |editor, cx| {
 6221                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6222                            })?
 6223                            .await;
 6224                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6225                    }
 6226                })
 6227            }
 6228        };
 6229
 6230        cx.spawn_in(window, async move |editor, cx| {
 6231            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6232            let code_actions = code_actions_task.await;
 6233            let spawn_straight_away = quick_launch
 6234                && resolved_tasks
 6235                    .as_ref()
 6236                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6237                && code_actions
 6238                    .as_ref()
 6239                    .is_none_or(|actions| actions.is_empty())
 6240                && debug_scenarios.is_empty();
 6241
 6242            editor.update_in(cx, |editor, window, cx| {
 6243                crate::hover_popover::hide_hover(editor, cx);
 6244                let actions = CodeActionContents::new(
 6245                    resolved_tasks,
 6246                    code_actions,
 6247                    debug_scenarios,
 6248                    task_context.unwrap_or_default(),
 6249                );
 6250
 6251                // Don't show the menu if there are no actions available
 6252                if actions.is_empty() {
 6253                    cx.notify();
 6254                    return Task::ready(Ok(()));
 6255                }
 6256
 6257                *editor.context_menu.borrow_mut() =
 6258                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6259                        buffer,
 6260                        actions,
 6261                        selected_item: Default::default(),
 6262                        scroll_handle: UniformListScrollHandle::default(),
 6263                        deployed_from,
 6264                    }));
 6265                cx.notify();
 6266                if spawn_straight_away
 6267                    && let Some(task) = editor.confirm_code_action(
 6268                        &ConfirmCodeAction { item_ix: Some(0) },
 6269                        window,
 6270                        cx,
 6271                    )
 6272                {
 6273                    return task;
 6274                }
 6275
 6276                Task::ready(Ok(()))
 6277            })
 6278        })
 6279        .detach_and_log_err(cx);
 6280    }
 6281
 6282    fn debug_scenarios(
 6283        &mut self,
 6284        resolved_tasks: &Option<ResolvedTasks>,
 6285        buffer: &Entity<Buffer>,
 6286        cx: &mut App,
 6287    ) -> Task<Vec<task::DebugScenario>> {
 6288        maybe!({
 6289            let project = self.project()?;
 6290            let dap_store = project.read(cx).dap_store();
 6291            let mut scenarios = vec![];
 6292            let resolved_tasks = resolved_tasks.as_ref()?;
 6293            let buffer = buffer.read(cx);
 6294            let language = buffer.language()?;
 6295            let file = buffer.file();
 6296            let debug_adapter = language_settings(language.name().into(), file, cx)
 6297                .debuggers
 6298                .first()
 6299                .map(SharedString::from)
 6300                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6301
 6302            dap_store.update(cx, |dap_store, cx| {
 6303                for (_, task) in &resolved_tasks.templates {
 6304                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6305                        task.original_task().clone(),
 6306                        debug_adapter.clone().into(),
 6307                        task.display_label().to_owned().into(),
 6308                        cx,
 6309                    );
 6310                    scenarios.push(maybe_scenario);
 6311                }
 6312            });
 6313            Some(cx.background_spawn(async move {
 6314                futures::future::join_all(scenarios)
 6315                    .await
 6316                    .into_iter()
 6317                    .flatten()
 6318                    .collect::<Vec<_>>()
 6319            }))
 6320        })
 6321        .unwrap_or_else(|| Task::ready(vec![]))
 6322    }
 6323
 6324    fn code_actions(
 6325        &mut self,
 6326        buffer_row: u32,
 6327        window: &mut Window,
 6328        cx: &mut Context<Self>,
 6329    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6330        let mut task = self.code_actions_task.take();
 6331        cx.spawn_in(window, async move |editor, cx| {
 6332            while let Some(prev_task) = task {
 6333                prev_task.await.log_err();
 6334                task = editor
 6335                    .update(cx, |this, _| this.code_actions_task.take())
 6336                    .ok()?;
 6337            }
 6338
 6339            editor
 6340                .update(cx, |editor, cx| {
 6341                    editor
 6342                        .available_code_actions
 6343                        .clone()
 6344                        .and_then(|(location, code_actions)| {
 6345                            let snapshot = location.buffer.read(cx).snapshot();
 6346                            let point_range = location.range.to_point(&snapshot);
 6347                            let point_range = point_range.start.row..=point_range.end.row;
 6348                            if point_range.contains(&buffer_row) {
 6349                                Some(code_actions)
 6350                            } else {
 6351                                None
 6352                            }
 6353                        })
 6354                })
 6355                .ok()
 6356                .flatten()
 6357        })
 6358    }
 6359
 6360    pub fn confirm_code_action(
 6361        &mut self,
 6362        action: &ConfirmCodeAction,
 6363        window: &mut Window,
 6364        cx: &mut Context<Self>,
 6365    ) -> Option<Task<Result<()>>> {
 6366        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6367
 6368        let actions_menu =
 6369            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6370                menu
 6371            } else {
 6372                return None;
 6373            };
 6374
 6375        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6376        let action = actions_menu.actions.get(action_ix)?;
 6377        let title = action.label();
 6378        let buffer = actions_menu.buffer;
 6379        let workspace = self.workspace()?;
 6380
 6381        match action {
 6382            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6383                workspace.update(cx, |workspace, cx| {
 6384                    workspace.schedule_resolved_task(
 6385                        task_source_kind,
 6386                        resolved_task,
 6387                        false,
 6388                        window,
 6389                        cx,
 6390                    );
 6391
 6392                    Some(Task::ready(Ok(())))
 6393                })
 6394            }
 6395            CodeActionsItem::CodeAction {
 6396                excerpt_id,
 6397                action,
 6398                provider,
 6399            } => {
 6400                let apply_code_action =
 6401                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6402                let workspace = workspace.downgrade();
 6403                Some(cx.spawn_in(window, async move |editor, cx| {
 6404                    let project_transaction = apply_code_action.await?;
 6405                    Self::open_project_transaction(
 6406                        &editor,
 6407                        workspace,
 6408                        project_transaction,
 6409                        title,
 6410                        cx,
 6411                    )
 6412                    .await
 6413                }))
 6414            }
 6415            CodeActionsItem::DebugScenario(scenario) => {
 6416                let context = actions_menu.actions.context;
 6417
 6418                workspace.update(cx, |workspace, cx| {
 6419                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6420                    workspace.start_debug_session(
 6421                        scenario,
 6422                        context,
 6423                        Some(buffer),
 6424                        None,
 6425                        window,
 6426                        cx,
 6427                    );
 6428                });
 6429                Some(Task::ready(Ok(())))
 6430            }
 6431        }
 6432    }
 6433
 6434    pub async fn open_project_transaction(
 6435        editor: &WeakEntity<Editor>,
 6436        workspace: WeakEntity<Workspace>,
 6437        transaction: ProjectTransaction,
 6438        title: String,
 6439        cx: &mut AsyncWindowContext,
 6440    ) -> Result<()> {
 6441        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6442        cx.update(|_, cx| {
 6443            entries.sort_unstable_by_key(|(buffer, _)| {
 6444                buffer.read(cx).file().map(|f| f.path().clone())
 6445            });
 6446        })?;
 6447        if entries.is_empty() {
 6448            return Ok(());
 6449        }
 6450
 6451        // If the project transaction's edits are all contained within this editor, then
 6452        // avoid opening a new editor to display them.
 6453
 6454        if let [(buffer, transaction)] = &*entries {
 6455            let excerpt = editor.update(cx, |editor, cx| {
 6456                editor
 6457                    .buffer()
 6458                    .read(cx)
 6459                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6460            })?;
 6461            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6462                && excerpted_buffer == *buffer
 6463            {
 6464                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6465                    let excerpt_range = excerpt_range.to_offset(buffer);
 6466                    buffer
 6467                        .edited_ranges_for_transaction::<usize>(transaction)
 6468                        .all(|range| {
 6469                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6470                        })
 6471                })?;
 6472
 6473                if all_edits_within_excerpt {
 6474                    return Ok(());
 6475                }
 6476            }
 6477        }
 6478
 6479        let mut ranges_to_highlight = Vec::new();
 6480        let excerpt_buffer = cx.new(|cx| {
 6481            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6482            for (buffer_handle, transaction) in &entries {
 6483                let edited_ranges = buffer_handle
 6484                    .read(cx)
 6485                    .edited_ranges_for_transaction::<Point>(transaction)
 6486                    .collect::<Vec<_>>();
 6487                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6488                    PathKey::for_buffer(buffer_handle, cx),
 6489                    buffer_handle.clone(),
 6490                    edited_ranges,
 6491                    multibuffer_context_lines(cx),
 6492                    cx,
 6493                );
 6494
 6495                ranges_to_highlight.extend(ranges);
 6496            }
 6497            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6498            multibuffer
 6499        })?;
 6500
 6501        workspace.update_in(cx, |workspace, window, cx| {
 6502            let project = workspace.project().clone();
 6503            let editor =
 6504                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6505            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6506            editor.update(cx, |editor, cx| {
 6507                editor.highlight_background::<Self>(
 6508                    &ranges_to_highlight,
 6509                    |theme| theme.colors().editor_highlighted_line_background,
 6510                    cx,
 6511                );
 6512            });
 6513        })?;
 6514
 6515        Ok(())
 6516    }
 6517
 6518    pub fn clear_code_action_providers(&mut self) {
 6519        self.code_action_providers.clear();
 6520        self.available_code_actions.take();
 6521    }
 6522
 6523    pub fn add_code_action_provider(
 6524        &mut self,
 6525        provider: Rc<dyn CodeActionProvider>,
 6526        window: &mut Window,
 6527        cx: &mut Context<Self>,
 6528    ) {
 6529        if self
 6530            .code_action_providers
 6531            .iter()
 6532            .any(|existing_provider| existing_provider.id() == provider.id())
 6533        {
 6534            return;
 6535        }
 6536
 6537        self.code_action_providers.push(provider);
 6538        self.refresh_code_actions(window, cx);
 6539    }
 6540
 6541    pub fn remove_code_action_provider(
 6542        &mut self,
 6543        id: Arc<str>,
 6544        window: &mut Window,
 6545        cx: &mut Context<Self>,
 6546    ) {
 6547        self.code_action_providers
 6548            .retain(|provider| provider.id() != id);
 6549        self.refresh_code_actions(window, cx);
 6550    }
 6551
 6552    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6553        !self.code_action_providers.is_empty()
 6554            && EditorSettings::get_global(cx).toolbar.code_actions
 6555    }
 6556
 6557    pub fn has_available_code_actions(&self) -> bool {
 6558        self.available_code_actions
 6559            .as_ref()
 6560            .is_some_and(|(_, actions)| !actions.is_empty())
 6561    }
 6562
 6563    fn render_inline_code_actions(
 6564        &self,
 6565        icon_size: ui::IconSize,
 6566        display_row: DisplayRow,
 6567        is_active: bool,
 6568        cx: &mut Context<Self>,
 6569    ) -> AnyElement {
 6570        let show_tooltip = !self.context_menu_visible();
 6571        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6572            .icon_size(icon_size)
 6573            .shape(ui::IconButtonShape::Square)
 6574            .icon_color(ui::Color::Hidden)
 6575            .toggle_state(is_active)
 6576            .when(show_tooltip, |this| {
 6577                this.tooltip({
 6578                    let focus_handle = self.focus_handle.clone();
 6579                    move |window, cx| {
 6580                        Tooltip::for_action_in(
 6581                            "Toggle Code Actions",
 6582                            &ToggleCodeActions {
 6583                                deployed_from: None,
 6584                                quick_launch: false,
 6585                            },
 6586                            &focus_handle,
 6587                            window,
 6588                            cx,
 6589                        )
 6590                    }
 6591                })
 6592            })
 6593            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6594                window.focus(&editor.focus_handle(cx));
 6595                editor.toggle_code_actions(
 6596                    &crate::actions::ToggleCodeActions {
 6597                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6598                            display_row,
 6599                        )),
 6600                        quick_launch: false,
 6601                    },
 6602                    window,
 6603                    cx,
 6604                );
 6605            }))
 6606            .into_any_element()
 6607    }
 6608
 6609    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6610        &self.context_menu
 6611    }
 6612
 6613    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6614        let newest_selection = self.selections.newest_anchor().clone();
 6615        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6616        let buffer = self.buffer.read(cx);
 6617        if newest_selection.head().diff_base_anchor.is_some() {
 6618            return None;
 6619        }
 6620        let (start_buffer, start) =
 6621            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6622        let (end_buffer, end) =
 6623            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6624        if start_buffer != end_buffer {
 6625            return None;
 6626        }
 6627
 6628        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6629            cx.background_executor()
 6630                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6631                .await;
 6632
 6633            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6634                let providers = this.code_action_providers.clone();
 6635                let tasks = this
 6636                    .code_action_providers
 6637                    .iter()
 6638                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6639                    .collect::<Vec<_>>();
 6640                (providers, tasks)
 6641            })?;
 6642
 6643            let mut actions = Vec::new();
 6644            for (provider, provider_actions) in
 6645                providers.into_iter().zip(future::join_all(tasks).await)
 6646            {
 6647                if let Some(provider_actions) = provider_actions.log_err() {
 6648                    actions.extend(provider_actions.into_iter().map(|action| {
 6649                        AvailableCodeAction {
 6650                            excerpt_id: newest_selection.start.excerpt_id,
 6651                            action,
 6652                            provider: provider.clone(),
 6653                        }
 6654                    }));
 6655                }
 6656            }
 6657
 6658            this.update(cx, |this, cx| {
 6659                this.available_code_actions = if actions.is_empty() {
 6660                    None
 6661                } else {
 6662                    Some((
 6663                        Location {
 6664                            buffer: start_buffer,
 6665                            range: start..end,
 6666                        },
 6667                        actions.into(),
 6668                    ))
 6669                };
 6670                cx.notify();
 6671            })
 6672        }));
 6673        None
 6674    }
 6675
 6676    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6677        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6678            self.show_git_blame_inline = false;
 6679
 6680            self.show_git_blame_inline_delay_task =
 6681                Some(cx.spawn_in(window, async move |this, cx| {
 6682                    cx.background_executor().timer(delay).await;
 6683
 6684                    this.update(cx, |this, cx| {
 6685                        this.show_git_blame_inline = true;
 6686                        cx.notify();
 6687                    })
 6688                    .log_err();
 6689                }));
 6690        }
 6691    }
 6692
 6693    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6694        let snapshot = self.snapshot(window, cx);
 6695        let cursor = self.selections.newest::<Point>(cx).head();
 6696        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6697        else {
 6698            return;
 6699        };
 6700
 6701        let Some(blame) = self.blame.as_ref() else {
 6702            return;
 6703        };
 6704
 6705        let row_info = RowInfo {
 6706            buffer_id: Some(buffer.remote_id()),
 6707            buffer_row: Some(point.row),
 6708            ..Default::default()
 6709        };
 6710        let Some((buffer, blame_entry)) = blame
 6711            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6712            .flatten()
 6713        else {
 6714            return;
 6715        };
 6716
 6717        let anchor = self.selections.newest_anchor().head();
 6718        let position = self.to_pixel_point(anchor, &snapshot, window);
 6719        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6720            self.show_blame_popover(
 6721                buffer,
 6722                &blame_entry,
 6723                position + last_bounds.origin,
 6724                true,
 6725                cx,
 6726            );
 6727        };
 6728    }
 6729
 6730    fn show_blame_popover(
 6731        &mut self,
 6732        buffer: BufferId,
 6733        blame_entry: &BlameEntry,
 6734        position: gpui::Point<Pixels>,
 6735        ignore_timeout: bool,
 6736        cx: &mut Context<Self>,
 6737    ) {
 6738        if let Some(state) = &mut self.inline_blame_popover {
 6739            state.hide_task.take();
 6740        } else {
 6741            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6742            let blame_entry = blame_entry.clone();
 6743            let show_task = cx.spawn(async move |editor, cx| {
 6744                if !ignore_timeout {
 6745                    cx.background_executor()
 6746                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6747                        .await;
 6748                }
 6749                editor
 6750                    .update(cx, |editor, cx| {
 6751                        editor.inline_blame_popover_show_task.take();
 6752                        let Some(blame) = editor.blame.as_ref() else {
 6753                            return;
 6754                        };
 6755                        let blame = blame.read(cx);
 6756                        let details = blame.details_for_entry(buffer, &blame_entry);
 6757                        let markdown = cx.new(|cx| {
 6758                            Markdown::new(
 6759                                details
 6760                                    .as_ref()
 6761                                    .map(|message| message.message.clone())
 6762                                    .unwrap_or_default(),
 6763                                None,
 6764                                None,
 6765                                cx,
 6766                            )
 6767                        });
 6768                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6769                            position,
 6770                            hide_task: None,
 6771                            popover_bounds: None,
 6772                            popover_state: InlineBlamePopoverState {
 6773                                scroll_handle: ScrollHandle::new(),
 6774                                commit_message: details,
 6775                                markdown,
 6776                            },
 6777                            keyboard_grace: ignore_timeout,
 6778                        });
 6779                        cx.notify();
 6780                    })
 6781                    .ok();
 6782            });
 6783            self.inline_blame_popover_show_task = Some(show_task);
 6784        }
 6785    }
 6786
 6787    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6788        self.inline_blame_popover_show_task.take();
 6789        if let Some(state) = &mut self.inline_blame_popover {
 6790            let hide_task = cx.spawn(async move |editor, cx| {
 6791                cx.background_executor()
 6792                    .timer(std::time::Duration::from_millis(100))
 6793                    .await;
 6794                editor
 6795                    .update(cx, |editor, cx| {
 6796                        editor.inline_blame_popover.take();
 6797                        cx.notify();
 6798                    })
 6799                    .ok();
 6800            });
 6801            state.hide_task = Some(hide_task);
 6802        }
 6803    }
 6804
 6805    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6806        if self.pending_rename.is_some() {
 6807            return None;
 6808        }
 6809
 6810        let provider = self.semantics_provider.clone()?;
 6811        let buffer = self.buffer.read(cx);
 6812        let newest_selection = self.selections.newest_anchor().clone();
 6813        let cursor_position = newest_selection.head();
 6814        let (cursor_buffer, cursor_buffer_position) =
 6815            buffer.text_anchor_for_position(cursor_position, cx)?;
 6816        let (tail_buffer, tail_buffer_position) =
 6817            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6818        if cursor_buffer != tail_buffer {
 6819            return None;
 6820        }
 6821
 6822        let snapshot = cursor_buffer.read(cx).snapshot();
 6823        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6824        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6825        if start_word_range != end_word_range {
 6826            self.document_highlights_task.take();
 6827            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6828            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6829            return None;
 6830        }
 6831
 6832        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6833        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6834            cx.background_executor()
 6835                .timer(Duration::from_millis(debounce))
 6836                .await;
 6837
 6838            let highlights = if let Some(highlights) = cx
 6839                .update(|cx| {
 6840                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6841                })
 6842                .ok()
 6843                .flatten()
 6844            {
 6845                highlights.await.log_err()
 6846            } else {
 6847                None
 6848            };
 6849
 6850            if let Some(highlights) = highlights {
 6851                this.update(cx, |this, cx| {
 6852                    if this.pending_rename.is_some() {
 6853                        return;
 6854                    }
 6855
 6856                    let buffer = this.buffer.read(cx);
 6857                    if buffer
 6858                        .text_anchor_for_position(cursor_position, cx)
 6859                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6860                    {
 6861                        return;
 6862                    }
 6863
 6864                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6865                    let mut write_ranges = Vec::new();
 6866                    let mut read_ranges = Vec::new();
 6867                    for highlight in highlights {
 6868                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6869                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6870                        {
 6871                            let start = highlight
 6872                                .range
 6873                                .start
 6874                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6875                            let end = highlight
 6876                                .range
 6877                                .end
 6878                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6879                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6880                                continue;
 6881                            }
 6882
 6883                            let range = Anchor::range_in_buffer(excerpt_id, buffer_id, start..end);
 6884                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6885                                write_ranges.push(range);
 6886                            } else {
 6887                                read_ranges.push(range);
 6888                            }
 6889                        }
 6890                    }
 6891
 6892                    this.highlight_background::<DocumentHighlightRead>(
 6893                        &read_ranges,
 6894                        |theme| theme.colors().editor_document_highlight_read_background,
 6895                        cx,
 6896                    );
 6897                    this.highlight_background::<DocumentHighlightWrite>(
 6898                        &write_ranges,
 6899                        |theme| theme.colors().editor_document_highlight_write_background,
 6900                        cx,
 6901                    );
 6902                    cx.notify();
 6903                })
 6904                .log_err();
 6905            }
 6906        }));
 6907        None
 6908    }
 6909
 6910    fn prepare_highlight_query_from_selection(
 6911        &mut self,
 6912        cx: &mut Context<Editor>,
 6913    ) -> Option<(String, Range<Anchor>)> {
 6914        if matches!(self.mode, EditorMode::SingleLine) {
 6915            return None;
 6916        }
 6917        if !EditorSettings::get_global(cx).selection_highlight {
 6918            return None;
 6919        }
 6920        if self.selections.count() != 1 || self.selections.line_mode() {
 6921            return None;
 6922        }
 6923        let selection = self.selections.newest::<Point>(cx);
 6924        if selection.is_empty() || selection.start.row != selection.end.row {
 6925            return None;
 6926        }
 6927        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6928        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6929        let query = multi_buffer_snapshot
 6930            .text_for_range(selection_anchor_range.clone())
 6931            .collect::<String>();
 6932        if query.trim().is_empty() {
 6933            return None;
 6934        }
 6935        Some((query, selection_anchor_range))
 6936    }
 6937
 6938    fn update_selection_occurrence_highlights(
 6939        &mut self,
 6940        query_text: String,
 6941        query_range: Range<Anchor>,
 6942        multi_buffer_range_to_query: Range<Point>,
 6943        use_debounce: bool,
 6944        window: &mut Window,
 6945        cx: &mut Context<Editor>,
 6946    ) -> Task<()> {
 6947        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6948        cx.spawn_in(window, async move |editor, cx| {
 6949            if use_debounce {
 6950                cx.background_executor()
 6951                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6952                    .await;
 6953            }
 6954            let match_task = cx.background_spawn(async move {
 6955                let buffer_ranges = multi_buffer_snapshot
 6956                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6957                    .into_iter()
 6958                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6959                let mut match_ranges = Vec::new();
 6960                let Ok(regex) = project::search::SearchQuery::text(
 6961                    query_text.clone(),
 6962                    false,
 6963                    false,
 6964                    false,
 6965                    Default::default(),
 6966                    Default::default(),
 6967                    false,
 6968                    None,
 6969                ) else {
 6970                    return Vec::default();
 6971                };
 6972                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6973                    match_ranges.extend(
 6974                        regex
 6975                            .search(buffer_snapshot, Some(search_range.clone()))
 6976                            .await
 6977                            .into_iter()
 6978                            .filter_map(|match_range| {
 6979                                let match_start = buffer_snapshot
 6980                                    .anchor_after(search_range.start + match_range.start);
 6981                                let match_end = buffer_snapshot
 6982                                    .anchor_before(search_range.start + match_range.end);
 6983                                let match_anchor_range = Anchor::range_in_buffer(
 6984                                    excerpt_id,
 6985                                    buffer_snapshot.remote_id(),
 6986                                    match_start..match_end,
 6987                                );
 6988                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6989                            }),
 6990                    );
 6991                }
 6992                match_ranges
 6993            });
 6994            let match_ranges = match_task.await;
 6995            editor
 6996                .update_in(cx, |editor, _, cx| {
 6997                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6998                    if !match_ranges.is_empty() {
 6999                        editor.highlight_background::<SelectedTextHighlight>(
 7000                            &match_ranges,
 7001                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7002                            cx,
 7003                        )
 7004                    }
 7005                })
 7006                .log_err();
 7007        })
 7008    }
 7009
 7010    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7011        struct NewlineFold;
 7012        let type_id = std::any::TypeId::of::<NewlineFold>();
 7013        if !self.mode.is_single_line() {
 7014            return;
 7015        }
 7016        let snapshot = self.snapshot(window, cx);
 7017        if snapshot.buffer_snapshot().max_point().row == 0 {
 7018            return;
 7019        }
 7020        let task = cx.background_spawn(async move {
 7021            let new_newlines = snapshot
 7022                .buffer_chars_at(0)
 7023                .filter_map(|(c, i)| {
 7024                    if c == '\n' {
 7025                        Some(
 7026                            snapshot.buffer_snapshot().anchor_after(i)
 7027                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7028                        )
 7029                    } else {
 7030                        None
 7031                    }
 7032                })
 7033                .collect::<Vec<_>>();
 7034            let existing_newlines = snapshot
 7035                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7036                .filter_map(|fold| {
 7037                    if fold.placeholder.type_tag == Some(type_id) {
 7038                        Some(fold.range.start..fold.range.end)
 7039                    } else {
 7040                        None
 7041                    }
 7042                })
 7043                .collect::<Vec<_>>();
 7044
 7045            (new_newlines, existing_newlines)
 7046        });
 7047        self.folding_newlines = cx.spawn(async move |this, cx| {
 7048            let (new_newlines, existing_newlines) = task.await;
 7049            if new_newlines == existing_newlines {
 7050                return;
 7051            }
 7052            let placeholder = FoldPlaceholder {
 7053                render: Arc::new(move |_, _, cx| {
 7054                    div()
 7055                        .bg(cx.theme().status().hint_background)
 7056                        .border_b_1()
 7057                        .size_full()
 7058                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7059                        .border_color(cx.theme().status().hint)
 7060                        .child("\\n")
 7061                        .into_any()
 7062                }),
 7063                constrain_width: false,
 7064                merge_adjacent: false,
 7065                type_tag: Some(type_id),
 7066            };
 7067            let creases = new_newlines
 7068                .into_iter()
 7069                .map(|range| Crease::simple(range, placeholder.clone()))
 7070                .collect();
 7071            this.update(cx, |this, cx| {
 7072                this.display_map.update(cx, |display_map, cx| {
 7073                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7074                    display_map.fold(creases, cx);
 7075                });
 7076            })
 7077            .ok();
 7078        });
 7079    }
 7080
 7081    fn refresh_selected_text_highlights(
 7082        &mut self,
 7083        on_buffer_edit: bool,
 7084        window: &mut Window,
 7085        cx: &mut Context<Editor>,
 7086    ) {
 7087        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7088        else {
 7089            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7090            self.quick_selection_highlight_task.take();
 7091            self.debounced_selection_highlight_task.take();
 7092            return;
 7093        };
 7094        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7095        if on_buffer_edit
 7096            || self
 7097                .quick_selection_highlight_task
 7098                .as_ref()
 7099                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7100        {
 7101            let multi_buffer_visible_start = self
 7102                .scroll_manager
 7103                .anchor()
 7104                .anchor
 7105                .to_point(&multi_buffer_snapshot);
 7106            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7107                multi_buffer_visible_start
 7108                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7109                Bias::Left,
 7110            );
 7111            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7112            self.quick_selection_highlight_task = Some((
 7113                query_range.clone(),
 7114                self.update_selection_occurrence_highlights(
 7115                    query_text.clone(),
 7116                    query_range.clone(),
 7117                    multi_buffer_visible_range,
 7118                    false,
 7119                    window,
 7120                    cx,
 7121                ),
 7122            ));
 7123        }
 7124        if on_buffer_edit
 7125            || self
 7126                .debounced_selection_highlight_task
 7127                .as_ref()
 7128                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7129        {
 7130            let multi_buffer_start = multi_buffer_snapshot
 7131                .anchor_before(0)
 7132                .to_point(&multi_buffer_snapshot);
 7133            let multi_buffer_end = multi_buffer_snapshot
 7134                .anchor_after(multi_buffer_snapshot.len())
 7135                .to_point(&multi_buffer_snapshot);
 7136            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7137            self.debounced_selection_highlight_task = Some((
 7138                query_range.clone(),
 7139                self.update_selection_occurrence_highlights(
 7140                    query_text,
 7141                    query_range,
 7142                    multi_buffer_full_range,
 7143                    true,
 7144                    window,
 7145                    cx,
 7146                ),
 7147            ));
 7148        }
 7149    }
 7150
 7151    pub fn refresh_edit_prediction(
 7152        &mut self,
 7153        debounce: bool,
 7154        user_requested: bool,
 7155        window: &mut Window,
 7156        cx: &mut Context<Self>,
 7157    ) -> Option<()> {
 7158        if DisableAiSettings::get_global(cx).disable_ai {
 7159            return None;
 7160        }
 7161
 7162        let provider = self.edit_prediction_provider()?;
 7163        let cursor = self.selections.newest_anchor().head();
 7164        let (buffer, cursor_buffer_position) =
 7165            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7166
 7167        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7168            self.discard_edit_prediction(false, cx);
 7169            return None;
 7170        }
 7171
 7172        self.update_visible_edit_prediction(window, cx);
 7173
 7174        if !user_requested
 7175            && (!self.should_show_edit_predictions()
 7176                || !self.is_focused(window)
 7177                || buffer.read(cx).is_empty())
 7178        {
 7179            self.discard_edit_prediction(false, cx);
 7180            return None;
 7181        }
 7182
 7183        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7184        Some(())
 7185    }
 7186
 7187    fn show_edit_predictions_in_menu(&self) -> bool {
 7188        match self.edit_prediction_settings {
 7189            EditPredictionSettings::Disabled => false,
 7190            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7191        }
 7192    }
 7193
 7194    pub fn edit_predictions_enabled(&self) -> bool {
 7195        match self.edit_prediction_settings {
 7196            EditPredictionSettings::Disabled => false,
 7197            EditPredictionSettings::Enabled { .. } => true,
 7198        }
 7199    }
 7200
 7201    fn edit_prediction_requires_modifier(&self) -> bool {
 7202        match self.edit_prediction_settings {
 7203            EditPredictionSettings::Disabled => false,
 7204            EditPredictionSettings::Enabled {
 7205                preview_requires_modifier,
 7206                ..
 7207            } => preview_requires_modifier,
 7208        }
 7209    }
 7210
 7211    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7212        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7213            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7214            self.discard_edit_prediction(false, cx);
 7215        } else {
 7216            let selection = self.selections.newest_anchor();
 7217            let cursor = selection.head();
 7218
 7219            if let Some((buffer, cursor_buffer_position)) =
 7220                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7221            {
 7222                self.edit_prediction_settings =
 7223                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7224            }
 7225        }
 7226    }
 7227
 7228    fn edit_prediction_settings_at_position(
 7229        &self,
 7230        buffer: &Entity<Buffer>,
 7231        buffer_position: language::Anchor,
 7232        cx: &App,
 7233    ) -> EditPredictionSettings {
 7234        if !self.mode.is_full()
 7235            || !self.show_edit_predictions_override.unwrap_or(true)
 7236            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7237        {
 7238            return EditPredictionSettings::Disabled;
 7239        }
 7240
 7241        let buffer = buffer.read(cx);
 7242
 7243        let file = buffer.file();
 7244
 7245        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7246            return EditPredictionSettings::Disabled;
 7247        };
 7248
 7249        let by_provider = matches!(
 7250            self.menu_edit_predictions_policy,
 7251            MenuEditPredictionsPolicy::ByProvider
 7252        );
 7253
 7254        let show_in_menu = by_provider
 7255            && self
 7256                .edit_prediction_provider
 7257                .as_ref()
 7258                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7259
 7260        let preview_requires_modifier =
 7261            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7262
 7263        EditPredictionSettings::Enabled {
 7264            show_in_menu,
 7265            preview_requires_modifier,
 7266        }
 7267    }
 7268
 7269    fn should_show_edit_predictions(&self) -> bool {
 7270        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7271    }
 7272
 7273    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7274        matches!(
 7275            self.edit_prediction_preview,
 7276            EditPredictionPreview::Active { .. }
 7277        )
 7278    }
 7279
 7280    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7281        let cursor = self.selections.newest_anchor().head();
 7282        if let Some((buffer, cursor_position)) =
 7283            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7284        {
 7285            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7286        } else {
 7287            false
 7288        }
 7289    }
 7290
 7291    pub fn supports_minimap(&self, cx: &App) -> bool {
 7292        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7293    }
 7294
 7295    fn edit_predictions_enabled_in_buffer(
 7296        &self,
 7297        buffer: &Entity<Buffer>,
 7298        buffer_position: language::Anchor,
 7299        cx: &App,
 7300    ) -> bool {
 7301        maybe!({
 7302            if self.read_only(cx) {
 7303                return Some(false);
 7304            }
 7305            let provider = self.edit_prediction_provider()?;
 7306            if !provider.is_enabled(buffer, buffer_position, cx) {
 7307                return Some(false);
 7308            }
 7309            let buffer = buffer.read(cx);
 7310            let Some(file) = buffer.file() else {
 7311                return Some(true);
 7312            };
 7313            let settings = all_language_settings(Some(file), cx);
 7314            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7315        })
 7316        .unwrap_or(false)
 7317    }
 7318
 7319    fn cycle_edit_prediction(
 7320        &mut self,
 7321        direction: Direction,
 7322        window: &mut Window,
 7323        cx: &mut Context<Self>,
 7324    ) -> Option<()> {
 7325        let provider = self.edit_prediction_provider()?;
 7326        let cursor = self.selections.newest_anchor().head();
 7327        let (buffer, cursor_buffer_position) =
 7328            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7329        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7330            return None;
 7331        }
 7332
 7333        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7334        self.update_visible_edit_prediction(window, cx);
 7335
 7336        Some(())
 7337    }
 7338
 7339    pub fn show_edit_prediction(
 7340        &mut self,
 7341        _: &ShowEditPrediction,
 7342        window: &mut Window,
 7343        cx: &mut Context<Self>,
 7344    ) {
 7345        if !self.has_active_edit_prediction() {
 7346            self.refresh_edit_prediction(false, true, window, cx);
 7347            return;
 7348        }
 7349
 7350        self.update_visible_edit_prediction(window, cx);
 7351    }
 7352
 7353    pub fn display_cursor_names(
 7354        &mut self,
 7355        _: &DisplayCursorNames,
 7356        window: &mut Window,
 7357        cx: &mut Context<Self>,
 7358    ) {
 7359        self.show_cursor_names(window, cx);
 7360    }
 7361
 7362    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7363        self.show_cursor_names = true;
 7364        cx.notify();
 7365        cx.spawn_in(window, async move |this, cx| {
 7366            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7367            this.update(cx, |this, cx| {
 7368                this.show_cursor_names = false;
 7369                cx.notify()
 7370            })
 7371            .ok()
 7372        })
 7373        .detach();
 7374    }
 7375
 7376    pub fn next_edit_prediction(
 7377        &mut self,
 7378        _: &NextEditPrediction,
 7379        window: &mut Window,
 7380        cx: &mut Context<Self>,
 7381    ) {
 7382        if self.has_active_edit_prediction() {
 7383            self.cycle_edit_prediction(Direction::Next, window, cx);
 7384        } else {
 7385            let is_copilot_disabled = self
 7386                .refresh_edit_prediction(false, true, window, cx)
 7387                .is_none();
 7388            if is_copilot_disabled {
 7389                cx.propagate();
 7390            }
 7391        }
 7392    }
 7393
 7394    pub fn previous_edit_prediction(
 7395        &mut self,
 7396        _: &PreviousEditPrediction,
 7397        window: &mut Window,
 7398        cx: &mut Context<Self>,
 7399    ) {
 7400        if self.has_active_edit_prediction() {
 7401            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7402        } else {
 7403            let is_copilot_disabled = self
 7404                .refresh_edit_prediction(false, true, window, cx)
 7405                .is_none();
 7406            if is_copilot_disabled {
 7407                cx.propagate();
 7408            }
 7409        }
 7410    }
 7411
 7412    pub fn accept_edit_prediction(
 7413        &mut self,
 7414        _: &AcceptEditPrediction,
 7415        window: &mut Window,
 7416        cx: &mut Context<Self>,
 7417    ) {
 7418        if self.show_edit_predictions_in_menu() {
 7419            self.hide_context_menu(window, cx);
 7420        }
 7421
 7422        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7423            return;
 7424        };
 7425
 7426        match &active_edit_prediction.completion {
 7427            EditPrediction::MoveWithin { target, .. } => {
 7428                let target = *target;
 7429
 7430                if let Some(position_map) = &self.last_position_map {
 7431                    if position_map
 7432                        .visible_row_range
 7433                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7434                        || !self.edit_prediction_requires_modifier()
 7435                    {
 7436                        self.unfold_ranges(&[target..target], true, false, cx);
 7437                        // Note that this is also done in vim's handler of the Tab action.
 7438                        self.change_selections(
 7439                            SelectionEffects::scroll(Autoscroll::newest()),
 7440                            window,
 7441                            cx,
 7442                            |selections| {
 7443                                selections.select_anchor_ranges([target..target]);
 7444                            },
 7445                        );
 7446                        self.clear_row_highlights::<EditPredictionPreview>();
 7447
 7448                        self.edit_prediction_preview
 7449                            .set_previous_scroll_position(None);
 7450                    } else {
 7451                        self.edit_prediction_preview
 7452                            .set_previous_scroll_position(Some(
 7453                                position_map.snapshot.scroll_anchor,
 7454                            ));
 7455
 7456                        self.highlight_rows::<EditPredictionPreview>(
 7457                            target..target,
 7458                            cx.theme().colors().editor_highlighted_line_background,
 7459                            RowHighlightOptions {
 7460                                autoscroll: true,
 7461                                ..Default::default()
 7462                            },
 7463                            cx,
 7464                        );
 7465                        self.request_autoscroll(Autoscroll::fit(), cx);
 7466                    }
 7467                }
 7468            }
 7469            EditPrediction::MoveOutside { snapshot, target } => {
 7470                if let Some(workspace) = self.workspace() {
 7471                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7472                        .detach_and_log_err(cx);
 7473                }
 7474            }
 7475            EditPrediction::Edit { edits, .. } => {
 7476                self.report_edit_prediction_event(
 7477                    active_edit_prediction.completion_id.clone(),
 7478                    true,
 7479                    cx,
 7480                );
 7481
 7482                if let Some(provider) = self.edit_prediction_provider() {
 7483                    provider.accept(cx);
 7484                }
 7485
 7486                // Store the transaction ID and selections before applying the edit
 7487                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7488
 7489                let snapshot = self.buffer.read(cx).snapshot(cx);
 7490                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7491
 7492                self.buffer.update(cx, |buffer, cx| {
 7493                    buffer.edit(edits.iter().cloned(), None, cx)
 7494                });
 7495
 7496                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7497                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7498                });
 7499
 7500                let selections = self.selections.disjoint_anchors_arc();
 7501                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7502                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7503                    if has_new_transaction {
 7504                        self.selection_history
 7505                            .insert_transaction(transaction_id_now, selections);
 7506                    }
 7507                }
 7508
 7509                self.update_visible_edit_prediction(window, cx);
 7510                if self.active_edit_prediction.is_none() {
 7511                    self.refresh_edit_prediction(true, true, window, cx);
 7512                }
 7513
 7514                cx.notify();
 7515            }
 7516        }
 7517
 7518        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7519    }
 7520
 7521    pub fn accept_partial_edit_prediction(
 7522        &mut self,
 7523        _: &AcceptPartialEditPrediction,
 7524        window: &mut Window,
 7525        cx: &mut Context<Self>,
 7526    ) {
 7527        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7528            return;
 7529        };
 7530        if self.selections.count() != 1 {
 7531            return;
 7532        }
 7533
 7534        match &active_edit_prediction.completion {
 7535            EditPrediction::MoveWithin { target, .. } => {
 7536                let target = *target;
 7537                self.change_selections(
 7538                    SelectionEffects::scroll(Autoscroll::newest()),
 7539                    window,
 7540                    cx,
 7541                    |selections| {
 7542                        selections.select_anchor_ranges([target..target]);
 7543                    },
 7544                );
 7545            }
 7546            EditPrediction::MoveOutside { snapshot, target } => {
 7547                if let Some(workspace) = self.workspace() {
 7548                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7549                        .detach_and_log_err(cx);
 7550                }
 7551            }
 7552            EditPrediction::Edit { edits, .. } => {
 7553                self.report_edit_prediction_event(
 7554                    active_edit_prediction.completion_id.clone(),
 7555                    true,
 7556                    cx,
 7557                );
 7558
 7559                // Find an insertion that starts at the cursor position.
 7560                let snapshot = self.buffer.read(cx).snapshot(cx);
 7561                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7562                let insertion = edits.iter().find_map(|(range, text)| {
 7563                    let range = range.to_offset(&snapshot);
 7564                    if range.is_empty() && range.start == cursor_offset {
 7565                        Some(text)
 7566                    } else {
 7567                        None
 7568                    }
 7569                });
 7570
 7571                if let Some(text) = insertion {
 7572                    let mut partial_completion = text
 7573                        .chars()
 7574                        .by_ref()
 7575                        .take_while(|c| c.is_alphabetic())
 7576                        .collect::<String>();
 7577                    if partial_completion.is_empty() {
 7578                        partial_completion = text
 7579                            .chars()
 7580                            .by_ref()
 7581                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7582                            .collect::<String>();
 7583                    }
 7584
 7585                    cx.emit(EditorEvent::InputHandled {
 7586                        utf16_range_to_replace: None,
 7587                        text: partial_completion.clone().into(),
 7588                    });
 7589
 7590                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7591
 7592                    self.refresh_edit_prediction(true, true, window, cx);
 7593                    cx.notify();
 7594                } else {
 7595                    self.accept_edit_prediction(&Default::default(), window, cx);
 7596                }
 7597            }
 7598        }
 7599    }
 7600
 7601    fn discard_edit_prediction(
 7602        &mut self,
 7603        should_report_edit_prediction_event: bool,
 7604        cx: &mut Context<Self>,
 7605    ) -> bool {
 7606        if should_report_edit_prediction_event {
 7607            let completion_id = self
 7608                .active_edit_prediction
 7609                .as_ref()
 7610                .and_then(|active_completion| active_completion.completion_id.clone());
 7611
 7612            self.report_edit_prediction_event(completion_id, false, cx);
 7613        }
 7614
 7615        if let Some(provider) = self.edit_prediction_provider() {
 7616            provider.discard(cx);
 7617        }
 7618
 7619        self.take_active_edit_prediction(cx)
 7620    }
 7621
 7622    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7623        let Some(provider) = self.edit_prediction_provider() else {
 7624            return;
 7625        };
 7626
 7627        let Some((_, buffer, _)) = self
 7628            .buffer
 7629            .read(cx)
 7630            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7631        else {
 7632            return;
 7633        };
 7634
 7635        let extension = buffer
 7636            .read(cx)
 7637            .file()
 7638            .and_then(|file| Some(file.path().extension()?.to_string()));
 7639
 7640        let event_type = match accepted {
 7641            true => "Edit Prediction Accepted",
 7642            false => "Edit Prediction Discarded",
 7643        };
 7644        telemetry::event!(
 7645            event_type,
 7646            provider = provider.name(),
 7647            prediction_id = id,
 7648            suggestion_accepted = accepted,
 7649            file_extension = extension,
 7650        );
 7651    }
 7652
 7653    fn open_editor_at_anchor(
 7654        snapshot: &language::BufferSnapshot,
 7655        target: language::Anchor,
 7656        workspace: &Entity<Workspace>,
 7657        window: &mut Window,
 7658        cx: &mut App,
 7659    ) -> Task<Result<()>> {
 7660        workspace.update(cx, |workspace, cx| {
 7661            let path = snapshot.file().map(|file| file.full_path(cx));
 7662            let Some(path) =
 7663                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7664            else {
 7665                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7666            };
 7667            let target = text::ToPoint::to_point(&target, snapshot);
 7668            let item = workspace.open_path(path, None, true, window, cx);
 7669            window.spawn(cx, async move |cx| {
 7670                let Some(editor) = item.await?.downcast::<Editor>() else {
 7671                    return Ok(());
 7672                };
 7673                editor
 7674                    .update_in(cx, |editor, window, cx| {
 7675                        editor.go_to_singleton_buffer_point(target, window, cx);
 7676                    })
 7677                    .ok();
 7678                anyhow::Ok(())
 7679            })
 7680        })
 7681    }
 7682
 7683    pub fn has_active_edit_prediction(&self) -> bool {
 7684        self.active_edit_prediction.is_some()
 7685    }
 7686
 7687    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7688        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7689            return false;
 7690        };
 7691
 7692        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7693        self.clear_highlights::<EditPredictionHighlight>(cx);
 7694        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7695        true
 7696    }
 7697
 7698    /// Returns true when we're displaying the edit prediction popover below the cursor
 7699    /// like we are not previewing and the LSP autocomplete menu is visible
 7700    /// or we are in `when_holding_modifier` mode.
 7701    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7702        if self.edit_prediction_preview_is_active()
 7703            || !self.show_edit_predictions_in_menu()
 7704            || !self.edit_predictions_enabled()
 7705        {
 7706            return false;
 7707        }
 7708
 7709        if self.has_visible_completions_menu() {
 7710            return true;
 7711        }
 7712
 7713        has_completion && self.edit_prediction_requires_modifier()
 7714    }
 7715
 7716    fn handle_modifiers_changed(
 7717        &mut self,
 7718        modifiers: Modifiers,
 7719        position_map: &PositionMap,
 7720        window: &mut Window,
 7721        cx: &mut Context<Self>,
 7722    ) {
 7723        if self.show_edit_predictions_in_menu() {
 7724            self.update_edit_prediction_preview(&modifiers, window, cx);
 7725        }
 7726
 7727        self.update_selection_mode(&modifiers, position_map, window, cx);
 7728
 7729        let mouse_position = window.mouse_position();
 7730        if !position_map.text_hitbox.is_hovered(window) {
 7731            return;
 7732        }
 7733
 7734        self.update_hovered_link(
 7735            position_map.point_for_position(mouse_position),
 7736            &position_map.snapshot,
 7737            modifiers,
 7738            window,
 7739            cx,
 7740        )
 7741    }
 7742
 7743    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7744        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7745        if invert {
 7746            match multi_cursor_setting {
 7747                MultiCursorModifier::Alt => modifiers.alt,
 7748                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7749            }
 7750        } else {
 7751            match multi_cursor_setting {
 7752                MultiCursorModifier::Alt => modifiers.secondary(),
 7753                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7754            }
 7755        }
 7756    }
 7757
 7758    fn columnar_selection_mode(
 7759        modifiers: &Modifiers,
 7760        cx: &mut Context<Self>,
 7761    ) -> Option<ColumnarMode> {
 7762        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7763            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7764                Some(ColumnarMode::FromMouse)
 7765            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7766                Some(ColumnarMode::FromSelection)
 7767            } else {
 7768                None
 7769            }
 7770        } else {
 7771            None
 7772        }
 7773    }
 7774
 7775    fn update_selection_mode(
 7776        &mut self,
 7777        modifiers: &Modifiers,
 7778        position_map: &PositionMap,
 7779        window: &mut Window,
 7780        cx: &mut Context<Self>,
 7781    ) {
 7782        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7783            return;
 7784        };
 7785        if self.selections.pending_anchor().is_none() {
 7786            return;
 7787        }
 7788
 7789        let mouse_position = window.mouse_position();
 7790        let point_for_position = position_map.point_for_position(mouse_position);
 7791        let position = point_for_position.previous_valid;
 7792
 7793        self.select(
 7794            SelectPhase::BeginColumnar {
 7795                position,
 7796                reset: false,
 7797                mode,
 7798                goal_column: point_for_position.exact_unclipped.column(),
 7799            },
 7800            window,
 7801            cx,
 7802        );
 7803    }
 7804
 7805    fn update_edit_prediction_preview(
 7806        &mut self,
 7807        modifiers: &Modifiers,
 7808        window: &mut Window,
 7809        cx: &mut Context<Self>,
 7810    ) {
 7811        let mut modifiers_held = false;
 7812        if let Some(accept_keystroke) = self
 7813            .accept_edit_prediction_keybind(false, window, cx)
 7814            .keystroke()
 7815        {
 7816            modifiers_held = modifiers_held
 7817                || (accept_keystroke.modifiers() == modifiers
 7818                    && accept_keystroke.modifiers().modified());
 7819        };
 7820        if let Some(accept_partial_keystroke) = self
 7821            .accept_edit_prediction_keybind(true, window, cx)
 7822            .keystroke()
 7823        {
 7824            modifiers_held = modifiers_held
 7825                || (accept_partial_keystroke.modifiers() == modifiers
 7826                    && accept_partial_keystroke.modifiers().modified());
 7827        }
 7828
 7829        if modifiers_held {
 7830            if matches!(
 7831                self.edit_prediction_preview,
 7832                EditPredictionPreview::Inactive { .. }
 7833            ) {
 7834                self.edit_prediction_preview = EditPredictionPreview::Active {
 7835                    previous_scroll_position: None,
 7836                    since: Instant::now(),
 7837                };
 7838
 7839                self.update_visible_edit_prediction(window, cx);
 7840                cx.notify();
 7841            }
 7842        } else if let EditPredictionPreview::Active {
 7843            previous_scroll_position,
 7844            since,
 7845        } = self.edit_prediction_preview
 7846        {
 7847            if let (Some(previous_scroll_position), Some(position_map)) =
 7848                (previous_scroll_position, self.last_position_map.as_ref())
 7849            {
 7850                self.set_scroll_position(
 7851                    previous_scroll_position
 7852                        .scroll_position(&position_map.snapshot.display_snapshot),
 7853                    window,
 7854                    cx,
 7855                );
 7856            }
 7857
 7858            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7859                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7860            };
 7861            self.clear_row_highlights::<EditPredictionPreview>();
 7862            self.update_visible_edit_prediction(window, cx);
 7863            cx.notify();
 7864        }
 7865    }
 7866
 7867    fn update_visible_edit_prediction(
 7868        &mut self,
 7869        _window: &mut Window,
 7870        cx: &mut Context<Self>,
 7871    ) -> Option<()> {
 7872        if DisableAiSettings::get_global(cx).disable_ai {
 7873            return None;
 7874        }
 7875
 7876        if self.ime_transaction.is_some() {
 7877            self.discard_edit_prediction(false, cx);
 7878            return None;
 7879        }
 7880
 7881        let selection = self.selections.newest_anchor();
 7882        let cursor = selection.head();
 7883        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7884        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7885        let excerpt_id = cursor.excerpt_id;
 7886
 7887        let show_in_menu = self.show_edit_predictions_in_menu();
 7888        let completions_menu_has_precedence = !show_in_menu
 7889            && (self.context_menu.borrow().is_some()
 7890                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7891
 7892        if completions_menu_has_precedence
 7893            || !offset_selection.is_empty()
 7894            || self
 7895                .active_edit_prediction
 7896                .as_ref()
 7897                .is_some_and(|completion| {
 7898                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7899                        return false;
 7900                    };
 7901                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7902                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7903                    !invalidation_range.contains(&offset_selection.head())
 7904                })
 7905        {
 7906            self.discard_edit_prediction(false, cx);
 7907            return None;
 7908        }
 7909
 7910        self.take_active_edit_prediction(cx);
 7911        let Some(provider) = self.edit_prediction_provider() else {
 7912            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7913            return None;
 7914        };
 7915
 7916        let (buffer, cursor_buffer_position) =
 7917            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7918
 7919        self.edit_prediction_settings =
 7920            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7921
 7922        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7923
 7924        if self.edit_prediction_indent_conflict {
 7925            let cursor_point = cursor.to_point(&multibuffer);
 7926
 7927            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7928
 7929            if let Some((_, indent)) = indents.iter().next()
 7930                && indent.len == cursor_point.column
 7931            {
 7932                self.edit_prediction_indent_conflict = false;
 7933            }
 7934        }
 7935
 7936        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7937
 7938        let (completion_id, edits, edit_preview) = match edit_prediction {
 7939            edit_prediction::EditPrediction::Local {
 7940                id,
 7941                edits,
 7942                edit_preview,
 7943            } => (id, edits, edit_preview),
 7944            edit_prediction::EditPrediction::Jump {
 7945                id,
 7946                snapshot,
 7947                target,
 7948            } => {
 7949                self.stale_edit_prediction_in_menu = None;
 7950                self.active_edit_prediction = Some(EditPredictionState {
 7951                    inlay_ids: vec![],
 7952                    completion: EditPrediction::MoveOutside { snapshot, target },
 7953                    completion_id: id,
 7954                    invalidation_range: None,
 7955                });
 7956                cx.notify();
 7957                return Some(());
 7958            }
 7959        };
 7960
 7961        let edits = edits
 7962            .into_iter()
 7963            .flat_map(|(range, new_text)| {
 7964                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7965                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7966                Some((start..end, new_text))
 7967            })
 7968            .collect::<Vec<_>>();
 7969        if edits.is_empty() {
 7970            return None;
 7971        }
 7972
 7973        let first_edit_start = edits.first().unwrap().0.start;
 7974        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7975        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7976
 7977        let last_edit_end = edits.last().unwrap().0.end;
 7978        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7979        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7980
 7981        let cursor_row = cursor.to_point(&multibuffer).row;
 7982
 7983        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7984
 7985        let mut inlay_ids = Vec::new();
 7986        let invalidation_row_range;
 7987        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7988            Some(cursor_row..edit_end_row)
 7989        } else if cursor_row > edit_end_row {
 7990            Some(edit_start_row..cursor_row)
 7991        } else {
 7992            None
 7993        };
 7994        let supports_jump = self
 7995            .edit_prediction_provider
 7996            .as_ref()
 7997            .map(|provider| provider.provider.supports_jump_to_edit())
 7998            .unwrap_or(true);
 7999
 8000        let is_move = supports_jump
 8001            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8002        let completion = if is_move {
 8003            invalidation_row_range =
 8004                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8005            let target = first_edit_start;
 8006            EditPrediction::MoveWithin { target, snapshot }
 8007        } else {
 8008            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8009                && !self.edit_predictions_hidden_for_vim_mode;
 8010
 8011            if show_completions_in_buffer {
 8012                if edits
 8013                    .iter()
 8014                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8015                {
 8016                    let mut inlays = Vec::new();
 8017                    for (range, new_text) in &edits {
 8018                        let inlay = Inlay::edit_prediction(
 8019                            post_inc(&mut self.next_inlay_id),
 8020                            range.start,
 8021                            new_text.as_str(),
 8022                        );
 8023                        inlay_ids.push(inlay.id);
 8024                        inlays.push(inlay);
 8025                    }
 8026
 8027                    self.splice_inlays(&[], inlays, cx);
 8028                } else {
 8029                    let background_color = cx.theme().status().deleted_background;
 8030                    self.highlight_text::<EditPredictionHighlight>(
 8031                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8032                        HighlightStyle {
 8033                            background_color: Some(background_color),
 8034                            ..Default::default()
 8035                        },
 8036                        cx,
 8037                    );
 8038                }
 8039            }
 8040
 8041            invalidation_row_range = edit_start_row..edit_end_row;
 8042
 8043            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8044                if provider.show_tab_accept_marker() {
 8045                    EditDisplayMode::TabAccept
 8046                } else {
 8047                    EditDisplayMode::Inline
 8048                }
 8049            } else {
 8050                EditDisplayMode::DiffPopover
 8051            };
 8052
 8053            EditPrediction::Edit {
 8054                edits,
 8055                edit_preview,
 8056                display_mode,
 8057                snapshot,
 8058            }
 8059        };
 8060
 8061        let invalidation_range = multibuffer
 8062            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8063            ..multibuffer.anchor_after(Point::new(
 8064                invalidation_row_range.end,
 8065                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8066            ));
 8067
 8068        self.stale_edit_prediction_in_menu = None;
 8069        self.active_edit_prediction = Some(EditPredictionState {
 8070            inlay_ids,
 8071            completion,
 8072            completion_id,
 8073            invalidation_range: Some(invalidation_range),
 8074        });
 8075
 8076        cx.notify();
 8077
 8078        Some(())
 8079    }
 8080
 8081    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8082        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8083    }
 8084
 8085    fn clear_tasks(&mut self) {
 8086        self.tasks.clear()
 8087    }
 8088
 8089    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8090        if self.tasks.insert(key, value).is_some() {
 8091            // This case should hopefully be rare, but just in case...
 8092            log::error!(
 8093                "multiple different run targets found on a single line, only the last target will be rendered"
 8094            )
 8095        }
 8096    }
 8097
 8098    /// Get all display points of breakpoints that will be rendered within editor
 8099    ///
 8100    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8101    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8102    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8103    fn active_breakpoints(
 8104        &self,
 8105        range: Range<DisplayRow>,
 8106        window: &mut Window,
 8107        cx: &mut Context<Self>,
 8108    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8109        let mut breakpoint_display_points = HashMap::default();
 8110
 8111        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8112            return breakpoint_display_points;
 8113        };
 8114
 8115        let snapshot = self.snapshot(window, cx);
 8116
 8117        let multi_buffer_snapshot = snapshot.display_snapshot.buffer_snapshot();
 8118        let Some(project) = self.project() else {
 8119            return breakpoint_display_points;
 8120        };
 8121
 8122        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8123            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8124
 8125        for (buffer_snapshot, range, excerpt_id) in
 8126            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8127        {
 8128            let Some(buffer) = project
 8129                .read(cx)
 8130                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8131            else {
 8132                continue;
 8133            };
 8134            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8135                &buffer,
 8136                Some(
 8137                    buffer_snapshot.anchor_before(range.start)
 8138                        ..buffer_snapshot.anchor_after(range.end),
 8139                ),
 8140                buffer_snapshot,
 8141                cx,
 8142            );
 8143            for (breakpoint, state) in breakpoints {
 8144                let multi_buffer_anchor =
 8145                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8146                let position = multi_buffer_anchor
 8147                    .to_point(multi_buffer_snapshot)
 8148                    .to_display_point(&snapshot);
 8149
 8150                breakpoint_display_points.insert(
 8151                    position.row(),
 8152                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8153                );
 8154            }
 8155        }
 8156
 8157        breakpoint_display_points
 8158    }
 8159
 8160    fn breakpoint_context_menu(
 8161        &self,
 8162        anchor: Anchor,
 8163        window: &mut Window,
 8164        cx: &mut Context<Self>,
 8165    ) -> Entity<ui::ContextMenu> {
 8166        let weak_editor = cx.weak_entity();
 8167        let focus_handle = self.focus_handle(cx);
 8168
 8169        let row = self
 8170            .buffer
 8171            .read(cx)
 8172            .snapshot(cx)
 8173            .summary_for_anchor::<Point>(&anchor)
 8174            .row;
 8175
 8176        let breakpoint = self
 8177            .breakpoint_at_row(row, window, cx)
 8178            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8179
 8180        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8181            "Edit Log Breakpoint"
 8182        } else {
 8183            "Set Log Breakpoint"
 8184        };
 8185
 8186        let condition_breakpoint_msg = if breakpoint
 8187            .as_ref()
 8188            .is_some_and(|bp| bp.1.condition.is_some())
 8189        {
 8190            "Edit Condition Breakpoint"
 8191        } else {
 8192            "Set Condition Breakpoint"
 8193        };
 8194
 8195        let hit_condition_breakpoint_msg = if breakpoint
 8196            .as_ref()
 8197            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8198        {
 8199            "Edit Hit Condition Breakpoint"
 8200        } else {
 8201            "Set Hit Condition Breakpoint"
 8202        };
 8203
 8204        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8205            "Unset Breakpoint"
 8206        } else {
 8207            "Set Breakpoint"
 8208        };
 8209
 8210        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8211
 8212        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8213            BreakpointState::Enabled => Some("Disable"),
 8214            BreakpointState::Disabled => Some("Enable"),
 8215        });
 8216
 8217        let (anchor, breakpoint) =
 8218            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8219
 8220        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8221            menu.on_blur_subscription(Subscription::new(|| {}))
 8222                .context(focus_handle)
 8223                .when(run_to_cursor, |this| {
 8224                    let weak_editor = weak_editor.clone();
 8225                    this.entry("Run to cursor", None, move |window, cx| {
 8226                        weak_editor
 8227                            .update(cx, |editor, cx| {
 8228                                editor.change_selections(
 8229                                    SelectionEffects::no_scroll(),
 8230                                    window,
 8231                                    cx,
 8232                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8233                                );
 8234                            })
 8235                            .ok();
 8236
 8237                        window.dispatch_action(Box::new(RunToCursor), cx);
 8238                    })
 8239                    .separator()
 8240                })
 8241                .when_some(toggle_state_msg, |this, msg| {
 8242                    this.entry(msg, None, {
 8243                        let weak_editor = weak_editor.clone();
 8244                        let breakpoint = breakpoint.clone();
 8245                        move |_window, cx| {
 8246                            weak_editor
 8247                                .update(cx, |this, cx| {
 8248                                    this.edit_breakpoint_at_anchor(
 8249                                        anchor,
 8250                                        breakpoint.as_ref().clone(),
 8251                                        BreakpointEditAction::InvertState,
 8252                                        cx,
 8253                                    );
 8254                                })
 8255                                .log_err();
 8256                        }
 8257                    })
 8258                })
 8259                .entry(set_breakpoint_msg, None, {
 8260                    let weak_editor = weak_editor.clone();
 8261                    let breakpoint = breakpoint.clone();
 8262                    move |_window, cx| {
 8263                        weak_editor
 8264                            .update(cx, |this, cx| {
 8265                                this.edit_breakpoint_at_anchor(
 8266                                    anchor,
 8267                                    breakpoint.as_ref().clone(),
 8268                                    BreakpointEditAction::Toggle,
 8269                                    cx,
 8270                                );
 8271                            })
 8272                            .log_err();
 8273                    }
 8274                })
 8275                .entry(log_breakpoint_msg, None, {
 8276                    let breakpoint = breakpoint.clone();
 8277                    let weak_editor = weak_editor.clone();
 8278                    move |window, cx| {
 8279                        weak_editor
 8280                            .update(cx, |this, cx| {
 8281                                this.add_edit_breakpoint_block(
 8282                                    anchor,
 8283                                    breakpoint.as_ref(),
 8284                                    BreakpointPromptEditAction::Log,
 8285                                    window,
 8286                                    cx,
 8287                                );
 8288                            })
 8289                            .log_err();
 8290                    }
 8291                })
 8292                .entry(condition_breakpoint_msg, None, {
 8293                    let breakpoint = breakpoint.clone();
 8294                    let weak_editor = weak_editor.clone();
 8295                    move |window, cx| {
 8296                        weak_editor
 8297                            .update(cx, |this, cx| {
 8298                                this.add_edit_breakpoint_block(
 8299                                    anchor,
 8300                                    breakpoint.as_ref(),
 8301                                    BreakpointPromptEditAction::Condition,
 8302                                    window,
 8303                                    cx,
 8304                                );
 8305                            })
 8306                            .log_err();
 8307                    }
 8308                })
 8309                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8310                    weak_editor
 8311                        .update(cx, |this, cx| {
 8312                            this.add_edit_breakpoint_block(
 8313                                anchor,
 8314                                breakpoint.as_ref(),
 8315                                BreakpointPromptEditAction::HitCondition,
 8316                                window,
 8317                                cx,
 8318                            );
 8319                        })
 8320                        .log_err();
 8321                })
 8322        })
 8323    }
 8324
 8325    fn render_breakpoint(
 8326        &self,
 8327        position: Anchor,
 8328        row: DisplayRow,
 8329        breakpoint: &Breakpoint,
 8330        state: Option<BreakpointSessionState>,
 8331        cx: &mut Context<Self>,
 8332    ) -> IconButton {
 8333        let is_rejected = state.is_some_and(|s| !s.verified);
 8334        // Is it a breakpoint that shows up when hovering over gutter?
 8335        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8336            (false, false),
 8337            |PhantomBreakpointIndicator {
 8338                 is_active,
 8339                 display_row,
 8340                 collides_with_existing_breakpoint,
 8341             }| {
 8342                (
 8343                    is_active && display_row == row,
 8344                    collides_with_existing_breakpoint,
 8345                )
 8346            },
 8347        );
 8348
 8349        let (color, icon) = {
 8350            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8351                (false, false) => ui::IconName::DebugBreakpoint,
 8352                (true, false) => ui::IconName::DebugLogBreakpoint,
 8353                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8354                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8355            };
 8356
 8357            let color = if is_phantom {
 8358                Color::Hint
 8359            } else if is_rejected {
 8360                Color::Disabled
 8361            } else {
 8362                Color::Debugger
 8363            };
 8364
 8365            (color, icon)
 8366        };
 8367
 8368        let breakpoint = Arc::from(breakpoint.clone());
 8369
 8370        let alt_as_text = gpui::Keystroke {
 8371            modifiers: Modifiers::secondary_key(),
 8372            ..Default::default()
 8373        };
 8374        let primary_action_text = if breakpoint.is_disabled() {
 8375            "Enable breakpoint"
 8376        } else if is_phantom && !collides_with_existing {
 8377            "Set breakpoint"
 8378        } else {
 8379            "Unset breakpoint"
 8380        };
 8381        let focus_handle = self.focus_handle.clone();
 8382
 8383        let meta = if is_rejected {
 8384            SharedString::from("No executable code is associated with this line.")
 8385        } else if collides_with_existing && !breakpoint.is_disabled() {
 8386            SharedString::from(format!(
 8387                "{alt_as_text}-click to disable,\nright-click for more options."
 8388            ))
 8389        } else {
 8390            SharedString::from("Right-click for more options.")
 8391        };
 8392        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8393            .icon_size(IconSize::XSmall)
 8394            .size(ui::ButtonSize::None)
 8395            .when(is_rejected, |this| {
 8396                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8397            })
 8398            .icon_color(color)
 8399            .style(ButtonStyle::Transparent)
 8400            .on_click(cx.listener({
 8401                move |editor, event: &ClickEvent, window, cx| {
 8402                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8403                        BreakpointEditAction::InvertState
 8404                    } else {
 8405                        BreakpointEditAction::Toggle
 8406                    };
 8407
 8408                    window.focus(&editor.focus_handle(cx));
 8409                    editor.edit_breakpoint_at_anchor(
 8410                        position,
 8411                        breakpoint.as_ref().clone(),
 8412                        edit_action,
 8413                        cx,
 8414                    );
 8415                }
 8416            }))
 8417            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8418                editor.set_breakpoint_context_menu(
 8419                    row,
 8420                    Some(position),
 8421                    event.position(),
 8422                    window,
 8423                    cx,
 8424                );
 8425            }))
 8426            .tooltip(move |window, cx| {
 8427                Tooltip::with_meta_in(
 8428                    primary_action_text,
 8429                    Some(&ToggleBreakpoint),
 8430                    meta.clone(),
 8431                    &focus_handle,
 8432                    window,
 8433                    cx,
 8434                )
 8435            })
 8436    }
 8437
 8438    fn build_tasks_context(
 8439        project: &Entity<Project>,
 8440        buffer: &Entity<Buffer>,
 8441        buffer_row: u32,
 8442        tasks: &Arc<RunnableTasks>,
 8443        cx: &mut Context<Self>,
 8444    ) -> Task<Option<task::TaskContext>> {
 8445        let position = Point::new(buffer_row, tasks.column);
 8446        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8447        let location = Location {
 8448            buffer: buffer.clone(),
 8449            range: range_start..range_start,
 8450        };
 8451        // Fill in the environmental variables from the tree-sitter captures
 8452        let mut captured_task_variables = TaskVariables::default();
 8453        for (capture_name, value) in tasks.extra_variables.clone() {
 8454            captured_task_variables.insert(
 8455                task::VariableName::Custom(capture_name.into()),
 8456                value.clone(),
 8457            );
 8458        }
 8459        project.update(cx, |project, cx| {
 8460            project.task_store().update(cx, |task_store, cx| {
 8461                task_store.task_context_for_location(captured_task_variables, location, cx)
 8462            })
 8463        })
 8464    }
 8465
 8466    pub fn spawn_nearest_task(
 8467        &mut self,
 8468        action: &SpawnNearestTask,
 8469        window: &mut Window,
 8470        cx: &mut Context<Self>,
 8471    ) {
 8472        let Some((workspace, _)) = self.workspace.clone() else {
 8473            return;
 8474        };
 8475        let Some(project) = self.project.clone() else {
 8476            return;
 8477        };
 8478
 8479        // Try to find a closest, enclosing node using tree-sitter that has a task
 8480        let Some((buffer, buffer_row, tasks)) = self
 8481            .find_enclosing_node_task(cx)
 8482            // Or find the task that's closest in row-distance.
 8483            .or_else(|| self.find_closest_task(cx))
 8484        else {
 8485            return;
 8486        };
 8487
 8488        let reveal_strategy = action.reveal;
 8489        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8490        cx.spawn_in(window, async move |_, cx| {
 8491            let context = task_context.await?;
 8492            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8493
 8494            let resolved = &mut resolved_task.resolved;
 8495            resolved.reveal = reveal_strategy;
 8496
 8497            workspace
 8498                .update_in(cx, |workspace, window, cx| {
 8499                    workspace.schedule_resolved_task(
 8500                        task_source_kind,
 8501                        resolved_task,
 8502                        false,
 8503                        window,
 8504                        cx,
 8505                    );
 8506                })
 8507                .ok()
 8508        })
 8509        .detach();
 8510    }
 8511
 8512    fn find_closest_task(
 8513        &mut self,
 8514        cx: &mut Context<Self>,
 8515    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8516        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8517
 8518        let ((buffer_id, row), tasks) = self
 8519            .tasks
 8520            .iter()
 8521            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8522
 8523        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8524        let tasks = Arc::new(tasks.to_owned());
 8525        Some((buffer, *row, tasks))
 8526    }
 8527
 8528    fn find_enclosing_node_task(
 8529        &mut self,
 8530        cx: &mut Context<Self>,
 8531    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8532        let snapshot = self.buffer.read(cx).snapshot(cx);
 8533        let offset = self.selections.newest::<usize>(cx).head();
 8534        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8535        let buffer_id = excerpt.buffer().remote_id();
 8536
 8537        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8538        let mut cursor = layer.node().walk();
 8539
 8540        while cursor.goto_first_child_for_byte(offset).is_some() {
 8541            if cursor.node().end_byte() == offset {
 8542                cursor.goto_next_sibling();
 8543            }
 8544        }
 8545
 8546        // Ascend to the smallest ancestor that contains the range and has a task.
 8547        loop {
 8548            let node = cursor.node();
 8549            let node_range = node.byte_range();
 8550            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8551
 8552            // Check if this node contains our offset
 8553            if node_range.start <= offset && node_range.end >= offset {
 8554                // If it contains offset, check for task
 8555                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8556                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8557                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8558                }
 8559            }
 8560
 8561            if !cursor.goto_parent() {
 8562                break;
 8563            }
 8564        }
 8565        None
 8566    }
 8567
 8568    fn render_run_indicator(
 8569        &self,
 8570        _style: &EditorStyle,
 8571        is_active: bool,
 8572        row: DisplayRow,
 8573        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8574        cx: &mut Context<Self>,
 8575    ) -> IconButton {
 8576        let color = Color::Muted;
 8577        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8578
 8579        IconButton::new(
 8580            ("run_indicator", row.0 as usize),
 8581            ui::IconName::PlayOutlined,
 8582        )
 8583        .shape(ui::IconButtonShape::Square)
 8584        .icon_size(IconSize::XSmall)
 8585        .icon_color(color)
 8586        .toggle_state(is_active)
 8587        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8588            let quick_launch = match e {
 8589                ClickEvent::Keyboard(_) => true,
 8590                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8591            };
 8592
 8593            window.focus(&editor.focus_handle(cx));
 8594            editor.toggle_code_actions(
 8595                &ToggleCodeActions {
 8596                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8597                    quick_launch,
 8598                },
 8599                window,
 8600                cx,
 8601            );
 8602        }))
 8603        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8604            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8605        }))
 8606    }
 8607
 8608    pub fn context_menu_visible(&self) -> bool {
 8609        !self.edit_prediction_preview_is_active()
 8610            && self
 8611                .context_menu
 8612                .borrow()
 8613                .as_ref()
 8614                .is_some_and(|menu| menu.visible())
 8615    }
 8616
 8617    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8618        self.context_menu
 8619            .borrow()
 8620            .as_ref()
 8621            .map(|menu| menu.origin())
 8622    }
 8623
 8624    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8625        self.context_menu_options = Some(options);
 8626    }
 8627
 8628    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8629    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8630
 8631    fn render_edit_prediction_popover(
 8632        &mut self,
 8633        text_bounds: &Bounds<Pixels>,
 8634        content_origin: gpui::Point<Pixels>,
 8635        right_margin: Pixels,
 8636        editor_snapshot: &EditorSnapshot,
 8637        visible_row_range: Range<DisplayRow>,
 8638        scroll_top: ScrollOffset,
 8639        scroll_bottom: ScrollOffset,
 8640        line_layouts: &[LineWithInvisibles],
 8641        line_height: Pixels,
 8642        scroll_position: gpui::Point<ScrollOffset>,
 8643        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8644        newest_selection_head: Option<DisplayPoint>,
 8645        editor_width: Pixels,
 8646        style: &EditorStyle,
 8647        window: &mut Window,
 8648        cx: &mut App,
 8649    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8650        if self.mode().is_minimap() {
 8651            return None;
 8652        }
 8653        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8654
 8655        if self.edit_prediction_visible_in_cursor_popover(true) {
 8656            return None;
 8657        }
 8658
 8659        match &active_edit_prediction.completion {
 8660            EditPrediction::MoveWithin { target, .. } => {
 8661                let target_display_point = target.to_display_point(editor_snapshot);
 8662
 8663                if self.edit_prediction_requires_modifier() {
 8664                    if !self.edit_prediction_preview_is_active() {
 8665                        return None;
 8666                    }
 8667
 8668                    self.render_edit_prediction_modifier_jump_popover(
 8669                        text_bounds,
 8670                        content_origin,
 8671                        visible_row_range,
 8672                        line_layouts,
 8673                        line_height,
 8674                        scroll_pixel_position,
 8675                        newest_selection_head,
 8676                        target_display_point,
 8677                        window,
 8678                        cx,
 8679                    )
 8680                } else {
 8681                    self.render_edit_prediction_eager_jump_popover(
 8682                        text_bounds,
 8683                        content_origin,
 8684                        editor_snapshot,
 8685                        visible_row_range,
 8686                        scroll_top,
 8687                        scroll_bottom,
 8688                        line_height,
 8689                        scroll_pixel_position,
 8690                        target_display_point,
 8691                        editor_width,
 8692                        window,
 8693                        cx,
 8694                    )
 8695                }
 8696            }
 8697            EditPrediction::Edit {
 8698                display_mode: EditDisplayMode::Inline,
 8699                ..
 8700            } => None,
 8701            EditPrediction::Edit {
 8702                display_mode: EditDisplayMode::TabAccept,
 8703                edits,
 8704                ..
 8705            } => {
 8706                let range = &edits.first()?.0;
 8707                let target_display_point = range.end.to_display_point(editor_snapshot);
 8708
 8709                self.render_edit_prediction_end_of_line_popover(
 8710                    "Accept",
 8711                    editor_snapshot,
 8712                    visible_row_range,
 8713                    target_display_point,
 8714                    line_height,
 8715                    scroll_pixel_position,
 8716                    content_origin,
 8717                    editor_width,
 8718                    window,
 8719                    cx,
 8720                )
 8721            }
 8722            EditPrediction::Edit {
 8723                edits,
 8724                edit_preview,
 8725                display_mode: EditDisplayMode::DiffPopover,
 8726                snapshot,
 8727            } => self.render_edit_prediction_diff_popover(
 8728                text_bounds,
 8729                content_origin,
 8730                right_margin,
 8731                editor_snapshot,
 8732                visible_row_range,
 8733                line_layouts,
 8734                line_height,
 8735                scroll_position,
 8736                scroll_pixel_position,
 8737                newest_selection_head,
 8738                editor_width,
 8739                style,
 8740                edits,
 8741                edit_preview,
 8742                snapshot,
 8743                window,
 8744                cx,
 8745            ),
 8746            EditPrediction::MoveOutside { snapshot, .. } => {
 8747                let file_name = snapshot
 8748                    .file()
 8749                    .map(|file| file.file_name(cx))
 8750                    .unwrap_or("untitled");
 8751                let mut element = self
 8752                    .render_edit_prediction_line_popover(
 8753                        format!("Jump to {file_name}"),
 8754                        Some(IconName::ZedPredict),
 8755                        window,
 8756                        cx,
 8757                    )
 8758                    .into_any();
 8759
 8760                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8761                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8762                let origin_y = text_bounds.size.height - size.height - px(30.);
 8763                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8764                element.prepaint_at(origin, window, cx);
 8765
 8766                Some((element, origin))
 8767            }
 8768        }
 8769    }
 8770
 8771    fn render_edit_prediction_modifier_jump_popover(
 8772        &mut self,
 8773        text_bounds: &Bounds<Pixels>,
 8774        content_origin: gpui::Point<Pixels>,
 8775        visible_row_range: Range<DisplayRow>,
 8776        line_layouts: &[LineWithInvisibles],
 8777        line_height: Pixels,
 8778        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8779        newest_selection_head: Option<DisplayPoint>,
 8780        target_display_point: DisplayPoint,
 8781        window: &mut Window,
 8782        cx: &mut App,
 8783    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8784        let scrolled_content_origin =
 8785            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8786
 8787        const SCROLL_PADDING_Y: Pixels = px(12.);
 8788
 8789        if target_display_point.row() < visible_row_range.start {
 8790            return self.render_edit_prediction_scroll_popover(
 8791                |_| SCROLL_PADDING_Y,
 8792                IconName::ArrowUp,
 8793                visible_row_range,
 8794                line_layouts,
 8795                newest_selection_head,
 8796                scrolled_content_origin,
 8797                window,
 8798                cx,
 8799            );
 8800        } else if target_display_point.row() >= visible_row_range.end {
 8801            return self.render_edit_prediction_scroll_popover(
 8802                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8803                IconName::ArrowDown,
 8804                visible_row_range,
 8805                line_layouts,
 8806                newest_selection_head,
 8807                scrolled_content_origin,
 8808                window,
 8809                cx,
 8810            );
 8811        }
 8812
 8813        const POLE_WIDTH: Pixels = px(2.);
 8814
 8815        let line_layout =
 8816            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8817        let target_column = target_display_point.column() as usize;
 8818
 8819        let target_x = line_layout.x_for_index(target_column);
 8820        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8821            - scroll_pixel_position.y;
 8822
 8823        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8824
 8825        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8826        border_color.l += 0.001;
 8827
 8828        let mut element = v_flex()
 8829            .items_end()
 8830            .when(flag_on_right, |el| el.items_start())
 8831            .child(if flag_on_right {
 8832                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8833                    .rounded_bl(px(0.))
 8834                    .rounded_tl(px(0.))
 8835                    .border_l_2()
 8836                    .border_color(border_color)
 8837            } else {
 8838                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8839                    .rounded_br(px(0.))
 8840                    .rounded_tr(px(0.))
 8841                    .border_r_2()
 8842                    .border_color(border_color)
 8843            })
 8844            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8845            .into_any();
 8846
 8847        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8848
 8849        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8850            - point(
 8851                if flag_on_right {
 8852                    POLE_WIDTH
 8853                } else {
 8854                    size.width - POLE_WIDTH
 8855                },
 8856                size.height - line_height,
 8857            );
 8858
 8859        origin.x = origin.x.max(content_origin.x);
 8860
 8861        element.prepaint_at(origin, window, cx);
 8862
 8863        Some((element, origin))
 8864    }
 8865
 8866    fn render_edit_prediction_scroll_popover(
 8867        &mut self,
 8868        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8869        scroll_icon: IconName,
 8870        visible_row_range: Range<DisplayRow>,
 8871        line_layouts: &[LineWithInvisibles],
 8872        newest_selection_head: Option<DisplayPoint>,
 8873        scrolled_content_origin: gpui::Point<Pixels>,
 8874        window: &mut Window,
 8875        cx: &mut App,
 8876    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8877        let mut element = self
 8878            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8879            .into_any();
 8880
 8881        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8882
 8883        let cursor = newest_selection_head?;
 8884        let cursor_row_layout =
 8885            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8886        let cursor_column = cursor.column() as usize;
 8887
 8888        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8889
 8890        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8891
 8892        element.prepaint_at(origin, window, cx);
 8893        Some((element, origin))
 8894    }
 8895
 8896    fn render_edit_prediction_eager_jump_popover(
 8897        &mut self,
 8898        text_bounds: &Bounds<Pixels>,
 8899        content_origin: gpui::Point<Pixels>,
 8900        editor_snapshot: &EditorSnapshot,
 8901        visible_row_range: Range<DisplayRow>,
 8902        scroll_top: ScrollOffset,
 8903        scroll_bottom: ScrollOffset,
 8904        line_height: Pixels,
 8905        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8906        target_display_point: DisplayPoint,
 8907        editor_width: Pixels,
 8908        window: &mut Window,
 8909        cx: &mut App,
 8910    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8911        if target_display_point.row().as_f64() < scroll_top {
 8912            let mut element = self
 8913                .render_edit_prediction_line_popover(
 8914                    "Jump to Edit",
 8915                    Some(IconName::ArrowUp),
 8916                    window,
 8917                    cx,
 8918                )
 8919                .into_any();
 8920
 8921            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8922            let offset = point(
 8923                (text_bounds.size.width - size.width) / 2.,
 8924                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8925            );
 8926
 8927            let origin = text_bounds.origin + offset;
 8928            element.prepaint_at(origin, window, cx);
 8929            Some((element, origin))
 8930        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8931            let mut element = self
 8932                .render_edit_prediction_line_popover(
 8933                    "Jump to Edit",
 8934                    Some(IconName::ArrowDown),
 8935                    window,
 8936                    cx,
 8937                )
 8938                .into_any();
 8939
 8940            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8941            let offset = point(
 8942                (text_bounds.size.width - size.width) / 2.,
 8943                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8944            );
 8945
 8946            let origin = text_bounds.origin + offset;
 8947            element.prepaint_at(origin, window, cx);
 8948            Some((element, origin))
 8949        } else {
 8950            self.render_edit_prediction_end_of_line_popover(
 8951                "Jump to Edit",
 8952                editor_snapshot,
 8953                visible_row_range,
 8954                target_display_point,
 8955                line_height,
 8956                scroll_pixel_position,
 8957                content_origin,
 8958                editor_width,
 8959                window,
 8960                cx,
 8961            )
 8962        }
 8963    }
 8964
 8965    fn render_edit_prediction_end_of_line_popover(
 8966        self: &mut Editor,
 8967        label: &'static str,
 8968        editor_snapshot: &EditorSnapshot,
 8969        visible_row_range: Range<DisplayRow>,
 8970        target_display_point: DisplayPoint,
 8971        line_height: Pixels,
 8972        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8973        content_origin: gpui::Point<Pixels>,
 8974        editor_width: Pixels,
 8975        window: &mut Window,
 8976        cx: &mut App,
 8977    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8978        let target_line_end = DisplayPoint::new(
 8979            target_display_point.row(),
 8980            editor_snapshot.line_len(target_display_point.row()),
 8981        );
 8982
 8983        let mut element = self
 8984            .render_edit_prediction_line_popover(label, None, window, cx)
 8985            .into_any();
 8986
 8987        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8988
 8989        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8990
 8991        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8992        let mut origin = start_point
 8993            + line_origin
 8994            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8995        origin.x = origin.x.max(content_origin.x);
 8996
 8997        let max_x = content_origin.x + editor_width - size.width;
 8998
 8999        if origin.x > max_x {
 9000            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9001
 9002            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9003                origin.y += offset;
 9004                IconName::ArrowUp
 9005            } else {
 9006                origin.y -= offset;
 9007                IconName::ArrowDown
 9008            };
 9009
 9010            element = self
 9011                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9012                .into_any();
 9013
 9014            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9015
 9016            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9017        }
 9018
 9019        element.prepaint_at(origin, window, cx);
 9020        Some((element, origin))
 9021    }
 9022
 9023    fn render_edit_prediction_diff_popover(
 9024        self: &Editor,
 9025        text_bounds: &Bounds<Pixels>,
 9026        content_origin: gpui::Point<Pixels>,
 9027        right_margin: Pixels,
 9028        editor_snapshot: &EditorSnapshot,
 9029        visible_row_range: Range<DisplayRow>,
 9030        line_layouts: &[LineWithInvisibles],
 9031        line_height: Pixels,
 9032        scroll_position: gpui::Point<ScrollOffset>,
 9033        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9034        newest_selection_head: Option<DisplayPoint>,
 9035        editor_width: Pixels,
 9036        style: &EditorStyle,
 9037        edits: &Vec<(Range<Anchor>, String)>,
 9038        edit_preview: &Option<language::EditPreview>,
 9039        snapshot: &language::BufferSnapshot,
 9040        window: &mut Window,
 9041        cx: &mut App,
 9042    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9043        let edit_start = edits
 9044            .first()
 9045            .unwrap()
 9046            .0
 9047            .start
 9048            .to_display_point(editor_snapshot);
 9049        let edit_end = edits
 9050            .last()
 9051            .unwrap()
 9052            .0
 9053            .end
 9054            .to_display_point(editor_snapshot);
 9055
 9056        let is_visible = visible_row_range.contains(&edit_start.row())
 9057            || visible_row_range.contains(&edit_end.row());
 9058        if !is_visible {
 9059            return None;
 9060        }
 9061
 9062        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9063            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9064        } else {
 9065            // Fallback for providers without edit_preview
 9066            crate::edit_prediction_fallback_text(edits, cx)
 9067        };
 9068
 9069        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9070        let line_count = highlighted_edits.text.lines().count();
 9071
 9072        const BORDER_WIDTH: Pixels = px(1.);
 9073
 9074        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9075        let has_keybind = keybind.is_some();
 9076
 9077        let mut element = h_flex()
 9078            .items_start()
 9079            .child(
 9080                h_flex()
 9081                    .bg(cx.theme().colors().editor_background)
 9082                    .border(BORDER_WIDTH)
 9083                    .shadow_xs()
 9084                    .border_color(cx.theme().colors().border)
 9085                    .rounded_l_lg()
 9086                    .when(line_count > 1, |el| el.rounded_br_lg())
 9087                    .pr_1()
 9088                    .child(styled_text),
 9089            )
 9090            .child(
 9091                h_flex()
 9092                    .h(line_height + BORDER_WIDTH * 2.)
 9093                    .px_1p5()
 9094                    .gap_1()
 9095                    // Workaround: For some reason, there's a gap if we don't do this
 9096                    .ml(-BORDER_WIDTH)
 9097                    .shadow(vec![gpui::BoxShadow {
 9098                        color: gpui::black().opacity(0.05),
 9099                        offset: point(px(1.), px(1.)),
 9100                        blur_radius: px(2.),
 9101                        spread_radius: px(0.),
 9102                    }])
 9103                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9104                    .border(BORDER_WIDTH)
 9105                    .border_color(cx.theme().colors().border)
 9106                    .rounded_r_lg()
 9107                    .id("edit_prediction_diff_popover_keybind")
 9108                    .when(!has_keybind, |el| {
 9109                        let status_colors = cx.theme().status();
 9110
 9111                        el.bg(status_colors.error_background)
 9112                            .border_color(status_colors.error.opacity(0.6))
 9113                            .child(Icon::new(IconName::Info).color(Color::Error))
 9114                            .cursor_default()
 9115                            .hoverable_tooltip(move |_window, cx| {
 9116                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9117                            })
 9118                    })
 9119                    .children(keybind),
 9120            )
 9121            .into_any();
 9122
 9123        let longest_row =
 9124            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9125        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9126            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9127        } else {
 9128            layout_line(
 9129                longest_row,
 9130                editor_snapshot,
 9131                style,
 9132                editor_width,
 9133                |_| false,
 9134                window,
 9135                cx,
 9136            )
 9137            .width
 9138        };
 9139
 9140        let viewport_bounds =
 9141            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9142                right: -right_margin,
 9143                ..Default::default()
 9144            });
 9145
 9146        let x_after_longest = Pixels::from(
 9147            ScrollPixelOffset::from(
 9148                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9149            ) - scroll_pixel_position.x,
 9150        );
 9151
 9152        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9153
 9154        // Fully visible if it can be displayed within the window (allow overlapping other
 9155        // panes). However, this is only allowed if the popover starts within text_bounds.
 9156        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9157            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9158
 9159        let mut origin = if can_position_to_the_right {
 9160            point(
 9161                x_after_longest,
 9162                text_bounds.origin.y
 9163                    + Pixels::from(
 9164                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9165                            - scroll_pixel_position.y,
 9166                    ),
 9167            )
 9168        } else {
 9169            let cursor_row = newest_selection_head.map(|head| head.row());
 9170            let above_edit = edit_start
 9171                .row()
 9172                .0
 9173                .checked_sub(line_count as u32)
 9174                .map(DisplayRow);
 9175            let below_edit = Some(edit_end.row() + 1);
 9176            let above_cursor =
 9177                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9178            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9179
 9180            // Place the edit popover adjacent to the edit if there is a location
 9181            // available that is onscreen and does not obscure the cursor. Otherwise,
 9182            // place it adjacent to the cursor.
 9183            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9184                .into_iter()
 9185                .flatten()
 9186                .find(|&start_row| {
 9187                    let end_row = start_row + line_count as u32;
 9188                    visible_row_range.contains(&start_row)
 9189                        && visible_row_range.contains(&end_row)
 9190                        && cursor_row
 9191                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9192                })?;
 9193
 9194            content_origin
 9195                + point(
 9196                    Pixels::from(-scroll_pixel_position.x),
 9197                    Pixels::from(
 9198                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9199                    ),
 9200                )
 9201        };
 9202
 9203        origin.x -= BORDER_WIDTH;
 9204
 9205        window.defer_draw(element, origin, 1);
 9206
 9207        // Do not return an element, since it will already be drawn due to defer_draw.
 9208        None
 9209    }
 9210
 9211    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9212        px(30.)
 9213    }
 9214
 9215    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9216        if self.read_only(cx) {
 9217            cx.theme().players().read_only()
 9218        } else {
 9219            self.style.as_ref().unwrap().local_player
 9220        }
 9221    }
 9222
 9223    fn render_edit_prediction_accept_keybind(
 9224        &self,
 9225        window: &mut Window,
 9226        cx: &App,
 9227    ) -> Option<AnyElement> {
 9228        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9229        let accept_keystroke = accept_binding.keystroke()?;
 9230
 9231        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9232
 9233        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9234            Color::Accent
 9235        } else {
 9236            Color::Muted
 9237        };
 9238
 9239        h_flex()
 9240            .px_0p5()
 9241            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9242            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9243            .text_size(TextSize::XSmall.rems(cx))
 9244            .child(h_flex().children(ui::render_modifiers(
 9245                accept_keystroke.modifiers(),
 9246                PlatformStyle::platform(),
 9247                Some(modifiers_color),
 9248                Some(IconSize::XSmall.rems().into()),
 9249                true,
 9250            )))
 9251            .when(is_platform_style_mac, |parent| {
 9252                parent.child(accept_keystroke.key().to_string())
 9253            })
 9254            .when(!is_platform_style_mac, |parent| {
 9255                parent.child(
 9256                    Key::new(
 9257                        util::capitalize(accept_keystroke.key()),
 9258                        Some(Color::Default),
 9259                    )
 9260                    .size(Some(IconSize::XSmall.rems().into())),
 9261                )
 9262            })
 9263            .into_any()
 9264            .into()
 9265    }
 9266
 9267    fn render_edit_prediction_line_popover(
 9268        &self,
 9269        label: impl Into<SharedString>,
 9270        icon: Option<IconName>,
 9271        window: &mut Window,
 9272        cx: &App,
 9273    ) -> Stateful<Div> {
 9274        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9275
 9276        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9277        let has_keybind = keybind.is_some();
 9278
 9279        h_flex()
 9280            .id("ep-line-popover")
 9281            .py_0p5()
 9282            .pl_1()
 9283            .pr(padding_right)
 9284            .gap_1()
 9285            .rounded_md()
 9286            .border_1()
 9287            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9288            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9289            .shadow_xs()
 9290            .when(!has_keybind, |el| {
 9291                let status_colors = cx.theme().status();
 9292
 9293                el.bg(status_colors.error_background)
 9294                    .border_color(status_colors.error.opacity(0.6))
 9295                    .pl_2()
 9296                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9297                    .cursor_default()
 9298                    .hoverable_tooltip(move |_window, cx| {
 9299                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9300                    })
 9301            })
 9302            .children(keybind)
 9303            .child(
 9304                Label::new(label)
 9305                    .size(LabelSize::Small)
 9306                    .when(!has_keybind, |el| {
 9307                        el.color(cx.theme().status().error.into()).strikethrough()
 9308                    }),
 9309            )
 9310            .when(!has_keybind, |el| {
 9311                el.child(
 9312                    h_flex().ml_1().child(
 9313                        Icon::new(IconName::Info)
 9314                            .size(IconSize::Small)
 9315                            .color(cx.theme().status().error.into()),
 9316                    ),
 9317                )
 9318            })
 9319            .when_some(icon, |element, icon| {
 9320                element.child(
 9321                    div()
 9322                        .mt(px(1.5))
 9323                        .child(Icon::new(icon).size(IconSize::Small)),
 9324                )
 9325            })
 9326    }
 9327
 9328    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9329        let accent_color = cx.theme().colors().text_accent;
 9330        let editor_bg_color = cx.theme().colors().editor_background;
 9331        editor_bg_color.blend(accent_color.opacity(0.1))
 9332    }
 9333
 9334    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9335        let accent_color = cx.theme().colors().text_accent;
 9336        let editor_bg_color = cx.theme().colors().editor_background;
 9337        editor_bg_color.blend(accent_color.opacity(0.6))
 9338    }
 9339    fn get_prediction_provider_icon_name(
 9340        provider: &Option<RegisteredEditPredictionProvider>,
 9341    ) -> IconName {
 9342        match provider {
 9343            Some(provider) => match provider.provider.name() {
 9344                "copilot" => IconName::Copilot,
 9345                "supermaven" => IconName::Supermaven,
 9346                _ => IconName::ZedPredict,
 9347            },
 9348            None => IconName::ZedPredict,
 9349        }
 9350    }
 9351
 9352    fn render_edit_prediction_cursor_popover(
 9353        &self,
 9354        min_width: Pixels,
 9355        max_width: Pixels,
 9356        cursor_point: Point,
 9357        style: &EditorStyle,
 9358        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9359        _window: &Window,
 9360        cx: &mut Context<Editor>,
 9361    ) -> Option<AnyElement> {
 9362        let provider = self.edit_prediction_provider.as_ref()?;
 9363        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9364
 9365        let is_refreshing = provider.provider.is_refreshing(cx);
 9366
 9367        fn pending_completion_container(icon: IconName) -> Div {
 9368            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9369        }
 9370
 9371        let completion = match &self.active_edit_prediction {
 9372            Some(prediction) => {
 9373                if !self.has_visible_completions_menu() {
 9374                    const RADIUS: Pixels = px(6.);
 9375                    const BORDER_WIDTH: Pixels = px(1.);
 9376
 9377                    return Some(
 9378                        h_flex()
 9379                            .elevation_2(cx)
 9380                            .border(BORDER_WIDTH)
 9381                            .border_color(cx.theme().colors().border)
 9382                            .when(accept_keystroke.is_none(), |el| {
 9383                                el.border_color(cx.theme().status().error)
 9384                            })
 9385                            .rounded(RADIUS)
 9386                            .rounded_tl(px(0.))
 9387                            .overflow_hidden()
 9388                            .child(div().px_1p5().child(match &prediction.completion {
 9389                                EditPrediction::MoveWithin { target, snapshot } => {
 9390                                    use text::ToPoint as _;
 9391                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9392                                    {
 9393                                        Icon::new(IconName::ZedPredictDown)
 9394                                    } else {
 9395                                        Icon::new(IconName::ZedPredictUp)
 9396                                    }
 9397                                }
 9398                                EditPrediction::MoveOutside { .. } => {
 9399                                    // TODO [zeta2] custom icon for external jump?
 9400                                    Icon::new(provider_icon)
 9401                                }
 9402                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9403                            }))
 9404                            .child(
 9405                                h_flex()
 9406                                    .gap_1()
 9407                                    .py_1()
 9408                                    .px_2()
 9409                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9410                                    .border_l_1()
 9411                                    .border_color(cx.theme().colors().border)
 9412                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9413                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9414                                        el.child(
 9415                                            Label::new("Hold")
 9416                                                .size(LabelSize::Small)
 9417                                                .when(accept_keystroke.is_none(), |el| {
 9418                                                    el.strikethrough()
 9419                                                })
 9420                                                .line_height_style(LineHeightStyle::UiLabel),
 9421                                        )
 9422                                    })
 9423                                    .id("edit_prediction_cursor_popover_keybind")
 9424                                    .when(accept_keystroke.is_none(), |el| {
 9425                                        let status_colors = cx.theme().status();
 9426
 9427                                        el.bg(status_colors.error_background)
 9428                                            .border_color(status_colors.error.opacity(0.6))
 9429                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9430                                            .cursor_default()
 9431                                            .hoverable_tooltip(move |_window, cx| {
 9432                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9433                                                    .into()
 9434                                            })
 9435                                    })
 9436                                    .when_some(
 9437                                        accept_keystroke.as_ref(),
 9438                                        |el, accept_keystroke| {
 9439                                            el.child(h_flex().children(ui::render_modifiers(
 9440                                                accept_keystroke.modifiers(),
 9441                                                PlatformStyle::platform(),
 9442                                                Some(Color::Default),
 9443                                                Some(IconSize::XSmall.rems().into()),
 9444                                                false,
 9445                                            )))
 9446                                        },
 9447                                    ),
 9448                            )
 9449                            .into_any(),
 9450                    );
 9451                }
 9452
 9453                self.render_edit_prediction_cursor_popover_preview(
 9454                    prediction,
 9455                    cursor_point,
 9456                    style,
 9457                    cx,
 9458                )?
 9459            }
 9460
 9461            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9462                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9463                    stale_completion,
 9464                    cursor_point,
 9465                    style,
 9466                    cx,
 9467                )?,
 9468
 9469                None => pending_completion_container(provider_icon)
 9470                    .child(Label::new("...").size(LabelSize::Small)),
 9471            },
 9472
 9473            None => pending_completion_container(provider_icon)
 9474                .child(Label::new("...").size(LabelSize::Small)),
 9475        };
 9476
 9477        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9478            completion
 9479                .with_animation(
 9480                    "loading-completion",
 9481                    Animation::new(Duration::from_secs(2))
 9482                        .repeat()
 9483                        .with_easing(pulsating_between(0.4, 0.8)),
 9484                    |label, delta| label.opacity(delta),
 9485                )
 9486                .into_any_element()
 9487        } else {
 9488            completion.into_any_element()
 9489        };
 9490
 9491        let has_completion = self.active_edit_prediction.is_some();
 9492
 9493        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9494        Some(
 9495            h_flex()
 9496                .min_w(min_width)
 9497                .max_w(max_width)
 9498                .flex_1()
 9499                .elevation_2(cx)
 9500                .border_color(cx.theme().colors().border)
 9501                .child(
 9502                    div()
 9503                        .flex_1()
 9504                        .py_1()
 9505                        .px_2()
 9506                        .overflow_hidden()
 9507                        .child(completion),
 9508                )
 9509                .when_some(accept_keystroke, |el, accept_keystroke| {
 9510                    if !accept_keystroke.modifiers().modified() {
 9511                        return el;
 9512                    }
 9513
 9514                    el.child(
 9515                        h_flex()
 9516                            .h_full()
 9517                            .border_l_1()
 9518                            .rounded_r_lg()
 9519                            .border_color(cx.theme().colors().border)
 9520                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9521                            .gap_1()
 9522                            .py_1()
 9523                            .px_2()
 9524                            .child(
 9525                                h_flex()
 9526                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9527                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9528                                    .child(h_flex().children(ui::render_modifiers(
 9529                                        accept_keystroke.modifiers(),
 9530                                        PlatformStyle::platform(),
 9531                                        Some(if !has_completion {
 9532                                            Color::Muted
 9533                                        } else {
 9534                                            Color::Default
 9535                                        }),
 9536                                        None,
 9537                                        false,
 9538                                    ))),
 9539                            )
 9540                            .child(Label::new("Preview").into_any_element())
 9541                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9542                    )
 9543                })
 9544                .into_any(),
 9545        )
 9546    }
 9547
 9548    fn render_edit_prediction_cursor_popover_preview(
 9549        &self,
 9550        completion: &EditPredictionState,
 9551        cursor_point: Point,
 9552        style: &EditorStyle,
 9553        cx: &mut Context<Editor>,
 9554    ) -> Option<Div> {
 9555        use text::ToPoint as _;
 9556
 9557        fn render_relative_row_jump(
 9558            prefix: impl Into<String>,
 9559            current_row: u32,
 9560            target_row: u32,
 9561        ) -> Div {
 9562            let (row_diff, arrow) = if target_row < current_row {
 9563                (current_row - target_row, IconName::ArrowUp)
 9564            } else {
 9565                (target_row - current_row, IconName::ArrowDown)
 9566            };
 9567
 9568            h_flex()
 9569                .child(
 9570                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9571                        .color(Color::Muted)
 9572                        .size(LabelSize::Small),
 9573                )
 9574                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9575        }
 9576
 9577        let supports_jump = self
 9578            .edit_prediction_provider
 9579            .as_ref()
 9580            .map(|provider| provider.provider.supports_jump_to_edit())
 9581            .unwrap_or(true);
 9582
 9583        match &completion.completion {
 9584            EditPrediction::MoveWithin {
 9585                target, snapshot, ..
 9586            } => {
 9587                if !supports_jump {
 9588                    return None;
 9589                }
 9590
 9591                Some(
 9592                    h_flex()
 9593                        .px_2()
 9594                        .gap_2()
 9595                        .flex_1()
 9596                        .child(
 9597                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9598                                Icon::new(IconName::ZedPredictDown)
 9599                            } else {
 9600                                Icon::new(IconName::ZedPredictUp)
 9601                            },
 9602                        )
 9603                        .child(Label::new("Jump to Edit")),
 9604                )
 9605            }
 9606            EditPrediction::MoveOutside { snapshot, .. } => {
 9607                let file_name = snapshot
 9608                    .file()
 9609                    .map(|file| file.file_name(cx))
 9610                    .unwrap_or("untitled");
 9611                Some(
 9612                    h_flex()
 9613                        .px_2()
 9614                        .gap_2()
 9615                        .flex_1()
 9616                        .child(Icon::new(IconName::ZedPredict))
 9617                        .child(Label::new(format!("Jump to {file_name}"))),
 9618                )
 9619            }
 9620            EditPrediction::Edit {
 9621                edits,
 9622                edit_preview,
 9623                snapshot,
 9624                display_mode: _,
 9625            } => {
 9626                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9627
 9628                let (highlighted_edits, has_more_lines) =
 9629                    if let Some(edit_preview) = edit_preview.as_ref() {
 9630                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9631                            .first_line_preview()
 9632                    } else {
 9633                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9634                    };
 9635
 9636                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9637                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9638
 9639                let preview = h_flex()
 9640                    .gap_1()
 9641                    .min_w_16()
 9642                    .child(styled_text)
 9643                    .when(has_more_lines, |parent| parent.child(""));
 9644
 9645                let left = if supports_jump && first_edit_row != cursor_point.row {
 9646                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9647                        .into_any_element()
 9648                } else {
 9649                    let icon_name =
 9650                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9651                    Icon::new(icon_name).into_any_element()
 9652                };
 9653
 9654                Some(
 9655                    h_flex()
 9656                        .h_full()
 9657                        .flex_1()
 9658                        .gap_2()
 9659                        .pr_1()
 9660                        .overflow_x_hidden()
 9661                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9662                        .child(left)
 9663                        .child(preview),
 9664                )
 9665            }
 9666        }
 9667    }
 9668
 9669    pub fn render_context_menu(
 9670        &self,
 9671        style: &EditorStyle,
 9672        max_height_in_lines: u32,
 9673        window: &mut Window,
 9674        cx: &mut Context<Editor>,
 9675    ) -> Option<AnyElement> {
 9676        let menu = self.context_menu.borrow();
 9677        let menu = menu.as_ref()?;
 9678        if !menu.visible() {
 9679            return None;
 9680        };
 9681        Some(menu.render(style, max_height_in_lines, window, cx))
 9682    }
 9683
 9684    fn render_context_menu_aside(
 9685        &mut self,
 9686        max_size: Size<Pixels>,
 9687        window: &mut Window,
 9688        cx: &mut Context<Editor>,
 9689    ) -> Option<AnyElement> {
 9690        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9691            if menu.visible() {
 9692                menu.render_aside(max_size, window, cx)
 9693            } else {
 9694                None
 9695            }
 9696        })
 9697    }
 9698
 9699    fn hide_context_menu(
 9700        &mut self,
 9701        window: &mut Window,
 9702        cx: &mut Context<Self>,
 9703    ) -> Option<CodeContextMenu> {
 9704        cx.notify();
 9705        self.completion_tasks.clear();
 9706        let context_menu = self.context_menu.borrow_mut().take();
 9707        self.stale_edit_prediction_in_menu.take();
 9708        self.update_visible_edit_prediction(window, cx);
 9709        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9710            && let Some(completion_provider) = &self.completion_provider
 9711        {
 9712            completion_provider.selection_changed(None, window, cx);
 9713        }
 9714        context_menu
 9715    }
 9716
 9717    fn show_snippet_choices(
 9718        &mut self,
 9719        choices: &Vec<String>,
 9720        selection: Range<Anchor>,
 9721        cx: &mut Context<Self>,
 9722    ) {
 9723        let Some((_, buffer, _)) = self
 9724            .buffer()
 9725            .read(cx)
 9726            .excerpt_containing(selection.start, cx)
 9727        else {
 9728            return;
 9729        };
 9730        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9731        else {
 9732            return;
 9733        };
 9734        if buffer != end_buffer {
 9735            log::error!("expected anchor range to have matching buffer IDs");
 9736            return;
 9737        }
 9738
 9739        let id = post_inc(&mut self.next_completion_id);
 9740        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9741        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9742            CompletionsMenu::new_snippet_choices(
 9743                id,
 9744                true,
 9745                choices,
 9746                selection,
 9747                buffer,
 9748                snippet_sort_order,
 9749            ),
 9750        ));
 9751    }
 9752
 9753    pub fn insert_snippet(
 9754        &mut self,
 9755        insertion_ranges: &[Range<usize>],
 9756        snippet: Snippet,
 9757        window: &mut Window,
 9758        cx: &mut Context<Self>,
 9759    ) -> Result<()> {
 9760        struct Tabstop<T> {
 9761            is_end_tabstop: bool,
 9762            ranges: Vec<Range<T>>,
 9763            choices: Option<Vec<String>>,
 9764        }
 9765
 9766        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9767            let snippet_text: Arc<str> = snippet.text.clone().into();
 9768            let edits = insertion_ranges
 9769                .iter()
 9770                .cloned()
 9771                .map(|range| (range, snippet_text.clone()));
 9772            let autoindent_mode = AutoindentMode::Block {
 9773                original_indent_columns: Vec::new(),
 9774            };
 9775            buffer.edit(edits, Some(autoindent_mode), cx);
 9776
 9777            let snapshot = &*buffer.read(cx);
 9778            let snippet = &snippet;
 9779            snippet
 9780                .tabstops
 9781                .iter()
 9782                .map(|tabstop| {
 9783                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9784                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9785                    });
 9786                    let mut tabstop_ranges = tabstop
 9787                        .ranges
 9788                        .iter()
 9789                        .flat_map(|tabstop_range| {
 9790                            let mut delta = 0_isize;
 9791                            insertion_ranges.iter().map(move |insertion_range| {
 9792                                let insertion_start = insertion_range.start as isize + delta;
 9793                                delta +=
 9794                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9795
 9796                                let start = ((insertion_start + tabstop_range.start) as usize)
 9797                                    .min(snapshot.len());
 9798                                let end = ((insertion_start + tabstop_range.end) as usize)
 9799                                    .min(snapshot.len());
 9800                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9801                            })
 9802                        })
 9803                        .collect::<Vec<_>>();
 9804                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9805
 9806                    Tabstop {
 9807                        is_end_tabstop,
 9808                        ranges: tabstop_ranges,
 9809                        choices: tabstop.choices.clone(),
 9810                    }
 9811                })
 9812                .collect::<Vec<_>>()
 9813        });
 9814        if let Some(tabstop) = tabstops.first() {
 9815            self.change_selections(Default::default(), window, cx, |s| {
 9816                // Reverse order so that the first range is the newest created selection.
 9817                // Completions will use it and autoscroll will prioritize it.
 9818                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9819            });
 9820
 9821            if let Some(choices) = &tabstop.choices
 9822                && let Some(selection) = tabstop.ranges.first()
 9823            {
 9824                self.show_snippet_choices(choices, selection.clone(), cx)
 9825            }
 9826
 9827            // If we're already at the last tabstop and it's at the end of the snippet,
 9828            // we're done, we don't need to keep the state around.
 9829            if !tabstop.is_end_tabstop {
 9830                let choices = tabstops
 9831                    .iter()
 9832                    .map(|tabstop| tabstop.choices.clone())
 9833                    .collect();
 9834
 9835                let ranges = tabstops
 9836                    .into_iter()
 9837                    .map(|tabstop| tabstop.ranges)
 9838                    .collect::<Vec<_>>();
 9839
 9840                self.snippet_stack.push(SnippetState {
 9841                    active_index: 0,
 9842                    ranges,
 9843                    choices,
 9844                });
 9845            }
 9846
 9847            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9848            if self.autoclose_regions.is_empty() {
 9849                let snapshot = self.buffer.read(cx).snapshot(cx);
 9850                let mut all_selections = self.selections.all::<Point>(cx);
 9851                for selection in &mut all_selections {
 9852                    let selection_head = selection.head();
 9853                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9854                        continue;
 9855                    };
 9856
 9857                    let mut bracket_pair = None;
 9858                    let max_lookup_length = scope
 9859                        .brackets()
 9860                        .map(|(pair, _)| {
 9861                            pair.start
 9862                                .as_str()
 9863                                .chars()
 9864                                .count()
 9865                                .max(pair.end.as_str().chars().count())
 9866                        })
 9867                        .max();
 9868                    if let Some(max_lookup_length) = max_lookup_length {
 9869                        let next_text = snapshot
 9870                            .chars_at(selection_head)
 9871                            .take(max_lookup_length)
 9872                            .collect::<String>();
 9873                        let prev_text = snapshot
 9874                            .reversed_chars_at(selection_head)
 9875                            .take(max_lookup_length)
 9876                            .collect::<String>();
 9877
 9878                        for (pair, enabled) in scope.brackets() {
 9879                            if enabled
 9880                                && pair.close
 9881                                && prev_text.starts_with(pair.start.as_str())
 9882                                && next_text.starts_with(pair.end.as_str())
 9883                            {
 9884                                bracket_pair = Some(pair.clone());
 9885                                break;
 9886                            }
 9887                        }
 9888                    }
 9889
 9890                    if let Some(pair) = bracket_pair {
 9891                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9892                        let autoclose_enabled =
 9893                            self.use_autoclose && snapshot_settings.use_autoclose;
 9894                        if autoclose_enabled {
 9895                            let start = snapshot.anchor_after(selection_head);
 9896                            let end = snapshot.anchor_after(selection_head);
 9897                            self.autoclose_regions.push(AutocloseRegion {
 9898                                selection_id: selection.id,
 9899                                range: start..end,
 9900                                pair,
 9901                            });
 9902                        }
 9903                    }
 9904                }
 9905            }
 9906        }
 9907        Ok(())
 9908    }
 9909
 9910    pub fn move_to_next_snippet_tabstop(
 9911        &mut self,
 9912        window: &mut Window,
 9913        cx: &mut Context<Self>,
 9914    ) -> bool {
 9915        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9916    }
 9917
 9918    pub fn move_to_prev_snippet_tabstop(
 9919        &mut self,
 9920        window: &mut Window,
 9921        cx: &mut Context<Self>,
 9922    ) -> bool {
 9923        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9924    }
 9925
 9926    pub fn move_to_snippet_tabstop(
 9927        &mut self,
 9928        bias: Bias,
 9929        window: &mut Window,
 9930        cx: &mut Context<Self>,
 9931    ) -> bool {
 9932        if let Some(mut snippet) = self.snippet_stack.pop() {
 9933            match bias {
 9934                Bias::Left => {
 9935                    if snippet.active_index > 0 {
 9936                        snippet.active_index -= 1;
 9937                    } else {
 9938                        self.snippet_stack.push(snippet);
 9939                        return false;
 9940                    }
 9941                }
 9942                Bias::Right => {
 9943                    if snippet.active_index + 1 < snippet.ranges.len() {
 9944                        snippet.active_index += 1;
 9945                    } else {
 9946                        self.snippet_stack.push(snippet);
 9947                        return false;
 9948                    }
 9949                }
 9950            }
 9951            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9952                self.change_selections(Default::default(), window, cx, |s| {
 9953                    // Reverse order so that the first range is the newest created selection.
 9954                    // Completions will use it and autoscroll will prioritize it.
 9955                    s.select_ranges(current_ranges.iter().rev().cloned())
 9956                });
 9957
 9958                if let Some(choices) = &snippet.choices[snippet.active_index]
 9959                    && let Some(selection) = current_ranges.first()
 9960                {
 9961                    self.show_snippet_choices(choices, selection.clone(), cx);
 9962                }
 9963
 9964                // If snippet state is not at the last tabstop, push it back on the stack
 9965                if snippet.active_index + 1 < snippet.ranges.len() {
 9966                    self.snippet_stack.push(snippet);
 9967                }
 9968                return true;
 9969            }
 9970        }
 9971
 9972        false
 9973    }
 9974
 9975    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9976        self.transact(window, cx, |this, window, cx| {
 9977            this.select_all(&SelectAll, window, cx);
 9978            this.insert("", window, cx);
 9979        });
 9980    }
 9981
 9982    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9983        if self.read_only(cx) {
 9984            return;
 9985        }
 9986        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9987        self.transact(window, cx, |this, window, cx| {
 9988            this.select_autoclose_pair(window, cx);
 9989            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9990            if !this.linked_edit_ranges.is_empty() {
 9991                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9992                let snapshot = this.buffer.read(cx).snapshot(cx);
 9993
 9994                for selection in selections.iter() {
 9995                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9996                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9997                    if selection_start.buffer_id != selection_end.buffer_id {
 9998                        continue;
 9999                    }
10000                    if let Some(ranges) =
10001                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10002                    {
10003                        for (buffer, entries) in ranges {
10004                            linked_ranges.entry(buffer).or_default().extend(entries);
10005                        }
10006                    }
10007                }
10008            }
10009
10010            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
10011            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10012            for selection in &mut selections {
10013                if selection.is_empty() {
10014                    let old_head = selection.head();
10015                    let mut new_head =
10016                        movement::left(&display_map, old_head.to_display_point(&display_map))
10017                            .to_point(&display_map);
10018                    if let Some((buffer, line_buffer_range)) = display_map
10019                        .buffer_snapshot()
10020                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10021                    {
10022                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10023                        let indent_len = match indent_size.kind {
10024                            IndentKind::Space => {
10025                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10026                            }
10027                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10028                        };
10029                        if old_head.column <= indent_size.len && old_head.column > 0 {
10030                            let indent_len = indent_len.get();
10031                            new_head = cmp::min(
10032                                new_head,
10033                                MultiBufferPoint::new(
10034                                    old_head.row,
10035                                    ((old_head.column - 1) / indent_len) * indent_len,
10036                                ),
10037                            );
10038                        }
10039                    }
10040
10041                    selection.set_head(new_head, SelectionGoal::None);
10042                }
10043            }
10044
10045            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10046            this.insert("", window, cx);
10047            let empty_str: Arc<str> = Arc::from("");
10048            for (buffer, edits) in linked_ranges {
10049                let snapshot = buffer.read(cx).snapshot();
10050                use text::ToPoint as TP;
10051
10052                let edits = edits
10053                    .into_iter()
10054                    .map(|range| {
10055                        let end_point = TP::to_point(&range.end, &snapshot);
10056                        let mut start_point = TP::to_point(&range.start, &snapshot);
10057
10058                        if end_point == start_point {
10059                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10060                                .saturating_sub(1);
10061                            start_point =
10062                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10063                        };
10064
10065                        (start_point..end_point, empty_str.clone())
10066                    })
10067                    .sorted_by_key(|(range, _)| range.start)
10068                    .collect::<Vec<_>>();
10069                buffer.update(cx, |this, cx| {
10070                    this.edit(edits, None, cx);
10071                })
10072            }
10073            this.refresh_edit_prediction(true, false, window, cx);
10074            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
10075        });
10076    }
10077
10078    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10079        if self.read_only(cx) {
10080            return;
10081        }
10082        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10083        self.transact(window, cx, |this, window, cx| {
10084            this.change_selections(Default::default(), window, cx, |s| {
10085                s.move_with(|map, selection| {
10086                    if selection.is_empty() {
10087                        let cursor = movement::right(map, selection.head());
10088                        selection.end = cursor;
10089                        selection.reversed = true;
10090                        selection.goal = SelectionGoal::None;
10091                    }
10092                })
10093            });
10094            this.insert("", window, cx);
10095            this.refresh_edit_prediction(true, false, window, cx);
10096        });
10097    }
10098
10099    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10100        if self.mode.is_single_line() {
10101            cx.propagate();
10102            return;
10103        }
10104
10105        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10106        if self.move_to_prev_snippet_tabstop(window, cx) {
10107            return;
10108        }
10109        self.outdent(&Outdent, window, cx);
10110    }
10111
10112    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10113        if self.mode.is_single_line() {
10114            cx.propagate();
10115            return;
10116        }
10117
10118        if self.move_to_next_snippet_tabstop(window, cx) {
10119            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10120            return;
10121        }
10122        if self.read_only(cx) {
10123            return;
10124        }
10125        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10126        let mut selections = self.selections.all_adjusted(cx);
10127        let buffer = self.buffer.read(cx);
10128        let snapshot = buffer.snapshot(cx);
10129        let rows_iter = selections.iter().map(|s| s.head().row);
10130        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10131
10132        let has_some_cursor_in_whitespace = selections
10133            .iter()
10134            .filter(|selection| selection.is_empty())
10135            .any(|selection| {
10136                let cursor = selection.head();
10137                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10138                cursor.column < current_indent.len
10139            });
10140
10141        let mut edits = Vec::new();
10142        let mut prev_edited_row = 0;
10143        let mut row_delta = 0;
10144        for selection in &mut selections {
10145            if selection.start.row != prev_edited_row {
10146                row_delta = 0;
10147            }
10148            prev_edited_row = selection.end.row;
10149
10150            // If the selection is non-empty, then increase the indentation of the selected lines.
10151            if !selection.is_empty() {
10152                row_delta =
10153                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10154                continue;
10155            }
10156
10157            let cursor = selection.head();
10158            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10159            if let Some(suggested_indent) =
10160                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10161            {
10162                // Don't do anything if already at suggested indent
10163                // and there is any other cursor which is not
10164                if has_some_cursor_in_whitespace
10165                    && cursor.column == current_indent.len
10166                    && current_indent.len == suggested_indent.len
10167                {
10168                    continue;
10169                }
10170
10171                // Adjust line and move cursor to suggested indent
10172                // if cursor is not at suggested indent
10173                if cursor.column < suggested_indent.len
10174                    && cursor.column <= current_indent.len
10175                    && current_indent.len <= suggested_indent.len
10176                {
10177                    selection.start = Point::new(cursor.row, suggested_indent.len);
10178                    selection.end = selection.start;
10179                    if row_delta == 0 {
10180                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10181                            cursor.row,
10182                            current_indent,
10183                            suggested_indent,
10184                        ));
10185                        row_delta = suggested_indent.len - current_indent.len;
10186                    }
10187                    continue;
10188                }
10189
10190                // If current indent is more than suggested indent
10191                // only move cursor to current indent and skip indent
10192                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10193                    selection.start = Point::new(cursor.row, current_indent.len);
10194                    selection.end = selection.start;
10195                    continue;
10196                }
10197            }
10198
10199            // Otherwise, insert a hard or soft tab.
10200            let settings = buffer.language_settings_at(cursor, cx);
10201            let tab_size = if settings.hard_tabs {
10202                IndentSize::tab()
10203            } else {
10204                let tab_size = settings.tab_size.get();
10205                let indent_remainder = snapshot
10206                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10207                    .flat_map(str::chars)
10208                    .fold(row_delta % tab_size, |counter: u32, c| {
10209                        if c == '\t' {
10210                            0
10211                        } else {
10212                            (counter + 1) % tab_size
10213                        }
10214                    });
10215
10216                let chars_to_next_tab_stop = tab_size - indent_remainder;
10217                IndentSize::spaces(chars_to_next_tab_stop)
10218            };
10219            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10220            selection.end = selection.start;
10221            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10222            row_delta += tab_size.len;
10223        }
10224
10225        self.transact(window, cx, |this, window, cx| {
10226            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10227            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10228            this.refresh_edit_prediction(true, false, window, cx);
10229        });
10230    }
10231
10232    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10233        if self.read_only(cx) {
10234            return;
10235        }
10236        if self.mode.is_single_line() {
10237            cx.propagate();
10238            return;
10239        }
10240
10241        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10242        let mut selections = self.selections.all::<Point>(cx);
10243        let mut prev_edited_row = 0;
10244        let mut row_delta = 0;
10245        let mut edits = Vec::new();
10246        let buffer = self.buffer.read(cx);
10247        let snapshot = buffer.snapshot(cx);
10248        for selection in &mut selections {
10249            if selection.start.row != prev_edited_row {
10250                row_delta = 0;
10251            }
10252            prev_edited_row = selection.end.row;
10253
10254            row_delta =
10255                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10256        }
10257
10258        self.transact(window, cx, |this, window, cx| {
10259            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10260            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10261        });
10262    }
10263
10264    fn indent_selection(
10265        buffer: &MultiBuffer,
10266        snapshot: &MultiBufferSnapshot,
10267        selection: &mut Selection<Point>,
10268        edits: &mut Vec<(Range<Point>, String)>,
10269        delta_for_start_row: u32,
10270        cx: &App,
10271    ) -> u32 {
10272        let settings = buffer.language_settings_at(selection.start, cx);
10273        let tab_size = settings.tab_size.get();
10274        let indent_kind = if settings.hard_tabs {
10275            IndentKind::Tab
10276        } else {
10277            IndentKind::Space
10278        };
10279        let mut start_row = selection.start.row;
10280        let mut end_row = selection.end.row + 1;
10281
10282        // If a selection ends at the beginning of a line, don't indent
10283        // that last line.
10284        if selection.end.column == 0 && selection.end.row > selection.start.row {
10285            end_row -= 1;
10286        }
10287
10288        // Avoid re-indenting a row that has already been indented by a
10289        // previous selection, but still update this selection's column
10290        // to reflect that indentation.
10291        if delta_for_start_row > 0 {
10292            start_row += 1;
10293            selection.start.column += delta_for_start_row;
10294            if selection.end.row == selection.start.row {
10295                selection.end.column += delta_for_start_row;
10296            }
10297        }
10298
10299        let mut delta_for_end_row = 0;
10300        let has_multiple_rows = start_row + 1 != end_row;
10301        for row in start_row..end_row {
10302            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10303            let indent_delta = match (current_indent.kind, indent_kind) {
10304                (IndentKind::Space, IndentKind::Space) => {
10305                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10306                    IndentSize::spaces(columns_to_next_tab_stop)
10307                }
10308                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10309                (_, IndentKind::Tab) => IndentSize::tab(),
10310            };
10311
10312            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10313                0
10314            } else {
10315                selection.start.column
10316            };
10317            let row_start = Point::new(row, start);
10318            edits.push((
10319                row_start..row_start,
10320                indent_delta.chars().collect::<String>(),
10321            ));
10322
10323            // Update this selection's endpoints to reflect the indentation.
10324            if row == selection.start.row {
10325                selection.start.column += indent_delta.len;
10326            }
10327            if row == selection.end.row {
10328                selection.end.column += indent_delta.len;
10329                delta_for_end_row = indent_delta.len;
10330            }
10331        }
10332
10333        if selection.start.row == selection.end.row {
10334            delta_for_start_row + delta_for_end_row
10335        } else {
10336            delta_for_end_row
10337        }
10338    }
10339
10340    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10341        if self.read_only(cx) {
10342            return;
10343        }
10344        if self.mode.is_single_line() {
10345            cx.propagate();
10346            return;
10347        }
10348
10349        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10350        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10351        let selections = self.selections.all::<Point>(cx);
10352        let mut deletion_ranges = Vec::new();
10353        let mut last_outdent = None;
10354        {
10355            let buffer = self.buffer.read(cx);
10356            let snapshot = buffer.snapshot(cx);
10357            for selection in &selections {
10358                let settings = buffer.language_settings_at(selection.start, cx);
10359                let tab_size = settings.tab_size.get();
10360                let mut rows = selection.spanned_rows(false, &display_map);
10361
10362                // Avoid re-outdenting a row that has already been outdented by a
10363                // previous selection.
10364                if let Some(last_row) = last_outdent
10365                    && last_row == rows.start
10366                {
10367                    rows.start = rows.start.next_row();
10368                }
10369                let has_multiple_rows = rows.len() > 1;
10370                for row in rows.iter_rows() {
10371                    let indent_size = snapshot.indent_size_for_line(row);
10372                    if indent_size.len > 0 {
10373                        let deletion_len = match indent_size.kind {
10374                            IndentKind::Space => {
10375                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10376                                if columns_to_prev_tab_stop == 0 {
10377                                    tab_size
10378                                } else {
10379                                    columns_to_prev_tab_stop
10380                                }
10381                            }
10382                            IndentKind::Tab => 1,
10383                        };
10384                        let start = if has_multiple_rows
10385                            || deletion_len > selection.start.column
10386                            || indent_size.len < selection.start.column
10387                        {
10388                            0
10389                        } else {
10390                            selection.start.column - deletion_len
10391                        };
10392                        deletion_ranges.push(
10393                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10394                        );
10395                        last_outdent = Some(row);
10396                    }
10397                }
10398            }
10399        }
10400
10401        self.transact(window, cx, |this, window, cx| {
10402            this.buffer.update(cx, |buffer, cx| {
10403                let empty_str: Arc<str> = Arc::default();
10404                buffer.edit(
10405                    deletion_ranges
10406                        .into_iter()
10407                        .map(|range| (range, empty_str.clone())),
10408                    None,
10409                    cx,
10410                );
10411            });
10412            let selections = this.selections.all::<usize>(cx);
10413            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10414        });
10415    }
10416
10417    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10418        if self.read_only(cx) {
10419            return;
10420        }
10421        if self.mode.is_single_line() {
10422            cx.propagate();
10423            return;
10424        }
10425
10426        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10427        let selections = self
10428            .selections
10429            .all::<usize>(cx)
10430            .into_iter()
10431            .map(|s| s.range());
10432
10433        self.transact(window, cx, |this, window, cx| {
10434            this.buffer.update(cx, |buffer, cx| {
10435                buffer.autoindent_ranges(selections, cx);
10436            });
10437            let selections = this.selections.all::<usize>(cx);
10438            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10439        });
10440    }
10441
10442    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10443        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10444        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10445        let selections = self.selections.all::<Point>(cx);
10446
10447        let mut new_cursors = Vec::new();
10448        let mut edit_ranges = Vec::new();
10449        let mut selections = selections.iter().peekable();
10450        while let Some(selection) = selections.next() {
10451            let mut rows = selection.spanned_rows(false, &display_map);
10452
10453            // Accumulate contiguous regions of rows that we want to delete.
10454            while let Some(next_selection) = selections.peek() {
10455                let next_rows = next_selection.spanned_rows(false, &display_map);
10456                if next_rows.start <= rows.end {
10457                    rows.end = next_rows.end;
10458                    selections.next().unwrap();
10459                } else {
10460                    break;
10461                }
10462            }
10463
10464            let buffer = display_map.buffer_snapshot();
10465            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10466            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10467                // If there's a line after the range, delete the \n from the end of the row range
10468                (
10469                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10470                    rows.end,
10471                )
10472            } else {
10473                // If there isn't a line after the range, delete the \n from the line before the
10474                // start of the row range
10475                edit_start = edit_start.saturating_sub(1);
10476                (buffer.len(), rows.start.previous_row())
10477            };
10478
10479            let text_layout_details = self.text_layout_details(window);
10480            let x = display_map.x_for_display_point(
10481                selection.head().to_display_point(&display_map),
10482                &text_layout_details,
10483            );
10484            let row = Point::new(target_row.0, 0)
10485                .to_display_point(&display_map)
10486                .row();
10487            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10488
10489            new_cursors.push((
10490                selection.id,
10491                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10492                SelectionGoal::None,
10493            ));
10494            edit_ranges.push(edit_start..edit_end);
10495        }
10496
10497        self.transact(window, cx, |this, window, cx| {
10498            let buffer = this.buffer.update(cx, |buffer, cx| {
10499                let empty_str: Arc<str> = Arc::default();
10500                buffer.edit(
10501                    edit_ranges
10502                        .into_iter()
10503                        .map(|range| (range, empty_str.clone())),
10504                    None,
10505                    cx,
10506                );
10507                buffer.snapshot(cx)
10508            });
10509            let new_selections = new_cursors
10510                .into_iter()
10511                .map(|(id, cursor, goal)| {
10512                    let cursor = cursor.to_point(&buffer);
10513                    Selection {
10514                        id,
10515                        start: cursor,
10516                        end: cursor,
10517                        reversed: false,
10518                        goal,
10519                    }
10520                })
10521                .collect();
10522
10523            this.change_selections(Default::default(), window, cx, |s| {
10524                s.select(new_selections);
10525            });
10526        });
10527    }
10528
10529    pub fn join_lines_impl(
10530        &mut self,
10531        insert_whitespace: bool,
10532        window: &mut Window,
10533        cx: &mut Context<Self>,
10534    ) {
10535        if self.read_only(cx) {
10536            return;
10537        }
10538        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10539        for selection in self.selections.all::<Point>(cx) {
10540            let start = MultiBufferRow(selection.start.row);
10541            // Treat single line selections as if they include the next line. Otherwise this action
10542            // would do nothing for single line selections individual cursors.
10543            let end = if selection.start.row == selection.end.row {
10544                MultiBufferRow(selection.start.row + 1)
10545            } else {
10546                MultiBufferRow(selection.end.row)
10547            };
10548
10549            if let Some(last_row_range) = row_ranges.last_mut()
10550                && start <= last_row_range.end
10551            {
10552                last_row_range.end = end;
10553                continue;
10554            }
10555            row_ranges.push(start..end);
10556        }
10557
10558        let snapshot = self.buffer.read(cx).snapshot(cx);
10559        let mut cursor_positions = Vec::new();
10560        for row_range in &row_ranges {
10561            let anchor = snapshot.anchor_before(Point::new(
10562                row_range.end.previous_row().0,
10563                snapshot.line_len(row_range.end.previous_row()),
10564            ));
10565            cursor_positions.push(anchor..anchor);
10566        }
10567
10568        self.transact(window, cx, |this, window, cx| {
10569            for row_range in row_ranges.into_iter().rev() {
10570                for row in row_range.iter_rows().rev() {
10571                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10572                    let next_line_row = row.next_row();
10573                    let indent = snapshot.indent_size_for_line(next_line_row);
10574                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10575
10576                    let replace =
10577                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10578                            " "
10579                        } else {
10580                            ""
10581                        };
10582
10583                    this.buffer.update(cx, |buffer, cx| {
10584                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10585                    });
10586                }
10587            }
10588
10589            this.change_selections(Default::default(), window, cx, |s| {
10590                s.select_anchor_ranges(cursor_positions)
10591            });
10592        });
10593    }
10594
10595    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10596        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10597        self.join_lines_impl(true, window, cx);
10598    }
10599
10600    pub fn sort_lines_case_sensitive(
10601        &mut self,
10602        _: &SortLinesCaseSensitive,
10603        window: &mut Window,
10604        cx: &mut Context<Self>,
10605    ) {
10606        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10607    }
10608
10609    pub fn sort_lines_by_length(
10610        &mut self,
10611        _: &SortLinesByLength,
10612        window: &mut Window,
10613        cx: &mut Context<Self>,
10614    ) {
10615        self.manipulate_immutable_lines(window, cx, |lines| {
10616            lines.sort_by_key(|&line| line.chars().count())
10617        })
10618    }
10619
10620    pub fn sort_lines_case_insensitive(
10621        &mut self,
10622        _: &SortLinesCaseInsensitive,
10623        window: &mut Window,
10624        cx: &mut Context<Self>,
10625    ) {
10626        self.manipulate_immutable_lines(window, cx, |lines| {
10627            lines.sort_by_key(|line| line.to_lowercase())
10628        })
10629    }
10630
10631    pub fn unique_lines_case_insensitive(
10632        &mut self,
10633        _: &UniqueLinesCaseInsensitive,
10634        window: &mut Window,
10635        cx: &mut Context<Self>,
10636    ) {
10637        self.manipulate_immutable_lines(window, cx, |lines| {
10638            let mut seen = HashSet::default();
10639            lines.retain(|line| seen.insert(line.to_lowercase()));
10640        })
10641    }
10642
10643    pub fn unique_lines_case_sensitive(
10644        &mut self,
10645        _: &UniqueLinesCaseSensitive,
10646        window: &mut Window,
10647        cx: &mut Context<Self>,
10648    ) {
10649        self.manipulate_immutable_lines(window, cx, |lines| {
10650            let mut seen = HashSet::default();
10651            lines.retain(|line| seen.insert(*line));
10652        })
10653    }
10654
10655    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10656        let snapshot = self.buffer.read(cx).snapshot(cx);
10657        for selection in self.selections.disjoint_anchors_arc().iter() {
10658            if snapshot
10659                .language_at(selection.start)
10660                .and_then(|lang| lang.config().wrap_characters.as_ref())
10661                .is_some()
10662            {
10663                return true;
10664            }
10665        }
10666        false
10667    }
10668
10669    fn wrap_selections_in_tag(
10670        &mut self,
10671        _: &WrapSelectionsInTag,
10672        window: &mut Window,
10673        cx: &mut Context<Self>,
10674    ) {
10675        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10676
10677        let snapshot = self.buffer.read(cx).snapshot(cx);
10678
10679        let mut edits = Vec::new();
10680        let mut boundaries = Vec::new();
10681
10682        for selection in self.selections.all::<Point>(cx).iter() {
10683            let Some(wrap_config) = snapshot
10684                .language_at(selection.start)
10685                .and_then(|lang| lang.config().wrap_characters.clone())
10686            else {
10687                continue;
10688            };
10689
10690            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10691            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10692
10693            let start_before = snapshot.anchor_before(selection.start);
10694            let end_after = snapshot.anchor_after(selection.end);
10695
10696            edits.push((start_before..start_before, open_tag));
10697            edits.push((end_after..end_after, close_tag));
10698
10699            boundaries.push((
10700                start_before,
10701                end_after,
10702                wrap_config.start_prefix.len(),
10703                wrap_config.end_suffix.len(),
10704            ));
10705        }
10706
10707        if edits.is_empty() {
10708            return;
10709        }
10710
10711        self.transact(window, cx, |this, window, cx| {
10712            let buffer = this.buffer.update(cx, |buffer, cx| {
10713                buffer.edit(edits, None, cx);
10714                buffer.snapshot(cx)
10715            });
10716
10717            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10718            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10719                boundaries.into_iter()
10720            {
10721                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10722                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10723                new_selections.push(open_offset..open_offset);
10724                new_selections.push(close_offset..close_offset);
10725            }
10726
10727            this.change_selections(Default::default(), window, cx, |s| {
10728                s.select_ranges(new_selections);
10729            });
10730
10731            this.request_autoscroll(Autoscroll::fit(), cx);
10732        });
10733    }
10734
10735    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10736        let Some(project) = self.project.clone() else {
10737            return;
10738        };
10739        self.reload(project, window, cx)
10740            .detach_and_notify_err(window, cx);
10741    }
10742
10743    pub fn restore_file(
10744        &mut self,
10745        _: &::git::RestoreFile,
10746        window: &mut Window,
10747        cx: &mut Context<Self>,
10748    ) {
10749        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10750        let mut buffer_ids = HashSet::default();
10751        let snapshot = self.buffer().read(cx).snapshot(cx);
10752        for selection in self.selections.all::<usize>(cx) {
10753            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10754        }
10755
10756        let buffer = self.buffer().read(cx);
10757        let ranges = buffer_ids
10758            .into_iter()
10759            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10760            .collect::<Vec<_>>();
10761
10762        self.restore_hunks_in_ranges(ranges, window, cx);
10763    }
10764
10765    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10766        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10767        let selections = self
10768            .selections
10769            .all(cx)
10770            .into_iter()
10771            .map(|s| s.range())
10772            .collect();
10773        self.restore_hunks_in_ranges(selections, window, cx);
10774    }
10775
10776    pub fn restore_hunks_in_ranges(
10777        &mut self,
10778        ranges: Vec<Range<Point>>,
10779        window: &mut Window,
10780        cx: &mut Context<Editor>,
10781    ) {
10782        let mut revert_changes = HashMap::default();
10783        let chunk_by = self
10784            .snapshot(window, cx)
10785            .hunks_for_ranges(ranges)
10786            .into_iter()
10787            .chunk_by(|hunk| hunk.buffer_id);
10788        for (buffer_id, hunks) in &chunk_by {
10789            let hunks = hunks.collect::<Vec<_>>();
10790            for hunk in &hunks {
10791                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10792            }
10793            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10794        }
10795        drop(chunk_by);
10796        if !revert_changes.is_empty() {
10797            self.transact(window, cx, |editor, window, cx| {
10798                editor.restore(revert_changes, window, cx);
10799            });
10800        }
10801    }
10802
10803    pub fn open_active_item_in_terminal(
10804        &mut self,
10805        _: &OpenInTerminal,
10806        window: &mut Window,
10807        cx: &mut Context<Self>,
10808    ) {
10809        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10810            let project_path = buffer.read(cx).project_path(cx)?;
10811            let project = self.project()?.read(cx);
10812            let entry = project.entry_for_path(&project_path, cx)?;
10813            let parent = match &entry.canonical_path {
10814                Some(canonical_path) => canonical_path.to_path_buf(),
10815                None => project.absolute_path(&project_path, cx)?,
10816            }
10817            .parent()?
10818            .to_path_buf();
10819            Some(parent)
10820        }) {
10821            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10822        }
10823    }
10824
10825    fn set_breakpoint_context_menu(
10826        &mut self,
10827        display_row: DisplayRow,
10828        position: Option<Anchor>,
10829        clicked_point: gpui::Point<Pixels>,
10830        window: &mut Window,
10831        cx: &mut Context<Self>,
10832    ) {
10833        let source = self
10834            .buffer
10835            .read(cx)
10836            .snapshot(cx)
10837            .anchor_before(Point::new(display_row.0, 0u32));
10838
10839        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10840
10841        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10842            self,
10843            source,
10844            clicked_point,
10845            context_menu,
10846            window,
10847            cx,
10848        );
10849    }
10850
10851    fn add_edit_breakpoint_block(
10852        &mut self,
10853        anchor: Anchor,
10854        breakpoint: &Breakpoint,
10855        edit_action: BreakpointPromptEditAction,
10856        window: &mut Window,
10857        cx: &mut Context<Self>,
10858    ) {
10859        let weak_editor = cx.weak_entity();
10860        let bp_prompt = cx.new(|cx| {
10861            BreakpointPromptEditor::new(
10862                weak_editor,
10863                anchor,
10864                breakpoint.clone(),
10865                edit_action,
10866                window,
10867                cx,
10868            )
10869        });
10870
10871        let height = bp_prompt.update(cx, |this, cx| {
10872            this.prompt
10873                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10874        });
10875        let cloned_prompt = bp_prompt.clone();
10876        let blocks = vec![BlockProperties {
10877            style: BlockStyle::Sticky,
10878            placement: BlockPlacement::Above(anchor),
10879            height: Some(height),
10880            render: Arc::new(move |cx| {
10881                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10882                cloned_prompt.clone().into_any_element()
10883            }),
10884            priority: 0,
10885        }];
10886
10887        let focus_handle = bp_prompt.focus_handle(cx);
10888        window.focus(&focus_handle);
10889
10890        let block_ids = self.insert_blocks(blocks, None, cx);
10891        bp_prompt.update(cx, |prompt, _| {
10892            prompt.add_block_ids(block_ids);
10893        });
10894    }
10895
10896    pub(crate) fn breakpoint_at_row(
10897        &self,
10898        row: u32,
10899        window: &mut Window,
10900        cx: &mut Context<Self>,
10901    ) -> Option<(Anchor, Breakpoint)> {
10902        let snapshot = self.snapshot(window, cx);
10903        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10904
10905        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10906    }
10907
10908    pub(crate) fn breakpoint_at_anchor(
10909        &self,
10910        breakpoint_position: Anchor,
10911        snapshot: &EditorSnapshot,
10912        cx: &mut Context<Self>,
10913    ) -> Option<(Anchor, Breakpoint)> {
10914        let buffer = self
10915            .buffer
10916            .read(cx)
10917            .buffer_for_anchor(breakpoint_position, cx)?;
10918
10919        let enclosing_excerpt = breakpoint_position.excerpt_id;
10920        let buffer_snapshot = buffer.read(cx).snapshot();
10921
10922        let row = buffer_snapshot
10923            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10924            .row;
10925
10926        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10927        let anchor_end = snapshot
10928            .buffer_snapshot()
10929            .anchor_after(Point::new(row, line_len));
10930
10931        self.breakpoint_store
10932            .as_ref()?
10933            .read_with(cx, |breakpoint_store, cx| {
10934                breakpoint_store
10935                    .breakpoints(
10936                        &buffer,
10937                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10938                        &buffer_snapshot,
10939                        cx,
10940                    )
10941                    .next()
10942                    .and_then(|(bp, _)| {
10943                        let breakpoint_row = buffer_snapshot
10944                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10945                            .row;
10946
10947                        if breakpoint_row == row {
10948                            snapshot
10949                                .buffer_snapshot()
10950                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10951                                .map(|position| (position, bp.bp.clone()))
10952                        } else {
10953                            None
10954                        }
10955                    })
10956            })
10957    }
10958
10959    pub fn edit_log_breakpoint(
10960        &mut self,
10961        _: &EditLogBreakpoint,
10962        window: &mut Window,
10963        cx: &mut Context<Self>,
10964    ) {
10965        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10966            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10967                message: None,
10968                state: BreakpointState::Enabled,
10969                condition: None,
10970                hit_condition: None,
10971            });
10972
10973            self.add_edit_breakpoint_block(
10974                anchor,
10975                &breakpoint,
10976                BreakpointPromptEditAction::Log,
10977                window,
10978                cx,
10979            );
10980        }
10981    }
10982
10983    fn breakpoints_at_cursors(
10984        &self,
10985        window: &mut Window,
10986        cx: &mut Context<Self>,
10987    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10988        let snapshot = self.snapshot(window, cx);
10989        let cursors = self
10990            .selections
10991            .disjoint_anchors_arc()
10992            .iter()
10993            .map(|selection| {
10994                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
10995
10996                let breakpoint_position = self
10997                    .breakpoint_at_row(cursor_position.row, window, cx)
10998                    .map(|bp| bp.0)
10999                    .unwrap_or_else(|| {
11000                        snapshot
11001                            .display_snapshot
11002                            .buffer_snapshot()
11003                            .anchor_after(Point::new(cursor_position.row, 0))
11004                    });
11005
11006                let breakpoint = self
11007                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11008                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11009
11010                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11011            })
11012            // 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.
11013            .collect::<HashMap<Anchor, _>>();
11014
11015        cursors.into_iter().collect()
11016    }
11017
11018    pub fn enable_breakpoint(
11019        &mut self,
11020        _: &crate::actions::EnableBreakpoint,
11021        window: &mut Window,
11022        cx: &mut Context<Self>,
11023    ) {
11024        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11025            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11026                continue;
11027            };
11028            self.edit_breakpoint_at_anchor(
11029                anchor,
11030                breakpoint,
11031                BreakpointEditAction::InvertState,
11032                cx,
11033            );
11034        }
11035    }
11036
11037    pub fn disable_breakpoint(
11038        &mut self,
11039        _: &crate::actions::DisableBreakpoint,
11040        window: &mut Window,
11041        cx: &mut Context<Self>,
11042    ) {
11043        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11044            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11045                continue;
11046            };
11047            self.edit_breakpoint_at_anchor(
11048                anchor,
11049                breakpoint,
11050                BreakpointEditAction::InvertState,
11051                cx,
11052            );
11053        }
11054    }
11055
11056    pub fn toggle_breakpoint(
11057        &mut self,
11058        _: &crate::actions::ToggleBreakpoint,
11059        window: &mut Window,
11060        cx: &mut Context<Self>,
11061    ) {
11062        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11063            if let Some(breakpoint) = breakpoint {
11064                self.edit_breakpoint_at_anchor(
11065                    anchor,
11066                    breakpoint,
11067                    BreakpointEditAction::Toggle,
11068                    cx,
11069                );
11070            } else {
11071                self.edit_breakpoint_at_anchor(
11072                    anchor,
11073                    Breakpoint::new_standard(),
11074                    BreakpointEditAction::Toggle,
11075                    cx,
11076                );
11077            }
11078        }
11079    }
11080
11081    pub fn edit_breakpoint_at_anchor(
11082        &mut self,
11083        breakpoint_position: Anchor,
11084        breakpoint: Breakpoint,
11085        edit_action: BreakpointEditAction,
11086        cx: &mut Context<Self>,
11087    ) {
11088        let Some(breakpoint_store) = &self.breakpoint_store else {
11089            return;
11090        };
11091
11092        let Some(buffer) = self
11093            .buffer
11094            .read(cx)
11095            .buffer_for_anchor(breakpoint_position, cx)
11096        else {
11097            return;
11098        };
11099
11100        breakpoint_store.update(cx, |breakpoint_store, cx| {
11101            breakpoint_store.toggle_breakpoint(
11102                buffer,
11103                BreakpointWithPosition {
11104                    position: breakpoint_position.text_anchor,
11105                    bp: breakpoint,
11106                },
11107                edit_action,
11108                cx,
11109            );
11110        });
11111
11112        cx.notify();
11113    }
11114
11115    #[cfg(any(test, feature = "test-support"))]
11116    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11117        self.breakpoint_store.clone()
11118    }
11119
11120    pub fn prepare_restore_change(
11121        &self,
11122        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11123        hunk: &MultiBufferDiffHunk,
11124        cx: &mut App,
11125    ) -> Option<()> {
11126        if hunk.is_created_file() {
11127            return None;
11128        }
11129        let buffer = self.buffer.read(cx);
11130        let diff = buffer.diff_for(hunk.buffer_id)?;
11131        let buffer = buffer.buffer(hunk.buffer_id)?;
11132        let buffer = buffer.read(cx);
11133        let original_text = diff
11134            .read(cx)
11135            .base_text()
11136            .as_rope()
11137            .slice(hunk.diff_base_byte_range.clone());
11138        let buffer_snapshot = buffer.snapshot();
11139        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11140        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11141            probe
11142                .0
11143                .start
11144                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11145                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11146        }) {
11147            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11148            Some(())
11149        } else {
11150            None
11151        }
11152    }
11153
11154    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11155        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11156    }
11157
11158    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11159        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11160    }
11161
11162    fn manipulate_lines<M>(
11163        &mut self,
11164        window: &mut Window,
11165        cx: &mut Context<Self>,
11166        mut manipulate: M,
11167    ) where
11168        M: FnMut(&str) -> LineManipulationResult,
11169    {
11170        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11171
11172        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11173        let buffer = self.buffer.read(cx).snapshot(cx);
11174
11175        let mut edits = Vec::new();
11176
11177        let selections = self.selections.all::<Point>(cx);
11178        let mut selections = selections.iter().peekable();
11179        let mut contiguous_row_selections = Vec::new();
11180        let mut new_selections = Vec::new();
11181        let mut added_lines = 0;
11182        let mut removed_lines = 0;
11183
11184        while let Some(selection) = selections.next() {
11185            let (start_row, end_row) = consume_contiguous_rows(
11186                &mut contiguous_row_selections,
11187                selection,
11188                &display_map,
11189                &mut selections,
11190            );
11191
11192            let start_point = Point::new(start_row.0, 0);
11193            let end_point = Point::new(
11194                end_row.previous_row().0,
11195                buffer.line_len(end_row.previous_row()),
11196            );
11197            let text = buffer
11198                .text_for_range(start_point..end_point)
11199                .collect::<String>();
11200
11201            let LineManipulationResult {
11202                new_text,
11203                line_count_before,
11204                line_count_after,
11205            } = manipulate(&text);
11206
11207            edits.push((start_point..end_point, new_text));
11208
11209            // Selections must change based on added and removed line count
11210            let start_row =
11211                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11212            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11213            new_selections.push(Selection {
11214                id: selection.id,
11215                start: start_row,
11216                end: end_row,
11217                goal: SelectionGoal::None,
11218                reversed: selection.reversed,
11219            });
11220
11221            if line_count_after > line_count_before {
11222                added_lines += line_count_after - line_count_before;
11223            } else if line_count_before > line_count_after {
11224                removed_lines += line_count_before - line_count_after;
11225            }
11226        }
11227
11228        self.transact(window, cx, |this, window, cx| {
11229            let buffer = this.buffer.update(cx, |buffer, cx| {
11230                buffer.edit(edits, None, cx);
11231                buffer.snapshot(cx)
11232            });
11233
11234            // Recalculate offsets on newly edited buffer
11235            let new_selections = new_selections
11236                .iter()
11237                .map(|s| {
11238                    let start_point = Point::new(s.start.0, 0);
11239                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11240                    Selection {
11241                        id: s.id,
11242                        start: buffer.point_to_offset(start_point),
11243                        end: buffer.point_to_offset(end_point),
11244                        goal: s.goal,
11245                        reversed: s.reversed,
11246                    }
11247                })
11248                .collect();
11249
11250            this.change_selections(Default::default(), window, cx, |s| {
11251                s.select(new_selections);
11252            });
11253
11254            this.request_autoscroll(Autoscroll::fit(), cx);
11255        });
11256    }
11257
11258    fn manipulate_immutable_lines<Fn>(
11259        &mut self,
11260        window: &mut Window,
11261        cx: &mut Context<Self>,
11262        mut callback: Fn,
11263    ) where
11264        Fn: FnMut(&mut Vec<&str>),
11265    {
11266        self.manipulate_lines(window, cx, |text| {
11267            let mut lines: Vec<&str> = text.split('\n').collect();
11268            let line_count_before = lines.len();
11269
11270            callback(&mut lines);
11271
11272            LineManipulationResult {
11273                new_text: lines.join("\n"),
11274                line_count_before,
11275                line_count_after: lines.len(),
11276            }
11277        });
11278    }
11279
11280    fn manipulate_mutable_lines<Fn>(
11281        &mut self,
11282        window: &mut Window,
11283        cx: &mut Context<Self>,
11284        mut callback: Fn,
11285    ) where
11286        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11287    {
11288        self.manipulate_lines(window, cx, |text| {
11289            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11290            let line_count_before = lines.len();
11291
11292            callback(&mut lines);
11293
11294            LineManipulationResult {
11295                new_text: lines.join("\n"),
11296                line_count_before,
11297                line_count_after: lines.len(),
11298            }
11299        });
11300    }
11301
11302    pub fn convert_indentation_to_spaces(
11303        &mut self,
11304        _: &ConvertIndentationToSpaces,
11305        window: &mut Window,
11306        cx: &mut Context<Self>,
11307    ) {
11308        let settings = self.buffer.read(cx).language_settings(cx);
11309        let tab_size = settings.tab_size.get() as usize;
11310
11311        self.manipulate_mutable_lines(window, cx, |lines| {
11312            // Allocates a reasonably sized scratch buffer once for the whole loop
11313            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11314            // Avoids recomputing spaces that could be inserted many times
11315            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11316                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11317                .collect();
11318
11319            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11320                let mut chars = line.as_ref().chars();
11321                let mut col = 0;
11322                let mut changed = false;
11323
11324                for ch in chars.by_ref() {
11325                    match ch {
11326                        ' ' => {
11327                            reindented_line.push(' ');
11328                            col += 1;
11329                        }
11330                        '\t' => {
11331                            // \t are converted to spaces depending on the current column
11332                            let spaces_len = tab_size - (col % tab_size);
11333                            reindented_line.extend(&space_cache[spaces_len - 1]);
11334                            col += spaces_len;
11335                            changed = true;
11336                        }
11337                        _ => {
11338                            // If we dont append before break, the character is consumed
11339                            reindented_line.push(ch);
11340                            break;
11341                        }
11342                    }
11343                }
11344
11345                if !changed {
11346                    reindented_line.clear();
11347                    continue;
11348                }
11349                // Append the rest of the line and replace old reference with new one
11350                reindented_line.extend(chars);
11351                *line = Cow::Owned(reindented_line.clone());
11352                reindented_line.clear();
11353            }
11354        });
11355    }
11356
11357    pub fn convert_indentation_to_tabs(
11358        &mut self,
11359        _: &ConvertIndentationToTabs,
11360        window: &mut Window,
11361        cx: &mut Context<Self>,
11362    ) {
11363        let settings = self.buffer.read(cx).language_settings(cx);
11364        let tab_size = settings.tab_size.get() as usize;
11365
11366        self.manipulate_mutable_lines(window, cx, |lines| {
11367            // Allocates a reasonably sized buffer once for the whole loop
11368            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11369            // Avoids recomputing spaces that could be inserted many times
11370            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11371                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11372                .collect();
11373
11374            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11375                let mut chars = line.chars();
11376                let mut spaces_count = 0;
11377                let mut first_non_indent_char = None;
11378                let mut changed = false;
11379
11380                for ch in chars.by_ref() {
11381                    match ch {
11382                        ' ' => {
11383                            // Keep track of spaces. Append \t when we reach tab_size
11384                            spaces_count += 1;
11385                            changed = true;
11386                            if spaces_count == tab_size {
11387                                reindented_line.push('\t');
11388                                spaces_count = 0;
11389                            }
11390                        }
11391                        '\t' => {
11392                            reindented_line.push('\t');
11393                            spaces_count = 0;
11394                        }
11395                        _ => {
11396                            // Dont append it yet, we might have remaining spaces
11397                            first_non_indent_char = Some(ch);
11398                            break;
11399                        }
11400                    }
11401                }
11402
11403                if !changed {
11404                    reindented_line.clear();
11405                    continue;
11406                }
11407                // Remaining spaces that didn't make a full tab stop
11408                if spaces_count > 0 {
11409                    reindented_line.extend(&space_cache[spaces_count - 1]);
11410                }
11411                // If we consume an extra character that was not indentation, add it back
11412                if let Some(extra_char) = first_non_indent_char {
11413                    reindented_line.push(extra_char);
11414                }
11415                // Append the rest of the line and replace old reference with new one
11416                reindented_line.extend(chars);
11417                *line = Cow::Owned(reindented_line.clone());
11418                reindented_line.clear();
11419            }
11420        });
11421    }
11422
11423    pub fn convert_to_upper_case(
11424        &mut self,
11425        _: &ConvertToUpperCase,
11426        window: &mut Window,
11427        cx: &mut Context<Self>,
11428    ) {
11429        self.manipulate_text(window, cx, |text| text.to_uppercase())
11430    }
11431
11432    pub fn convert_to_lower_case(
11433        &mut self,
11434        _: &ConvertToLowerCase,
11435        window: &mut Window,
11436        cx: &mut Context<Self>,
11437    ) {
11438        self.manipulate_text(window, cx, |text| text.to_lowercase())
11439    }
11440
11441    pub fn convert_to_title_case(
11442        &mut self,
11443        _: &ConvertToTitleCase,
11444        window: &mut Window,
11445        cx: &mut Context<Self>,
11446    ) {
11447        self.manipulate_text(window, cx, |text| {
11448            text.split('\n')
11449                .map(|line| line.to_case(Case::Title))
11450                .join("\n")
11451        })
11452    }
11453
11454    pub fn convert_to_snake_case(
11455        &mut self,
11456        _: &ConvertToSnakeCase,
11457        window: &mut Window,
11458        cx: &mut Context<Self>,
11459    ) {
11460        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11461    }
11462
11463    pub fn convert_to_kebab_case(
11464        &mut self,
11465        _: &ConvertToKebabCase,
11466        window: &mut Window,
11467        cx: &mut Context<Self>,
11468    ) {
11469        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11470    }
11471
11472    pub fn convert_to_upper_camel_case(
11473        &mut self,
11474        _: &ConvertToUpperCamelCase,
11475        window: &mut Window,
11476        cx: &mut Context<Self>,
11477    ) {
11478        self.manipulate_text(window, cx, |text| {
11479            text.split('\n')
11480                .map(|line| line.to_case(Case::UpperCamel))
11481                .join("\n")
11482        })
11483    }
11484
11485    pub fn convert_to_lower_camel_case(
11486        &mut self,
11487        _: &ConvertToLowerCamelCase,
11488        window: &mut Window,
11489        cx: &mut Context<Self>,
11490    ) {
11491        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11492    }
11493
11494    pub fn convert_to_opposite_case(
11495        &mut self,
11496        _: &ConvertToOppositeCase,
11497        window: &mut Window,
11498        cx: &mut Context<Self>,
11499    ) {
11500        self.manipulate_text(window, cx, |text| {
11501            text.chars()
11502                .fold(String::with_capacity(text.len()), |mut t, c| {
11503                    if c.is_uppercase() {
11504                        t.extend(c.to_lowercase());
11505                    } else {
11506                        t.extend(c.to_uppercase());
11507                    }
11508                    t
11509                })
11510        })
11511    }
11512
11513    pub fn convert_to_sentence_case(
11514        &mut self,
11515        _: &ConvertToSentenceCase,
11516        window: &mut Window,
11517        cx: &mut Context<Self>,
11518    ) {
11519        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11520    }
11521
11522    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11523        self.manipulate_text(window, cx, |text| {
11524            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11525            if has_upper_case_characters {
11526                text.to_lowercase()
11527            } else {
11528                text.to_uppercase()
11529            }
11530        })
11531    }
11532
11533    pub fn convert_to_rot13(
11534        &mut self,
11535        _: &ConvertToRot13,
11536        window: &mut Window,
11537        cx: &mut Context<Self>,
11538    ) {
11539        self.manipulate_text(window, cx, |text| {
11540            text.chars()
11541                .map(|c| match c {
11542                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11543                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11544                    _ => c,
11545                })
11546                .collect()
11547        })
11548    }
11549
11550    pub fn convert_to_rot47(
11551        &mut self,
11552        _: &ConvertToRot47,
11553        window: &mut Window,
11554        cx: &mut Context<Self>,
11555    ) {
11556        self.manipulate_text(window, cx, |text| {
11557            text.chars()
11558                .map(|c| {
11559                    let code_point = c as u32;
11560                    if code_point >= 33 && code_point <= 126 {
11561                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11562                    }
11563                    c
11564                })
11565                .collect()
11566        })
11567    }
11568
11569    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11570    where
11571        Fn: FnMut(&str) -> String,
11572    {
11573        let buffer = self.buffer.read(cx).snapshot(cx);
11574
11575        let mut new_selections = Vec::new();
11576        let mut edits = Vec::new();
11577        let mut selection_adjustment = 0i32;
11578
11579        for selection in self.selections.all_adjusted(cx) {
11580            let selection_is_empty = selection.is_empty();
11581
11582            let (start, end) = if selection_is_empty {
11583                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11584                (word_range.start, word_range.end)
11585            } else {
11586                (
11587                    buffer.point_to_offset(selection.start),
11588                    buffer.point_to_offset(selection.end),
11589                )
11590            };
11591
11592            let text = buffer.text_for_range(start..end).collect::<String>();
11593            let old_length = text.len() as i32;
11594            let text = callback(&text);
11595
11596            new_selections.push(Selection {
11597                start: (start as i32 - selection_adjustment) as usize,
11598                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11599                goal: SelectionGoal::None,
11600                id: selection.id,
11601                reversed: selection.reversed,
11602            });
11603
11604            selection_adjustment += old_length - text.len() as i32;
11605
11606            edits.push((start..end, text));
11607        }
11608
11609        self.transact(window, cx, |this, window, cx| {
11610            this.buffer.update(cx, |buffer, cx| {
11611                buffer.edit(edits, None, cx);
11612            });
11613
11614            this.change_selections(Default::default(), window, cx, |s| {
11615                s.select(new_selections);
11616            });
11617
11618            this.request_autoscroll(Autoscroll::fit(), cx);
11619        });
11620    }
11621
11622    pub fn move_selection_on_drop(
11623        &mut self,
11624        selection: &Selection<Anchor>,
11625        target: DisplayPoint,
11626        is_cut: bool,
11627        window: &mut Window,
11628        cx: &mut Context<Self>,
11629    ) {
11630        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11631        let buffer = display_map.buffer_snapshot();
11632        let mut edits = Vec::new();
11633        let insert_point = display_map
11634            .clip_point(target, Bias::Left)
11635            .to_point(&display_map);
11636        let text = buffer
11637            .text_for_range(selection.start..selection.end)
11638            .collect::<String>();
11639        if is_cut {
11640            edits.push(((selection.start..selection.end), String::new()));
11641        }
11642        let insert_anchor = buffer.anchor_before(insert_point);
11643        edits.push(((insert_anchor..insert_anchor), text));
11644        let last_edit_start = insert_anchor.bias_left(buffer);
11645        let last_edit_end = insert_anchor.bias_right(buffer);
11646        self.transact(window, cx, |this, window, cx| {
11647            this.buffer.update(cx, |buffer, cx| {
11648                buffer.edit(edits, None, cx);
11649            });
11650            this.change_selections(Default::default(), window, cx, |s| {
11651                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11652            });
11653        });
11654    }
11655
11656    pub fn clear_selection_drag_state(&mut self) {
11657        self.selection_drag_state = SelectionDragState::None;
11658    }
11659
11660    pub fn duplicate(
11661        &mut self,
11662        upwards: bool,
11663        whole_lines: bool,
11664        window: &mut Window,
11665        cx: &mut Context<Self>,
11666    ) {
11667        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11668
11669        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11670        let buffer = display_map.buffer_snapshot();
11671        let selections = self.selections.all::<Point>(cx);
11672
11673        let mut edits = Vec::new();
11674        let mut selections_iter = selections.iter().peekable();
11675        while let Some(selection) = selections_iter.next() {
11676            let mut rows = selection.spanned_rows(false, &display_map);
11677            // duplicate line-wise
11678            if whole_lines || selection.start == selection.end {
11679                // Avoid duplicating the same lines twice.
11680                while let Some(next_selection) = selections_iter.peek() {
11681                    let next_rows = next_selection.spanned_rows(false, &display_map);
11682                    if next_rows.start < rows.end {
11683                        rows.end = next_rows.end;
11684                        selections_iter.next().unwrap();
11685                    } else {
11686                        break;
11687                    }
11688                }
11689
11690                // Copy the text from the selected row region and splice it either at the start
11691                // or end of the region.
11692                let start = Point::new(rows.start.0, 0);
11693                let end = Point::new(
11694                    rows.end.previous_row().0,
11695                    buffer.line_len(rows.end.previous_row()),
11696                );
11697                let text = buffer
11698                    .text_for_range(start..end)
11699                    .chain(Some("\n"))
11700                    .collect::<String>();
11701                let insert_location = if upwards {
11702                    Point::new(rows.end.0, 0)
11703                } else {
11704                    start
11705                };
11706                edits.push((insert_location..insert_location, text));
11707            } else {
11708                // duplicate character-wise
11709                let start = selection.start;
11710                let end = selection.end;
11711                let text = buffer.text_for_range(start..end).collect::<String>();
11712                edits.push((selection.end..selection.end, text));
11713            }
11714        }
11715
11716        self.transact(window, cx, |this, _, cx| {
11717            this.buffer.update(cx, |buffer, cx| {
11718                buffer.edit(edits, None, cx);
11719            });
11720
11721            this.request_autoscroll(Autoscroll::fit(), cx);
11722        });
11723    }
11724
11725    pub fn duplicate_line_up(
11726        &mut self,
11727        _: &DuplicateLineUp,
11728        window: &mut Window,
11729        cx: &mut Context<Self>,
11730    ) {
11731        self.duplicate(true, true, window, cx);
11732    }
11733
11734    pub fn duplicate_line_down(
11735        &mut self,
11736        _: &DuplicateLineDown,
11737        window: &mut Window,
11738        cx: &mut Context<Self>,
11739    ) {
11740        self.duplicate(false, true, window, cx);
11741    }
11742
11743    pub fn duplicate_selection(
11744        &mut self,
11745        _: &DuplicateSelection,
11746        window: &mut Window,
11747        cx: &mut Context<Self>,
11748    ) {
11749        self.duplicate(false, false, window, cx);
11750    }
11751
11752    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11753        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11754        if self.mode.is_single_line() {
11755            cx.propagate();
11756            return;
11757        }
11758
11759        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11760        let buffer = self.buffer.read(cx).snapshot(cx);
11761
11762        let mut edits = Vec::new();
11763        let mut unfold_ranges = Vec::new();
11764        let mut refold_creases = Vec::new();
11765
11766        let selections = self.selections.all::<Point>(cx);
11767        let mut selections = selections.iter().peekable();
11768        let mut contiguous_row_selections = Vec::new();
11769        let mut new_selections = Vec::new();
11770
11771        while let Some(selection) = selections.next() {
11772            // Find all the selections that span a contiguous row range
11773            let (start_row, end_row) = consume_contiguous_rows(
11774                &mut contiguous_row_selections,
11775                selection,
11776                &display_map,
11777                &mut selections,
11778            );
11779
11780            // Move the text spanned by the row range to be before the line preceding the row range
11781            if start_row.0 > 0 {
11782                let range_to_move = Point::new(
11783                    start_row.previous_row().0,
11784                    buffer.line_len(start_row.previous_row()),
11785                )
11786                    ..Point::new(
11787                        end_row.previous_row().0,
11788                        buffer.line_len(end_row.previous_row()),
11789                    );
11790                let insertion_point = display_map
11791                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11792                    .0;
11793
11794                // Don't move lines across excerpts
11795                if buffer
11796                    .excerpt_containing(insertion_point..range_to_move.end)
11797                    .is_some()
11798                {
11799                    let text = buffer
11800                        .text_for_range(range_to_move.clone())
11801                        .flat_map(|s| s.chars())
11802                        .skip(1)
11803                        .chain(['\n'])
11804                        .collect::<String>();
11805
11806                    edits.push((
11807                        buffer.anchor_after(range_to_move.start)
11808                            ..buffer.anchor_before(range_to_move.end),
11809                        String::new(),
11810                    ));
11811                    let insertion_anchor = buffer.anchor_after(insertion_point);
11812                    edits.push((insertion_anchor..insertion_anchor, text));
11813
11814                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11815
11816                    // Move selections up
11817                    new_selections.extend(contiguous_row_selections.drain(..).map(
11818                        |mut selection| {
11819                            selection.start.row -= row_delta;
11820                            selection.end.row -= row_delta;
11821                            selection
11822                        },
11823                    ));
11824
11825                    // Move folds up
11826                    unfold_ranges.push(range_to_move.clone());
11827                    for fold in display_map.folds_in_range(
11828                        buffer.anchor_before(range_to_move.start)
11829                            ..buffer.anchor_after(range_to_move.end),
11830                    ) {
11831                        let mut start = fold.range.start.to_point(&buffer);
11832                        let mut end = fold.range.end.to_point(&buffer);
11833                        start.row -= row_delta;
11834                        end.row -= row_delta;
11835                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11836                    }
11837                }
11838            }
11839
11840            // If we didn't move line(s), preserve the existing selections
11841            new_selections.append(&mut contiguous_row_selections);
11842        }
11843
11844        self.transact(window, cx, |this, window, cx| {
11845            this.unfold_ranges(&unfold_ranges, true, true, cx);
11846            this.buffer.update(cx, |buffer, cx| {
11847                for (range, text) in edits {
11848                    buffer.edit([(range, text)], None, cx);
11849                }
11850            });
11851            this.fold_creases(refold_creases, true, window, cx);
11852            this.change_selections(Default::default(), window, cx, |s| {
11853                s.select(new_selections);
11854            })
11855        });
11856    }
11857
11858    pub fn move_line_down(
11859        &mut self,
11860        _: &MoveLineDown,
11861        window: &mut Window,
11862        cx: &mut Context<Self>,
11863    ) {
11864        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11865        if self.mode.is_single_line() {
11866            cx.propagate();
11867            return;
11868        }
11869
11870        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11871        let buffer = self.buffer.read(cx).snapshot(cx);
11872
11873        let mut edits = Vec::new();
11874        let mut unfold_ranges = Vec::new();
11875        let mut refold_creases = Vec::new();
11876
11877        let selections = self.selections.all::<Point>(cx);
11878        let mut selections = selections.iter().peekable();
11879        let mut contiguous_row_selections = Vec::new();
11880        let mut new_selections = Vec::new();
11881
11882        while let Some(selection) = selections.next() {
11883            // Find all the selections that span a contiguous row range
11884            let (start_row, end_row) = consume_contiguous_rows(
11885                &mut contiguous_row_selections,
11886                selection,
11887                &display_map,
11888                &mut selections,
11889            );
11890
11891            // Move the text spanned by the row range to be after the last line of the row range
11892            if end_row.0 <= buffer.max_point().row {
11893                let range_to_move =
11894                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11895                let insertion_point = display_map
11896                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11897                    .0;
11898
11899                // Don't move lines across excerpt boundaries
11900                if buffer
11901                    .excerpt_containing(range_to_move.start..insertion_point)
11902                    .is_some()
11903                {
11904                    let mut text = String::from("\n");
11905                    text.extend(buffer.text_for_range(range_to_move.clone()));
11906                    text.pop(); // Drop trailing newline
11907                    edits.push((
11908                        buffer.anchor_after(range_to_move.start)
11909                            ..buffer.anchor_before(range_to_move.end),
11910                        String::new(),
11911                    ));
11912                    let insertion_anchor = buffer.anchor_after(insertion_point);
11913                    edits.push((insertion_anchor..insertion_anchor, text));
11914
11915                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11916
11917                    // Move selections down
11918                    new_selections.extend(contiguous_row_selections.drain(..).map(
11919                        |mut selection| {
11920                            selection.start.row += row_delta;
11921                            selection.end.row += row_delta;
11922                            selection
11923                        },
11924                    ));
11925
11926                    // Move folds down
11927                    unfold_ranges.push(range_to_move.clone());
11928                    for fold in display_map.folds_in_range(
11929                        buffer.anchor_before(range_to_move.start)
11930                            ..buffer.anchor_after(range_to_move.end),
11931                    ) {
11932                        let mut start = fold.range.start.to_point(&buffer);
11933                        let mut end = fold.range.end.to_point(&buffer);
11934                        start.row += row_delta;
11935                        end.row += row_delta;
11936                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11937                    }
11938                }
11939            }
11940
11941            // If we didn't move line(s), preserve the existing selections
11942            new_selections.append(&mut contiguous_row_selections);
11943        }
11944
11945        self.transact(window, cx, |this, window, cx| {
11946            this.unfold_ranges(&unfold_ranges, true, true, cx);
11947            this.buffer.update(cx, |buffer, cx| {
11948                for (range, text) in edits {
11949                    buffer.edit([(range, text)], None, cx);
11950                }
11951            });
11952            this.fold_creases(refold_creases, true, window, cx);
11953            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11954        });
11955    }
11956
11957    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11958        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11959        let text_layout_details = &self.text_layout_details(window);
11960        self.transact(window, cx, |this, window, cx| {
11961            let edits = this.change_selections(Default::default(), window, cx, |s| {
11962                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11963                s.move_with(|display_map, selection| {
11964                    if !selection.is_empty() {
11965                        return;
11966                    }
11967
11968                    let mut head = selection.head();
11969                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11970                    if head.column() == display_map.line_len(head.row()) {
11971                        transpose_offset = display_map
11972                            .buffer_snapshot()
11973                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11974                    }
11975
11976                    if transpose_offset == 0 {
11977                        return;
11978                    }
11979
11980                    *head.column_mut() += 1;
11981                    head = display_map.clip_point(head, Bias::Right);
11982                    let goal = SelectionGoal::HorizontalPosition(
11983                        display_map
11984                            .x_for_display_point(head, text_layout_details)
11985                            .into(),
11986                    );
11987                    selection.collapse_to(head, goal);
11988
11989                    let transpose_start = display_map
11990                        .buffer_snapshot()
11991                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11992                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11993                        let transpose_end = display_map
11994                            .buffer_snapshot()
11995                            .clip_offset(transpose_offset + 1, Bias::Right);
11996                        if let Some(ch) = display_map
11997                            .buffer_snapshot()
11998                            .chars_at(transpose_start)
11999                            .next()
12000                        {
12001                            edits.push((transpose_start..transpose_offset, String::new()));
12002                            edits.push((transpose_end..transpose_end, ch.to_string()));
12003                        }
12004                    }
12005                });
12006                edits
12007            });
12008            this.buffer
12009                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12010            let selections = this.selections.all::<usize>(cx);
12011            this.change_selections(Default::default(), window, cx, |s| {
12012                s.select(selections);
12013            });
12014        });
12015    }
12016
12017    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12018        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12019        if self.mode.is_single_line() {
12020            cx.propagate();
12021            return;
12022        }
12023
12024        self.rewrap_impl(RewrapOptions::default(), cx)
12025    }
12026
12027    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12028        let buffer = self.buffer.read(cx).snapshot(cx);
12029        let selections = self.selections.all::<Point>(cx);
12030
12031        #[derive(Clone, Debug, PartialEq)]
12032        enum CommentFormat {
12033            /// single line comment, with prefix for line
12034            Line(String),
12035            /// single line within a block comment, with prefix for line
12036            BlockLine(String),
12037            /// a single line of a block comment that includes the initial delimiter
12038            BlockCommentWithStart(BlockCommentConfig),
12039            /// a single line of a block comment that includes the ending delimiter
12040            BlockCommentWithEnd(BlockCommentConfig),
12041        }
12042
12043        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12044        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12045            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12046                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12047                .peekable();
12048
12049            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12050                row
12051            } else {
12052                return Vec::new();
12053            };
12054
12055            let language_settings = buffer.language_settings_at(selection.head(), cx);
12056            let language_scope = buffer.language_scope_at(selection.head());
12057
12058            let indent_and_prefix_for_row =
12059                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12060                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12061                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12062                        &language_scope
12063                    {
12064                        let indent_end = Point::new(row, indent.len);
12065                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12066                        let line_text_after_indent = buffer
12067                            .text_for_range(indent_end..line_end)
12068                            .collect::<String>();
12069
12070                        let is_within_comment_override = buffer
12071                            .language_scope_at(indent_end)
12072                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12073                        let comment_delimiters = if is_within_comment_override {
12074                            // we are within a comment syntax node, but we don't
12075                            // yet know what kind of comment: block, doc or line
12076                            match (
12077                                language_scope.documentation_comment(),
12078                                language_scope.block_comment(),
12079                            ) {
12080                                (Some(config), _) | (_, Some(config))
12081                                    if buffer.contains_str_at(indent_end, &config.start) =>
12082                                {
12083                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12084                                }
12085                                (Some(config), _) | (_, Some(config))
12086                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12087                                {
12088                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12089                                }
12090                                (Some(config), _) | (_, Some(config))
12091                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12092                                {
12093                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12094                                }
12095                                (_, _) => language_scope
12096                                    .line_comment_prefixes()
12097                                    .iter()
12098                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12099                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12100                            }
12101                        } else {
12102                            // we not in an overridden comment node, but we may
12103                            // be within a non-overridden line comment node
12104                            language_scope
12105                                .line_comment_prefixes()
12106                                .iter()
12107                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12108                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12109                        };
12110
12111                        let rewrap_prefix = language_scope
12112                            .rewrap_prefixes()
12113                            .iter()
12114                            .find_map(|prefix_regex| {
12115                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12116                                    if mat.start() == 0 {
12117                                        Some(mat.as_str().to_string())
12118                                    } else {
12119                                        None
12120                                    }
12121                                })
12122                            })
12123                            .flatten();
12124                        (comment_delimiters, rewrap_prefix)
12125                    } else {
12126                        (None, None)
12127                    };
12128                    (indent, comment_prefix, rewrap_prefix)
12129                };
12130
12131            let mut ranges = Vec::new();
12132            let from_empty_selection = selection.is_empty();
12133
12134            let mut current_range_start = first_row;
12135            let mut prev_row = first_row;
12136            let (
12137                mut current_range_indent,
12138                mut current_range_comment_delimiters,
12139                mut current_range_rewrap_prefix,
12140            ) = indent_and_prefix_for_row(first_row);
12141
12142            for row in non_blank_rows_iter.skip(1) {
12143                let has_paragraph_break = row > prev_row + 1;
12144
12145                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12146                    indent_and_prefix_for_row(row);
12147
12148                let has_indent_change = row_indent != current_range_indent;
12149                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12150
12151                let has_boundary_change = has_comment_change
12152                    || row_rewrap_prefix.is_some()
12153                    || (has_indent_change && current_range_comment_delimiters.is_some());
12154
12155                if has_paragraph_break || has_boundary_change {
12156                    ranges.push((
12157                        language_settings.clone(),
12158                        Point::new(current_range_start, 0)
12159                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12160                        current_range_indent,
12161                        current_range_comment_delimiters.clone(),
12162                        current_range_rewrap_prefix.clone(),
12163                        from_empty_selection,
12164                    ));
12165                    current_range_start = row;
12166                    current_range_indent = row_indent;
12167                    current_range_comment_delimiters = row_comment_delimiters;
12168                    current_range_rewrap_prefix = row_rewrap_prefix;
12169                }
12170                prev_row = row;
12171            }
12172
12173            ranges.push((
12174                language_settings.clone(),
12175                Point::new(current_range_start, 0)
12176                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12177                current_range_indent,
12178                current_range_comment_delimiters,
12179                current_range_rewrap_prefix,
12180                from_empty_selection,
12181            ));
12182
12183            ranges
12184        });
12185
12186        let mut edits = Vec::new();
12187        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12188
12189        for (
12190            language_settings,
12191            wrap_range,
12192            mut indent_size,
12193            comment_prefix,
12194            rewrap_prefix,
12195            from_empty_selection,
12196        ) in wrap_ranges
12197        {
12198            let mut start_row = wrap_range.start.row;
12199            let mut end_row = wrap_range.end.row;
12200
12201            // Skip selections that overlap with a range that has already been rewrapped.
12202            let selection_range = start_row..end_row;
12203            if rewrapped_row_ranges
12204                .iter()
12205                .any(|range| range.overlaps(&selection_range))
12206            {
12207                continue;
12208            }
12209
12210            let tab_size = language_settings.tab_size;
12211
12212            let (line_prefix, inside_comment) = match &comment_prefix {
12213                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12214                    (Some(prefix.as_str()), true)
12215                }
12216                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12217                    (Some(prefix.as_ref()), true)
12218                }
12219                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12220                    start: _,
12221                    end: _,
12222                    prefix,
12223                    tab_size,
12224                })) => {
12225                    indent_size.len += tab_size;
12226                    (Some(prefix.as_ref()), true)
12227                }
12228                None => (None, false),
12229            };
12230            let indent_prefix = indent_size.chars().collect::<String>();
12231            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12232
12233            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12234                RewrapBehavior::InComments => inside_comment,
12235                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12236                RewrapBehavior::Anywhere => true,
12237            };
12238
12239            let should_rewrap = options.override_language_settings
12240                || allow_rewrap_based_on_language
12241                || self.hard_wrap.is_some();
12242            if !should_rewrap {
12243                continue;
12244            }
12245
12246            if from_empty_selection {
12247                'expand_upwards: while start_row > 0 {
12248                    let prev_row = start_row - 1;
12249                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12250                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12251                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12252                    {
12253                        start_row = prev_row;
12254                    } else {
12255                        break 'expand_upwards;
12256                    }
12257                }
12258
12259                'expand_downwards: while end_row < buffer.max_point().row {
12260                    let next_row = end_row + 1;
12261                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12262                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12263                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12264                    {
12265                        end_row = next_row;
12266                    } else {
12267                        break 'expand_downwards;
12268                    }
12269                }
12270            }
12271
12272            let start = Point::new(start_row, 0);
12273            let start_offset = ToOffset::to_offset(&start, &buffer);
12274            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12275            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12276            let mut first_line_delimiter = None;
12277            let mut last_line_delimiter = None;
12278            let Some(lines_without_prefixes) = selection_text
12279                .lines()
12280                .enumerate()
12281                .map(|(ix, line)| {
12282                    let line_trimmed = line.trim_start();
12283                    if rewrap_prefix.is_some() && ix > 0 {
12284                        Ok(line_trimmed)
12285                    } else if let Some(
12286                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12287                            start,
12288                            prefix,
12289                            end,
12290                            tab_size,
12291                        })
12292                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12293                            start,
12294                            prefix,
12295                            end,
12296                            tab_size,
12297                        }),
12298                    ) = &comment_prefix
12299                    {
12300                        let line_trimmed = line_trimmed
12301                            .strip_prefix(start.as_ref())
12302                            .map(|s| {
12303                                let mut indent_size = indent_size;
12304                                indent_size.len -= tab_size;
12305                                let indent_prefix: String = indent_size.chars().collect();
12306                                first_line_delimiter = Some((indent_prefix, start));
12307                                s.trim_start()
12308                            })
12309                            .unwrap_or(line_trimmed);
12310                        let line_trimmed = line_trimmed
12311                            .strip_suffix(end.as_ref())
12312                            .map(|s| {
12313                                last_line_delimiter = Some(end);
12314                                s.trim_end()
12315                            })
12316                            .unwrap_or(line_trimmed);
12317                        let line_trimmed = line_trimmed
12318                            .strip_prefix(prefix.as_ref())
12319                            .unwrap_or(line_trimmed);
12320                        Ok(line_trimmed)
12321                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12322                        line_trimmed.strip_prefix(prefix).with_context(|| {
12323                            format!("line did not start with prefix {prefix:?}: {line:?}")
12324                        })
12325                    } else {
12326                        line_trimmed
12327                            .strip_prefix(&line_prefix.trim_start())
12328                            .with_context(|| {
12329                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12330                            })
12331                    }
12332                })
12333                .collect::<Result<Vec<_>, _>>()
12334                .log_err()
12335            else {
12336                continue;
12337            };
12338
12339            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12340                buffer
12341                    .language_settings_at(Point::new(start_row, 0), cx)
12342                    .preferred_line_length as usize
12343            });
12344
12345            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12346                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12347            } else {
12348                line_prefix.clone()
12349            };
12350
12351            let wrapped_text = {
12352                let mut wrapped_text = wrap_with_prefix(
12353                    line_prefix,
12354                    subsequent_lines_prefix,
12355                    lines_without_prefixes.join("\n"),
12356                    wrap_column,
12357                    tab_size,
12358                    options.preserve_existing_whitespace,
12359                );
12360
12361                if let Some((indent, delimiter)) = first_line_delimiter {
12362                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12363                }
12364                if let Some(last_line) = last_line_delimiter {
12365                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12366                }
12367
12368                wrapped_text
12369            };
12370
12371            // TODO: should always use char-based diff while still supporting cursor behavior that
12372            // matches vim.
12373            let mut diff_options = DiffOptions::default();
12374            if options.override_language_settings {
12375                diff_options.max_word_diff_len = 0;
12376                diff_options.max_word_diff_line_count = 0;
12377            } else {
12378                diff_options.max_word_diff_len = usize::MAX;
12379                diff_options.max_word_diff_line_count = usize::MAX;
12380            }
12381
12382            for (old_range, new_text) in
12383                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12384            {
12385                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12386                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12387                edits.push((edit_start..edit_end, new_text));
12388            }
12389
12390            rewrapped_row_ranges.push(start_row..=end_row);
12391        }
12392
12393        self.buffer
12394            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12395    }
12396
12397    pub fn cut_common(
12398        &mut self,
12399        cut_no_selection_line: bool,
12400        window: &mut Window,
12401        cx: &mut Context<Self>,
12402    ) -> ClipboardItem {
12403        let mut text = String::new();
12404        let buffer = self.buffer.read(cx).snapshot(cx);
12405        let mut selections = self.selections.all::<Point>(cx);
12406        let mut clipboard_selections = Vec::with_capacity(selections.len());
12407        {
12408            let max_point = buffer.max_point();
12409            let mut is_first = true;
12410            for selection in &mut selections {
12411                let is_entire_line =
12412                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12413                if is_entire_line {
12414                    selection.start = Point::new(selection.start.row, 0);
12415                    if !selection.is_empty() && selection.end.column == 0 {
12416                        selection.end = cmp::min(max_point, selection.end);
12417                    } else {
12418                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12419                    }
12420                    selection.goal = SelectionGoal::None;
12421                }
12422                if is_first {
12423                    is_first = false;
12424                } else {
12425                    text += "\n";
12426                }
12427                let mut len = 0;
12428                for chunk in buffer.text_for_range(selection.start..selection.end) {
12429                    text.push_str(chunk);
12430                    len += chunk.len();
12431                }
12432                clipboard_selections.push(ClipboardSelection {
12433                    len,
12434                    is_entire_line,
12435                    first_line_indent: buffer
12436                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12437                        .len,
12438                });
12439            }
12440        }
12441
12442        self.transact(window, cx, |this, window, cx| {
12443            this.change_selections(Default::default(), window, cx, |s| {
12444                s.select(selections);
12445            });
12446            this.insert("", window, cx);
12447        });
12448        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12449    }
12450
12451    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12452        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12453        let item = self.cut_common(true, window, cx);
12454        cx.write_to_clipboard(item);
12455    }
12456
12457    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12458        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12459        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12460            s.move_with(|snapshot, sel| {
12461                if sel.is_empty() {
12462                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12463                }
12464                if sel.is_empty() {
12465                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12466                }
12467            });
12468        });
12469        let item = self.cut_common(false, window, cx);
12470        cx.set_global(KillRing(item))
12471    }
12472
12473    pub fn kill_ring_yank(
12474        &mut self,
12475        _: &KillRingYank,
12476        window: &mut Window,
12477        cx: &mut Context<Self>,
12478    ) {
12479        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12480        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12481            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12482                (kill_ring.text().to_string(), kill_ring.metadata_json())
12483            } else {
12484                return;
12485            }
12486        } else {
12487            return;
12488        };
12489        self.do_paste(&text, metadata, false, window, cx);
12490    }
12491
12492    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12493        self.do_copy(true, cx);
12494    }
12495
12496    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12497        self.do_copy(false, cx);
12498    }
12499
12500    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12501        let selections = self.selections.all::<Point>(cx);
12502        let buffer = self.buffer.read(cx).read(cx);
12503        let mut text = String::new();
12504
12505        let mut clipboard_selections = Vec::with_capacity(selections.len());
12506        {
12507            let max_point = buffer.max_point();
12508            let mut is_first = true;
12509            for selection in &selections {
12510                let mut start = selection.start;
12511                let mut end = selection.end;
12512                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12513                if is_entire_line {
12514                    start = Point::new(start.row, 0);
12515                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12516                }
12517
12518                let mut trimmed_selections = Vec::new();
12519                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12520                    let row = MultiBufferRow(start.row);
12521                    let first_indent = buffer.indent_size_for_line(row);
12522                    if first_indent.len == 0 || start.column > first_indent.len {
12523                        trimmed_selections.push(start..end);
12524                    } else {
12525                        trimmed_selections.push(
12526                            Point::new(row.0, first_indent.len)
12527                                ..Point::new(row.0, buffer.line_len(row)),
12528                        );
12529                        for row in start.row + 1..=end.row {
12530                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12531                            if row == end.row {
12532                                line_len = end.column;
12533                            }
12534                            if line_len == 0 {
12535                                trimmed_selections
12536                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12537                                continue;
12538                            }
12539                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12540                            if row_indent_size.len >= first_indent.len {
12541                                trimmed_selections.push(
12542                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12543                                );
12544                            } else {
12545                                trimmed_selections.clear();
12546                                trimmed_selections.push(start..end);
12547                                break;
12548                            }
12549                        }
12550                    }
12551                } else {
12552                    trimmed_selections.push(start..end);
12553                }
12554
12555                for trimmed_range in trimmed_selections {
12556                    if is_first {
12557                        is_first = false;
12558                    } else {
12559                        text += "\n";
12560                    }
12561                    let mut len = 0;
12562                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12563                        text.push_str(chunk);
12564                        len += chunk.len();
12565                    }
12566                    clipboard_selections.push(ClipboardSelection {
12567                        len,
12568                        is_entire_line,
12569                        first_line_indent: buffer
12570                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12571                            .len,
12572                    });
12573                }
12574            }
12575        }
12576
12577        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12578            text,
12579            clipboard_selections,
12580        ));
12581    }
12582
12583    pub fn do_paste(
12584        &mut self,
12585        text: &String,
12586        clipboard_selections: Option<Vec<ClipboardSelection>>,
12587        handle_entire_lines: bool,
12588        window: &mut Window,
12589        cx: &mut Context<Self>,
12590    ) {
12591        if self.read_only(cx) {
12592            return;
12593        }
12594
12595        let clipboard_text = Cow::Borrowed(text.as_str());
12596
12597        self.transact(window, cx, |this, window, cx| {
12598            let had_active_edit_prediction = this.has_active_edit_prediction();
12599            let old_selections = this.selections.all::<usize>(cx);
12600            let cursor_offset = this.selections.last::<usize>(cx).head();
12601
12602            if let Some(mut clipboard_selections) = clipboard_selections {
12603                let all_selections_were_entire_line =
12604                    clipboard_selections.iter().all(|s| s.is_entire_line);
12605                let first_selection_indent_column =
12606                    clipboard_selections.first().map(|s| s.first_line_indent);
12607                if clipboard_selections.len() != old_selections.len() {
12608                    clipboard_selections.drain(..);
12609                }
12610                let mut auto_indent_on_paste = true;
12611
12612                this.buffer.update(cx, |buffer, cx| {
12613                    let snapshot = buffer.read(cx);
12614                    auto_indent_on_paste = snapshot
12615                        .language_settings_at(cursor_offset, cx)
12616                        .auto_indent_on_paste;
12617
12618                    let mut start_offset = 0;
12619                    let mut edits = Vec::new();
12620                    let mut original_indent_columns = Vec::new();
12621                    for (ix, selection) in old_selections.iter().enumerate() {
12622                        let to_insert;
12623                        let entire_line;
12624                        let original_indent_column;
12625                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12626                            let end_offset = start_offset + clipboard_selection.len;
12627                            to_insert = &clipboard_text[start_offset..end_offset];
12628                            entire_line = clipboard_selection.is_entire_line;
12629                            start_offset = end_offset + 1;
12630                            original_indent_column = Some(clipboard_selection.first_line_indent);
12631                        } else {
12632                            to_insert = &*clipboard_text;
12633                            entire_line = all_selections_were_entire_line;
12634                            original_indent_column = first_selection_indent_column
12635                        }
12636
12637                        let (range, to_insert) =
12638                            if selection.is_empty() && handle_entire_lines && entire_line {
12639                                // If the corresponding selection was empty when this slice of the
12640                                // clipboard text was written, then the entire line containing the
12641                                // selection was copied. If this selection is also currently empty,
12642                                // then paste the line before the current line of the buffer.
12643                                let column = selection.start.to_point(&snapshot).column as usize;
12644                                let line_start = selection.start - column;
12645                                (line_start..line_start, Cow::Borrowed(to_insert))
12646                            } else {
12647                                let language = snapshot.language_at(selection.head());
12648                                let range = selection.range();
12649                                if let Some(language) = language
12650                                    && language.name() == "Markdown".into()
12651                                {
12652                                    edit_for_markdown_paste(
12653                                        &snapshot,
12654                                        range,
12655                                        to_insert,
12656                                        url::Url::parse(to_insert).ok(),
12657                                    )
12658                                } else {
12659                                    (range, Cow::Borrowed(to_insert))
12660                                }
12661                            };
12662
12663                        edits.push((range, to_insert));
12664                        original_indent_columns.push(original_indent_column);
12665                    }
12666                    drop(snapshot);
12667
12668                    buffer.edit(
12669                        edits,
12670                        if auto_indent_on_paste {
12671                            Some(AutoindentMode::Block {
12672                                original_indent_columns,
12673                            })
12674                        } else {
12675                            None
12676                        },
12677                        cx,
12678                    );
12679                });
12680
12681                let selections = this.selections.all::<usize>(cx);
12682                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12683            } else {
12684                let url = url::Url::parse(&clipboard_text).ok();
12685
12686                let auto_indent_mode = if !clipboard_text.is_empty() {
12687                    Some(AutoindentMode::Block {
12688                        original_indent_columns: Vec::new(),
12689                    })
12690                } else {
12691                    None
12692                };
12693
12694                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12695                    let snapshot = buffer.snapshot(cx);
12696
12697                    let anchors = old_selections
12698                        .iter()
12699                        .map(|s| {
12700                            let anchor = snapshot.anchor_after(s.head());
12701                            s.map(|_| anchor)
12702                        })
12703                        .collect::<Vec<_>>();
12704
12705                    let mut edits = Vec::new();
12706
12707                    for selection in old_selections.iter() {
12708                        let language = snapshot.language_at(selection.head());
12709                        let range = selection.range();
12710
12711                        let (edit_range, edit_text) = if let Some(language) = language
12712                            && language.name() == "Markdown".into()
12713                        {
12714                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12715                        } else {
12716                            (range, clipboard_text.clone())
12717                        };
12718
12719                        edits.push((edit_range, edit_text));
12720                    }
12721
12722                    drop(snapshot);
12723                    buffer.edit(edits, auto_indent_mode, cx);
12724
12725                    anchors
12726                });
12727
12728                this.change_selections(Default::default(), window, cx, |s| {
12729                    s.select_anchors(selection_anchors);
12730                });
12731            }
12732
12733            let trigger_in_words =
12734                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12735
12736            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12737        });
12738    }
12739
12740    pub fn diff_clipboard_with_selection(
12741        &mut self,
12742        _: &DiffClipboardWithSelection,
12743        window: &mut Window,
12744        cx: &mut Context<Self>,
12745    ) {
12746        let selections = self.selections.all::<usize>(cx);
12747
12748        if selections.is_empty() {
12749            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12750            return;
12751        };
12752
12753        let clipboard_text = match cx.read_from_clipboard() {
12754            Some(item) => match item.entries().first() {
12755                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12756                _ => None,
12757            },
12758            None => None,
12759        };
12760
12761        let Some(clipboard_text) = clipboard_text else {
12762            log::warn!("Clipboard doesn't contain text.");
12763            return;
12764        };
12765
12766        window.dispatch_action(
12767            Box::new(DiffClipboardWithSelectionData {
12768                clipboard_text,
12769                editor: cx.entity(),
12770            }),
12771            cx,
12772        );
12773    }
12774
12775    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12776        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12777        if let Some(item) = cx.read_from_clipboard() {
12778            let entries = item.entries();
12779
12780            match entries.first() {
12781                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12782                // of all the pasted entries.
12783                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12784                    .do_paste(
12785                        clipboard_string.text(),
12786                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12787                        true,
12788                        window,
12789                        cx,
12790                    ),
12791                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12792            }
12793        }
12794    }
12795
12796    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12797        if self.read_only(cx) {
12798            return;
12799        }
12800
12801        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12802
12803        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12804            if let Some((selections, _)) =
12805                self.selection_history.transaction(transaction_id).cloned()
12806            {
12807                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12808                    s.select_anchors(selections.to_vec());
12809                });
12810            } else {
12811                log::error!(
12812                    "No entry in selection_history found for undo. \
12813                     This may correspond to a bug where undo does not update the selection. \
12814                     If this is occurring, please add details to \
12815                     https://github.com/zed-industries/zed/issues/22692"
12816                );
12817            }
12818            self.request_autoscroll(Autoscroll::fit(), cx);
12819            self.unmark_text(window, cx);
12820            self.refresh_edit_prediction(true, false, window, cx);
12821            cx.emit(EditorEvent::Edited { transaction_id });
12822            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12823        }
12824    }
12825
12826    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12827        if self.read_only(cx) {
12828            return;
12829        }
12830
12831        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12832
12833        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12834            if let Some((_, Some(selections))) =
12835                self.selection_history.transaction(transaction_id).cloned()
12836            {
12837                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12838                    s.select_anchors(selections.to_vec());
12839                });
12840            } else {
12841                log::error!(
12842                    "No entry in selection_history found for redo. \
12843                     This may correspond to a bug where undo does not update the selection. \
12844                     If this is occurring, please add details to \
12845                     https://github.com/zed-industries/zed/issues/22692"
12846                );
12847            }
12848            self.request_autoscroll(Autoscroll::fit(), cx);
12849            self.unmark_text(window, cx);
12850            self.refresh_edit_prediction(true, false, window, cx);
12851            cx.emit(EditorEvent::Edited { transaction_id });
12852        }
12853    }
12854
12855    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12856        self.buffer
12857            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12858    }
12859
12860    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12861        self.buffer
12862            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12863    }
12864
12865    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12866        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12867        self.change_selections(Default::default(), window, cx, |s| {
12868            s.move_with(|map, selection| {
12869                let cursor = if selection.is_empty() {
12870                    movement::left(map, selection.start)
12871                } else {
12872                    selection.start
12873                };
12874                selection.collapse_to(cursor, SelectionGoal::None);
12875            });
12876        })
12877    }
12878
12879    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12880        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12881        self.change_selections(Default::default(), window, cx, |s| {
12882            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12883        })
12884    }
12885
12886    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12887        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12888        self.change_selections(Default::default(), window, cx, |s| {
12889            s.move_with(|map, selection| {
12890                let cursor = if selection.is_empty() {
12891                    movement::right(map, selection.end)
12892                } else {
12893                    selection.end
12894                };
12895                selection.collapse_to(cursor, SelectionGoal::None)
12896            });
12897        })
12898    }
12899
12900    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12901        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12902        self.change_selections(Default::default(), window, cx, |s| {
12903            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12904        });
12905    }
12906
12907    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12908        if self.take_rename(true, window, cx).is_some() {
12909            return;
12910        }
12911
12912        if self.mode.is_single_line() {
12913            cx.propagate();
12914            return;
12915        }
12916
12917        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12918
12919        let text_layout_details = &self.text_layout_details(window);
12920        let selection_count = self.selections.count();
12921        let first_selection = self.selections.first_anchor();
12922
12923        self.change_selections(Default::default(), window, cx, |s| {
12924            s.move_with(|map, selection| {
12925                if !selection.is_empty() {
12926                    selection.goal = SelectionGoal::None;
12927                }
12928                let (cursor, goal) = movement::up(
12929                    map,
12930                    selection.start,
12931                    selection.goal,
12932                    false,
12933                    text_layout_details,
12934                );
12935                selection.collapse_to(cursor, goal);
12936            });
12937        });
12938
12939        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12940        {
12941            cx.propagate();
12942        }
12943    }
12944
12945    pub fn move_up_by_lines(
12946        &mut self,
12947        action: &MoveUpByLines,
12948        window: &mut Window,
12949        cx: &mut Context<Self>,
12950    ) {
12951        if self.take_rename(true, window, cx).is_some() {
12952            return;
12953        }
12954
12955        if self.mode.is_single_line() {
12956            cx.propagate();
12957            return;
12958        }
12959
12960        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12961
12962        let text_layout_details = &self.text_layout_details(window);
12963
12964        self.change_selections(Default::default(), window, cx, |s| {
12965            s.move_with(|map, selection| {
12966                if !selection.is_empty() {
12967                    selection.goal = SelectionGoal::None;
12968                }
12969                let (cursor, goal) = movement::up_by_rows(
12970                    map,
12971                    selection.start,
12972                    action.lines,
12973                    selection.goal,
12974                    false,
12975                    text_layout_details,
12976                );
12977                selection.collapse_to(cursor, goal);
12978            });
12979        })
12980    }
12981
12982    pub fn move_down_by_lines(
12983        &mut self,
12984        action: &MoveDownByLines,
12985        window: &mut Window,
12986        cx: &mut Context<Self>,
12987    ) {
12988        if self.take_rename(true, window, cx).is_some() {
12989            return;
12990        }
12991
12992        if self.mode.is_single_line() {
12993            cx.propagate();
12994            return;
12995        }
12996
12997        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12998
12999        let text_layout_details = &self.text_layout_details(window);
13000
13001        self.change_selections(Default::default(), window, cx, |s| {
13002            s.move_with(|map, selection| {
13003                if !selection.is_empty() {
13004                    selection.goal = SelectionGoal::None;
13005                }
13006                let (cursor, goal) = movement::down_by_rows(
13007                    map,
13008                    selection.start,
13009                    action.lines,
13010                    selection.goal,
13011                    false,
13012                    text_layout_details,
13013                );
13014                selection.collapse_to(cursor, goal);
13015            });
13016        })
13017    }
13018
13019    pub fn select_down_by_lines(
13020        &mut self,
13021        action: &SelectDownByLines,
13022        window: &mut Window,
13023        cx: &mut Context<Self>,
13024    ) {
13025        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13026        let text_layout_details = &self.text_layout_details(window);
13027        self.change_selections(Default::default(), window, cx, |s| {
13028            s.move_heads_with(|map, head, goal| {
13029                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13030            })
13031        })
13032    }
13033
13034    pub fn select_up_by_lines(
13035        &mut self,
13036        action: &SelectUpByLines,
13037        window: &mut Window,
13038        cx: &mut Context<Self>,
13039    ) {
13040        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13041        let text_layout_details = &self.text_layout_details(window);
13042        self.change_selections(Default::default(), window, cx, |s| {
13043            s.move_heads_with(|map, head, goal| {
13044                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13045            })
13046        })
13047    }
13048
13049    pub fn select_page_up(
13050        &mut self,
13051        _: &SelectPageUp,
13052        window: &mut Window,
13053        cx: &mut Context<Self>,
13054    ) {
13055        let Some(row_count) = self.visible_row_count() else {
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_heads_with(|map, head, goal| {
13065                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13066            })
13067        })
13068    }
13069
13070    pub fn move_page_up(
13071        &mut self,
13072        action: &MovePageUp,
13073        window: &mut Window,
13074        cx: &mut Context<Self>,
13075    ) {
13076        if self.take_rename(true, window, cx).is_some() {
13077            return;
13078        }
13079
13080        if self
13081            .context_menu
13082            .borrow_mut()
13083            .as_mut()
13084            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13085            .unwrap_or(false)
13086        {
13087            return;
13088        }
13089
13090        if matches!(self.mode, EditorMode::SingleLine) {
13091            cx.propagate();
13092            return;
13093        }
13094
13095        let Some(row_count) = self.visible_row_count() else {
13096            return;
13097        };
13098
13099        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13100
13101        let effects = if action.center_cursor {
13102            SelectionEffects::scroll(Autoscroll::center())
13103        } else {
13104            SelectionEffects::default()
13105        };
13106
13107        let text_layout_details = &self.text_layout_details(window);
13108
13109        self.change_selections(effects, window, cx, |s| {
13110            s.move_with(|map, selection| {
13111                if !selection.is_empty() {
13112                    selection.goal = SelectionGoal::None;
13113                }
13114                let (cursor, goal) = movement::up_by_rows(
13115                    map,
13116                    selection.end,
13117                    row_count,
13118                    selection.goal,
13119                    false,
13120                    text_layout_details,
13121                );
13122                selection.collapse_to(cursor, goal);
13123            });
13124        });
13125    }
13126
13127    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13128        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13129        let text_layout_details = &self.text_layout_details(window);
13130        self.change_selections(Default::default(), window, cx, |s| {
13131            s.move_heads_with(|map, head, goal| {
13132                movement::up(map, head, goal, false, text_layout_details)
13133            })
13134        })
13135    }
13136
13137    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13138        self.take_rename(true, window, cx);
13139
13140        if self.mode.is_single_line() {
13141            cx.propagate();
13142            return;
13143        }
13144
13145        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13146
13147        let text_layout_details = &self.text_layout_details(window);
13148        let selection_count = self.selections.count();
13149        let first_selection = self.selections.first_anchor();
13150
13151        self.change_selections(Default::default(), window, cx, |s| {
13152            s.move_with(|map, selection| {
13153                if !selection.is_empty() {
13154                    selection.goal = SelectionGoal::None;
13155                }
13156                let (cursor, goal) = movement::down(
13157                    map,
13158                    selection.end,
13159                    selection.goal,
13160                    false,
13161                    text_layout_details,
13162                );
13163                selection.collapse_to(cursor, goal);
13164            });
13165        });
13166
13167        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13168        {
13169            cx.propagate();
13170        }
13171    }
13172
13173    pub fn select_page_down(
13174        &mut self,
13175        _: &SelectPageDown,
13176        window: &mut Window,
13177        cx: &mut Context<Self>,
13178    ) {
13179        let Some(row_count) = self.visible_row_count() else {
13180            return;
13181        };
13182
13183        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13184
13185        let text_layout_details = &self.text_layout_details(window);
13186
13187        self.change_selections(Default::default(), window, cx, |s| {
13188            s.move_heads_with(|map, head, goal| {
13189                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13190            })
13191        })
13192    }
13193
13194    pub fn move_page_down(
13195        &mut self,
13196        action: &MovePageDown,
13197        window: &mut Window,
13198        cx: &mut Context<Self>,
13199    ) {
13200        if self.take_rename(true, window, cx).is_some() {
13201            return;
13202        }
13203
13204        if self
13205            .context_menu
13206            .borrow_mut()
13207            .as_mut()
13208            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13209            .unwrap_or(false)
13210        {
13211            return;
13212        }
13213
13214        if matches!(self.mode, EditorMode::SingleLine) {
13215            cx.propagate();
13216            return;
13217        }
13218
13219        let Some(row_count) = self.visible_row_count() else {
13220            return;
13221        };
13222
13223        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13224
13225        let effects = if action.center_cursor {
13226            SelectionEffects::scroll(Autoscroll::center())
13227        } else {
13228            SelectionEffects::default()
13229        };
13230
13231        let text_layout_details = &self.text_layout_details(window);
13232        self.change_selections(effects, window, cx, |s| {
13233            s.move_with(|map, selection| {
13234                if !selection.is_empty() {
13235                    selection.goal = SelectionGoal::None;
13236                }
13237                let (cursor, goal) = movement::down_by_rows(
13238                    map,
13239                    selection.end,
13240                    row_count,
13241                    selection.goal,
13242                    false,
13243                    text_layout_details,
13244                );
13245                selection.collapse_to(cursor, goal);
13246            });
13247        });
13248    }
13249
13250    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13251        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13252        let text_layout_details = &self.text_layout_details(window);
13253        self.change_selections(Default::default(), window, cx, |s| {
13254            s.move_heads_with(|map, head, goal| {
13255                movement::down(map, head, goal, false, text_layout_details)
13256            })
13257        });
13258    }
13259
13260    pub fn context_menu_first(
13261        &mut self,
13262        _: &ContextMenuFirst,
13263        window: &mut Window,
13264        cx: &mut Context<Self>,
13265    ) {
13266        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13267            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13268        }
13269    }
13270
13271    pub fn context_menu_prev(
13272        &mut self,
13273        _: &ContextMenuPrevious,
13274        window: &mut Window,
13275        cx: &mut Context<Self>,
13276    ) {
13277        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13278            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13279        }
13280    }
13281
13282    pub fn context_menu_next(
13283        &mut self,
13284        _: &ContextMenuNext,
13285        window: &mut Window,
13286        cx: &mut Context<Self>,
13287    ) {
13288        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13289            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13290        }
13291    }
13292
13293    pub fn context_menu_last(
13294        &mut self,
13295        _: &ContextMenuLast,
13296        window: &mut Window,
13297        cx: &mut Context<Self>,
13298    ) {
13299        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13300            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13301        }
13302    }
13303
13304    pub fn signature_help_prev(
13305        &mut self,
13306        _: &SignatureHelpPrevious,
13307        _: &mut Window,
13308        cx: &mut Context<Self>,
13309    ) {
13310        if let Some(popover) = self.signature_help_state.popover_mut() {
13311            if popover.current_signature == 0 {
13312                popover.current_signature = popover.signatures.len() - 1;
13313            } else {
13314                popover.current_signature -= 1;
13315            }
13316            cx.notify();
13317        }
13318    }
13319
13320    pub fn signature_help_next(
13321        &mut self,
13322        _: &SignatureHelpNext,
13323        _: &mut Window,
13324        cx: &mut Context<Self>,
13325    ) {
13326        if let Some(popover) = self.signature_help_state.popover_mut() {
13327            if popover.current_signature + 1 == popover.signatures.len() {
13328                popover.current_signature = 0;
13329            } else {
13330                popover.current_signature += 1;
13331            }
13332            cx.notify();
13333        }
13334    }
13335
13336    pub fn move_to_previous_word_start(
13337        &mut self,
13338        _: &MoveToPreviousWordStart,
13339        window: &mut Window,
13340        cx: &mut Context<Self>,
13341    ) {
13342        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13343        self.change_selections(Default::default(), window, cx, |s| {
13344            s.move_cursors_with(|map, head, _| {
13345                (
13346                    movement::previous_word_start(map, head),
13347                    SelectionGoal::None,
13348                )
13349            });
13350        })
13351    }
13352
13353    pub fn move_to_previous_subword_start(
13354        &mut self,
13355        _: &MoveToPreviousSubwordStart,
13356        window: &mut Window,
13357        cx: &mut Context<Self>,
13358    ) {
13359        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13360        self.change_selections(Default::default(), window, cx, |s| {
13361            s.move_cursors_with(|map, head, _| {
13362                (
13363                    movement::previous_subword_start(map, head),
13364                    SelectionGoal::None,
13365                )
13366            });
13367        })
13368    }
13369
13370    pub fn select_to_previous_word_start(
13371        &mut self,
13372        _: &SelectToPreviousWordStart,
13373        window: &mut Window,
13374        cx: &mut Context<Self>,
13375    ) {
13376        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13377        self.change_selections(Default::default(), window, cx, |s| {
13378            s.move_heads_with(|map, head, _| {
13379                (
13380                    movement::previous_word_start(map, head),
13381                    SelectionGoal::None,
13382                )
13383            });
13384        })
13385    }
13386
13387    pub fn select_to_previous_subword_start(
13388        &mut self,
13389        _: &SelectToPreviousSubwordStart,
13390        window: &mut Window,
13391        cx: &mut Context<Self>,
13392    ) {
13393        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13394        self.change_selections(Default::default(), window, cx, |s| {
13395            s.move_heads_with(|map, head, _| {
13396                (
13397                    movement::previous_subword_start(map, head),
13398                    SelectionGoal::None,
13399                )
13400            });
13401        })
13402    }
13403
13404    pub fn delete_to_previous_word_start(
13405        &mut self,
13406        action: &DeleteToPreviousWordStart,
13407        window: &mut Window,
13408        cx: &mut Context<Self>,
13409    ) {
13410        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13411        self.transact(window, cx, |this, window, cx| {
13412            this.select_autoclose_pair(window, cx);
13413            this.change_selections(Default::default(), window, cx, |s| {
13414                s.move_with(|map, selection| {
13415                    if selection.is_empty() {
13416                        let mut cursor = if action.ignore_newlines {
13417                            movement::previous_word_start(map, selection.head())
13418                        } else {
13419                            movement::previous_word_start_or_newline(map, selection.head())
13420                        };
13421                        cursor = movement::adjust_greedy_deletion(
13422                            map,
13423                            selection.head(),
13424                            cursor,
13425                            action.ignore_brackets,
13426                        );
13427                        selection.set_head(cursor, SelectionGoal::None);
13428                    }
13429                });
13430            });
13431            this.insert("", window, cx);
13432        });
13433    }
13434
13435    pub fn delete_to_previous_subword_start(
13436        &mut self,
13437        _: &DeleteToPreviousSubwordStart,
13438        window: &mut Window,
13439        cx: &mut Context<Self>,
13440    ) {
13441        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13442        self.transact(window, cx, |this, window, cx| {
13443            this.select_autoclose_pair(window, cx);
13444            this.change_selections(Default::default(), window, cx, |s| {
13445                s.move_with(|map, selection| {
13446                    if selection.is_empty() {
13447                        let mut cursor = movement::previous_subword_start(map, selection.head());
13448                        cursor =
13449                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13450                        selection.set_head(cursor, SelectionGoal::None);
13451                    }
13452                });
13453            });
13454            this.insert("", window, cx);
13455        });
13456    }
13457
13458    pub fn move_to_next_word_end(
13459        &mut self,
13460        _: &MoveToNextWordEnd,
13461        window: &mut Window,
13462        cx: &mut Context<Self>,
13463    ) {
13464        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13465        self.change_selections(Default::default(), window, cx, |s| {
13466            s.move_cursors_with(|map, head, _| {
13467                (movement::next_word_end(map, head), SelectionGoal::None)
13468            });
13469        })
13470    }
13471
13472    pub fn move_to_next_subword_end(
13473        &mut self,
13474        _: &MoveToNextSubwordEnd,
13475        window: &mut Window,
13476        cx: &mut Context<Self>,
13477    ) {
13478        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13479        self.change_selections(Default::default(), window, cx, |s| {
13480            s.move_cursors_with(|map, head, _| {
13481                (movement::next_subword_end(map, head), SelectionGoal::None)
13482            });
13483        })
13484    }
13485
13486    pub fn select_to_next_word_end(
13487        &mut self,
13488        _: &SelectToNextWordEnd,
13489        window: &mut Window,
13490        cx: &mut Context<Self>,
13491    ) {
13492        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13493        self.change_selections(Default::default(), window, cx, |s| {
13494            s.move_heads_with(|map, head, _| {
13495                (movement::next_word_end(map, head), SelectionGoal::None)
13496            });
13497        })
13498    }
13499
13500    pub fn select_to_next_subword_end(
13501        &mut self,
13502        _: &SelectToNextSubwordEnd,
13503        window: &mut Window,
13504        cx: &mut Context<Self>,
13505    ) {
13506        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13507        self.change_selections(Default::default(), window, cx, |s| {
13508            s.move_heads_with(|map, head, _| {
13509                (movement::next_subword_end(map, head), SelectionGoal::None)
13510            });
13511        })
13512    }
13513
13514    pub fn delete_to_next_word_end(
13515        &mut self,
13516        action: &DeleteToNextWordEnd,
13517        window: &mut Window,
13518        cx: &mut Context<Self>,
13519    ) {
13520        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13521        self.transact(window, cx, |this, window, cx| {
13522            this.change_selections(Default::default(), window, cx, |s| {
13523                s.move_with(|map, selection| {
13524                    if selection.is_empty() {
13525                        let mut cursor = if action.ignore_newlines {
13526                            movement::next_word_end(map, selection.head())
13527                        } else {
13528                            movement::next_word_end_or_newline(map, selection.head())
13529                        };
13530                        cursor = movement::adjust_greedy_deletion(
13531                            map,
13532                            selection.head(),
13533                            cursor,
13534                            action.ignore_brackets,
13535                        );
13536                        selection.set_head(cursor, SelectionGoal::None);
13537                    }
13538                });
13539            });
13540            this.insert("", window, cx);
13541        });
13542    }
13543
13544    pub fn delete_to_next_subword_end(
13545        &mut self,
13546        _: &DeleteToNextSubwordEnd,
13547        window: &mut Window,
13548        cx: &mut Context<Self>,
13549    ) {
13550        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13551        self.transact(window, cx, |this, window, cx| {
13552            this.change_selections(Default::default(), window, cx, |s| {
13553                s.move_with(|map, selection| {
13554                    if selection.is_empty() {
13555                        let mut cursor = movement::next_subword_end(map, selection.head());
13556                        cursor =
13557                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13558                        selection.set_head(cursor, SelectionGoal::None);
13559                    }
13560                });
13561            });
13562            this.insert("", window, cx);
13563        });
13564    }
13565
13566    pub fn move_to_beginning_of_line(
13567        &mut self,
13568        action: &MoveToBeginningOfLine,
13569        window: &mut Window,
13570        cx: &mut Context<Self>,
13571    ) {
13572        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13573        self.change_selections(Default::default(), window, cx, |s| {
13574            s.move_cursors_with(|map, head, _| {
13575                (
13576                    movement::indented_line_beginning(
13577                        map,
13578                        head,
13579                        action.stop_at_soft_wraps,
13580                        action.stop_at_indent,
13581                    ),
13582                    SelectionGoal::None,
13583                )
13584            });
13585        })
13586    }
13587
13588    pub fn select_to_beginning_of_line(
13589        &mut self,
13590        action: &SelectToBeginningOfLine,
13591        window: &mut Window,
13592        cx: &mut Context<Self>,
13593    ) {
13594        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13595        self.change_selections(Default::default(), window, cx, |s| {
13596            s.move_heads_with(|map, head, _| {
13597                (
13598                    movement::indented_line_beginning(
13599                        map,
13600                        head,
13601                        action.stop_at_soft_wraps,
13602                        action.stop_at_indent,
13603                    ),
13604                    SelectionGoal::None,
13605                )
13606            });
13607        });
13608    }
13609
13610    pub fn delete_to_beginning_of_line(
13611        &mut self,
13612        action: &DeleteToBeginningOfLine,
13613        window: &mut Window,
13614        cx: &mut Context<Self>,
13615    ) {
13616        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13617        self.transact(window, cx, |this, window, cx| {
13618            this.change_selections(Default::default(), window, cx, |s| {
13619                s.move_with(|_, selection| {
13620                    selection.reversed = true;
13621                });
13622            });
13623
13624            this.select_to_beginning_of_line(
13625                &SelectToBeginningOfLine {
13626                    stop_at_soft_wraps: false,
13627                    stop_at_indent: action.stop_at_indent,
13628                },
13629                window,
13630                cx,
13631            );
13632            this.backspace(&Backspace, window, cx);
13633        });
13634    }
13635
13636    pub fn move_to_end_of_line(
13637        &mut self,
13638        action: &MoveToEndOfLine,
13639        window: &mut Window,
13640        cx: &mut Context<Self>,
13641    ) {
13642        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13643        self.change_selections(Default::default(), window, cx, |s| {
13644            s.move_cursors_with(|map, head, _| {
13645                (
13646                    movement::line_end(map, head, action.stop_at_soft_wraps),
13647                    SelectionGoal::None,
13648                )
13649            });
13650        })
13651    }
13652
13653    pub fn select_to_end_of_line(
13654        &mut self,
13655        action: &SelectToEndOfLine,
13656        window: &mut Window,
13657        cx: &mut Context<Self>,
13658    ) {
13659        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13660        self.change_selections(Default::default(), window, cx, |s| {
13661            s.move_heads_with(|map, head, _| {
13662                (
13663                    movement::line_end(map, head, action.stop_at_soft_wraps),
13664                    SelectionGoal::None,
13665                )
13666            });
13667        })
13668    }
13669
13670    pub fn delete_to_end_of_line(
13671        &mut self,
13672        _: &DeleteToEndOfLine,
13673        window: &mut Window,
13674        cx: &mut Context<Self>,
13675    ) {
13676        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13677        self.transact(window, cx, |this, window, cx| {
13678            this.select_to_end_of_line(
13679                &SelectToEndOfLine {
13680                    stop_at_soft_wraps: false,
13681                },
13682                window,
13683                cx,
13684            );
13685            this.delete(&Delete, window, cx);
13686        });
13687    }
13688
13689    pub fn cut_to_end_of_line(
13690        &mut self,
13691        action: &CutToEndOfLine,
13692        window: &mut Window,
13693        cx: &mut Context<Self>,
13694    ) {
13695        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13696        self.transact(window, cx, |this, window, cx| {
13697            this.select_to_end_of_line(
13698                &SelectToEndOfLine {
13699                    stop_at_soft_wraps: false,
13700                },
13701                window,
13702                cx,
13703            );
13704            if !action.stop_at_newlines {
13705                this.change_selections(Default::default(), window, cx, |s| {
13706                    s.move_with(|_, sel| {
13707                        if sel.is_empty() {
13708                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13709                        }
13710                    });
13711                });
13712            }
13713            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13714            let item = this.cut_common(false, window, cx);
13715            cx.write_to_clipboard(item);
13716        });
13717    }
13718
13719    pub fn move_to_start_of_paragraph(
13720        &mut self,
13721        _: &MoveToStartOfParagraph,
13722        window: &mut Window,
13723        cx: &mut Context<Self>,
13724    ) {
13725        if matches!(self.mode, EditorMode::SingleLine) {
13726            cx.propagate();
13727            return;
13728        }
13729        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13730        self.change_selections(Default::default(), window, cx, |s| {
13731            s.move_with(|map, selection| {
13732                selection.collapse_to(
13733                    movement::start_of_paragraph(map, selection.head(), 1),
13734                    SelectionGoal::None,
13735                )
13736            });
13737        })
13738    }
13739
13740    pub fn move_to_end_of_paragraph(
13741        &mut self,
13742        _: &MoveToEndOfParagraph,
13743        window: &mut Window,
13744        cx: &mut Context<Self>,
13745    ) {
13746        if matches!(self.mode, EditorMode::SingleLine) {
13747            cx.propagate();
13748            return;
13749        }
13750        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13751        self.change_selections(Default::default(), window, cx, |s| {
13752            s.move_with(|map, selection| {
13753                selection.collapse_to(
13754                    movement::end_of_paragraph(map, selection.head(), 1),
13755                    SelectionGoal::None,
13756                )
13757            });
13758        })
13759    }
13760
13761    pub fn select_to_start_of_paragraph(
13762        &mut self,
13763        _: &SelectToStartOfParagraph,
13764        window: &mut Window,
13765        cx: &mut Context<Self>,
13766    ) {
13767        if matches!(self.mode, EditorMode::SingleLine) {
13768            cx.propagate();
13769            return;
13770        }
13771        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13772        self.change_selections(Default::default(), window, cx, |s| {
13773            s.move_heads_with(|map, head, _| {
13774                (
13775                    movement::start_of_paragraph(map, head, 1),
13776                    SelectionGoal::None,
13777                )
13778            });
13779        })
13780    }
13781
13782    pub fn select_to_end_of_paragraph(
13783        &mut self,
13784        _: &SelectToEndOfParagraph,
13785        window: &mut Window,
13786        cx: &mut Context<Self>,
13787    ) {
13788        if matches!(self.mode, EditorMode::SingleLine) {
13789            cx.propagate();
13790            return;
13791        }
13792        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13793        self.change_selections(Default::default(), window, cx, |s| {
13794            s.move_heads_with(|map, head, _| {
13795                (
13796                    movement::end_of_paragraph(map, head, 1),
13797                    SelectionGoal::None,
13798                )
13799            });
13800        })
13801    }
13802
13803    pub fn move_to_start_of_excerpt(
13804        &mut self,
13805        _: &MoveToStartOfExcerpt,
13806        window: &mut Window,
13807        cx: &mut Context<Self>,
13808    ) {
13809        if matches!(self.mode, EditorMode::SingleLine) {
13810            cx.propagate();
13811            return;
13812        }
13813        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13814        self.change_selections(Default::default(), window, cx, |s| {
13815            s.move_with(|map, selection| {
13816                selection.collapse_to(
13817                    movement::start_of_excerpt(
13818                        map,
13819                        selection.head(),
13820                        workspace::searchable::Direction::Prev,
13821                    ),
13822                    SelectionGoal::None,
13823                )
13824            });
13825        })
13826    }
13827
13828    pub fn move_to_start_of_next_excerpt(
13829        &mut self,
13830        _: &MoveToStartOfNextExcerpt,
13831        window: &mut Window,
13832        cx: &mut Context<Self>,
13833    ) {
13834        if matches!(self.mode, EditorMode::SingleLine) {
13835            cx.propagate();
13836            return;
13837        }
13838
13839        self.change_selections(Default::default(), window, cx, |s| {
13840            s.move_with(|map, selection| {
13841                selection.collapse_to(
13842                    movement::start_of_excerpt(
13843                        map,
13844                        selection.head(),
13845                        workspace::searchable::Direction::Next,
13846                    ),
13847                    SelectionGoal::None,
13848                )
13849            });
13850        })
13851    }
13852
13853    pub fn move_to_end_of_excerpt(
13854        &mut self,
13855        _: &MoveToEndOfExcerpt,
13856        window: &mut Window,
13857        cx: &mut Context<Self>,
13858    ) {
13859        if matches!(self.mode, EditorMode::SingleLine) {
13860            cx.propagate();
13861            return;
13862        }
13863        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13864        self.change_selections(Default::default(), window, cx, |s| {
13865            s.move_with(|map, selection| {
13866                selection.collapse_to(
13867                    movement::end_of_excerpt(
13868                        map,
13869                        selection.head(),
13870                        workspace::searchable::Direction::Next,
13871                    ),
13872                    SelectionGoal::None,
13873                )
13874            });
13875        })
13876    }
13877
13878    pub fn move_to_end_of_previous_excerpt(
13879        &mut self,
13880        _: &MoveToEndOfPreviousExcerpt,
13881        window: &mut Window,
13882        cx: &mut Context<Self>,
13883    ) {
13884        if matches!(self.mode, EditorMode::SingleLine) {
13885            cx.propagate();
13886            return;
13887        }
13888        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13889        self.change_selections(Default::default(), window, cx, |s| {
13890            s.move_with(|map, selection| {
13891                selection.collapse_to(
13892                    movement::end_of_excerpt(
13893                        map,
13894                        selection.head(),
13895                        workspace::searchable::Direction::Prev,
13896                    ),
13897                    SelectionGoal::None,
13898                )
13899            });
13900        })
13901    }
13902
13903    pub fn select_to_start_of_excerpt(
13904        &mut self,
13905        _: &SelectToStartOfExcerpt,
13906        window: &mut Window,
13907        cx: &mut Context<Self>,
13908    ) {
13909        if matches!(self.mode, EditorMode::SingleLine) {
13910            cx.propagate();
13911            return;
13912        }
13913        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13914        self.change_selections(Default::default(), window, cx, |s| {
13915            s.move_heads_with(|map, head, _| {
13916                (
13917                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13918                    SelectionGoal::None,
13919                )
13920            });
13921        })
13922    }
13923
13924    pub fn select_to_start_of_next_excerpt(
13925        &mut self,
13926        _: &SelectToStartOfNextExcerpt,
13927        window: &mut Window,
13928        cx: &mut Context<Self>,
13929    ) {
13930        if matches!(self.mode, EditorMode::SingleLine) {
13931            cx.propagate();
13932            return;
13933        }
13934        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13935        self.change_selections(Default::default(), window, cx, |s| {
13936            s.move_heads_with(|map, head, _| {
13937                (
13938                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13939                    SelectionGoal::None,
13940                )
13941            });
13942        })
13943    }
13944
13945    pub fn select_to_end_of_excerpt(
13946        &mut self,
13947        _: &SelectToEndOfExcerpt,
13948        window: &mut Window,
13949        cx: &mut Context<Self>,
13950    ) {
13951        if matches!(self.mode, EditorMode::SingleLine) {
13952            cx.propagate();
13953            return;
13954        }
13955        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13956        self.change_selections(Default::default(), window, cx, |s| {
13957            s.move_heads_with(|map, head, _| {
13958                (
13959                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13960                    SelectionGoal::None,
13961                )
13962            });
13963        })
13964    }
13965
13966    pub fn select_to_end_of_previous_excerpt(
13967        &mut self,
13968        _: &SelectToEndOfPreviousExcerpt,
13969        window: &mut Window,
13970        cx: &mut Context<Self>,
13971    ) {
13972        if matches!(self.mode, EditorMode::SingleLine) {
13973            cx.propagate();
13974            return;
13975        }
13976        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13977        self.change_selections(Default::default(), window, cx, |s| {
13978            s.move_heads_with(|map, head, _| {
13979                (
13980                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13981                    SelectionGoal::None,
13982                )
13983            });
13984        })
13985    }
13986
13987    pub fn move_to_beginning(
13988        &mut self,
13989        _: &MoveToBeginning,
13990        window: &mut Window,
13991        cx: &mut Context<Self>,
13992    ) {
13993        if matches!(self.mode, EditorMode::SingleLine) {
13994            cx.propagate();
13995            return;
13996        }
13997        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13998        self.change_selections(Default::default(), window, cx, |s| {
13999            s.select_ranges(vec![0..0]);
14000        });
14001    }
14002
14003    pub fn select_to_beginning(
14004        &mut self,
14005        _: &SelectToBeginning,
14006        window: &mut Window,
14007        cx: &mut Context<Self>,
14008    ) {
14009        let mut selection = self.selections.last::<Point>(cx);
14010        selection.set_head(Point::zero(), SelectionGoal::None);
14011        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14012        self.change_selections(Default::default(), window, cx, |s| {
14013            s.select(vec![selection]);
14014        });
14015    }
14016
14017    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14018        if matches!(self.mode, EditorMode::SingleLine) {
14019            cx.propagate();
14020            return;
14021        }
14022        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14023        let cursor = self.buffer.read(cx).read(cx).len();
14024        self.change_selections(Default::default(), window, cx, |s| {
14025            s.select_ranges(vec![cursor..cursor])
14026        });
14027    }
14028
14029    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14030        self.nav_history = nav_history;
14031    }
14032
14033    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14034        self.nav_history.as_ref()
14035    }
14036
14037    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14038        self.push_to_nav_history(
14039            self.selections.newest_anchor().head(),
14040            None,
14041            false,
14042            true,
14043            cx,
14044        );
14045    }
14046
14047    fn push_to_nav_history(
14048        &mut self,
14049        cursor_anchor: Anchor,
14050        new_position: Option<Point>,
14051        is_deactivate: bool,
14052        always: bool,
14053        cx: &mut Context<Self>,
14054    ) {
14055        if let Some(nav_history) = self.nav_history.as_mut() {
14056            let buffer = self.buffer.read(cx).read(cx);
14057            let cursor_position = cursor_anchor.to_point(&buffer);
14058            let scroll_state = self.scroll_manager.anchor();
14059            let scroll_top_row = scroll_state.top_row(&buffer);
14060            drop(buffer);
14061
14062            if let Some(new_position) = new_position {
14063                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14064                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14065                    return;
14066                }
14067            }
14068
14069            nav_history.push(
14070                Some(NavigationData {
14071                    cursor_anchor,
14072                    cursor_position,
14073                    scroll_anchor: scroll_state,
14074                    scroll_top_row,
14075                }),
14076                cx,
14077            );
14078            cx.emit(EditorEvent::PushedToNavHistory {
14079                anchor: cursor_anchor,
14080                is_deactivate,
14081            })
14082        }
14083    }
14084
14085    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14086        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14087        let buffer = self.buffer.read(cx).snapshot(cx);
14088        let mut selection = self.selections.first::<usize>(cx);
14089        selection.set_head(buffer.len(), SelectionGoal::None);
14090        self.change_selections(Default::default(), window, cx, |s| {
14091            s.select(vec![selection]);
14092        });
14093    }
14094
14095    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14096        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14097        let end = self.buffer.read(cx).read(cx).len();
14098        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14099            s.select_ranges(vec![0..end]);
14100        });
14101    }
14102
14103    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14104        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14105        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14106        let mut selections = self.selections.all::<Point>(cx);
14107        let max_point = display_map.buffer_snapshot().max_point();
14108        for selection in &mut selections {
14109            let rows = selection.spanned_rows(true, &display_map);
14110            selection.start = Point::new(rows.start.0, 0);
14111            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14112            selection.reversed = false;
14113        }
14114        self.change_selections(Default::default(), window, cx, |s| {
14115            s.select(selections);
14116        });
14117    }
14118
14119    pub fn split_selection_into_lines(
14120        &mut self,
14121        action: &SplitSelectionIntoLines,
14122        window: &mut Window,
14123        cx: &mut Context<Self>,
14124    ) {
14125        let selections = self
14126            .selections
14127            .all::<Point>(cx)
14128            .into_iter()
14129            .map(|selection| selection.start..selection.end)
14130            .collect::<Vec<_>>();
14131        self.unfold_ranges(&selections, true, true, cx);
14132
14133        let mut new_selection_ranges = Vec::new();
14134        {
14135            let buffer = self.buffer.read(cx).read(cx);
14136            for selection in selections {
14137                for row in selection.start.row..selection.end.row {
14138                    let line_start = Point::new(row, 0);
14139                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14140
14141                    if action.keep_selections {
14142                        // Keep the selection range for each line
14143                        let selection_start = if row == selection.start.row {
14144                            selection.start
14145                        } else {
14146                            line_start
14147                        };
14148                        new_selection_ranges.push(selection_start..line_end);
14149                    } else {
14150                        // Collapse to cursor at end of line
14151                        new_selection_ranges.push(line_end..line_end);
14152                    }
14153                }
14154
14155                let is_multiline_selection = selection.start.row != selection.end.row;
14156                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14157                // so this action feels more ergonomic when paired with other selection operations
14158                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14159                if !should_skip_last {
14160                    if action.keep_selections {
14161                        if is_multiline_selection {
14162                            let line_start = Point::new(selection.end.row, 0);
14163                            new_selection_ranges.push(line_start..selection.end);
14164                        } else {
14165                            new_selection_ranges.push(selection.start..selection.end);
14166                        }
14167                    } else {
14168                        new_selection_ranges.push(selection.end..selection.end);
14169                    }
14170                }
14171            }
14172        }
14173        self.change_selections(Default::default(), window, cx, |s| {
14174            s.select_ranges(new_selection_ranges);
14175        });
14176    }
14177
14178    pub fn add_selection_above(
14179        &mut self,
14180        _: &AddSelectionAbove,
14181        window: &mut Window,
14182        cx: &mut Context<Self>,
14183    ) {
14184        self.add_selection(true, window, cx);
14185    }
14186
14187    pub fn add_selection_below(
14188        &mut self,
14189        _: &AddSelectionBelow,
14190        window: &mut Window,
14191        cx: &mut Context<Self>,
14192    ) {
14193        self.add_selection(false, window, cx);
14194    }
14195
14196    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14197        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14198
14199        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14200        let all_selections = self.selections.all::<Point>(cx);
14201        let text_layout_details = self.text_layout_details(window);
14202
14203        let (mut columnar_selections, new_selections_to_columnarize) = {
14204            if let Some(state) = self.add_selections_state.as_ref() {
14205                let columnar_selection_ids: HashSet<_> = state
14206                    .groups
14207                    .iter()
14208                    .flat_map(|group| group.stack.iter())
14209                    .copied()
14210                    .collect();
14211
14212                all_selections
14213                    .into_iter()
14214                    .partition(|s| columnar_selection_ids.contains(&s.id))
14215            } else {
14216                (Vec::new(), all_selections)
14217            }
14218        };
14219
14220        let mut state = self
14221            .add_selections_state
14222            .take()
14223            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14224
14225        for selection in new_selections_to_columnarize {
14226            let range = selection.display_range(&display_map).sorted();
14227            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14228            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14229            let positions = start_x.min(end_x)..start_x.max(end_x);
14230            let mut stack = Vec::new();
14231            for row in range.start.row().0..=range.end.row().0 {
14232                if let Some(selection) = self.selections.build_columnar_selection(
14233                    &display_map,
14234                    DisplayRow(row),
14235                    &positions,
14236                    selection.reversed,
14237                    &text_layout_details,
14238                ) {
14239                    stack.push(selection.id);
14240                    columnar_selections.push(selection);
14241                }
14242            }
14243            if !stack.is_empty() {
14244                if above {
14245                    stack.reverse();
14246                }
14247                state.groups.push(AddSelectionsGroup { above, stack });
14248            }
14249        }
14250
14251        let mut final_selections = Vec::new();
14252        let end_row = if above {
14253            DisplayRow(0)
14254        } else {
14255            display_map.max_point().row()
14256        };
14257
14258        let mut last_added_item_per_group = HashMap::default();
14259        for group in state.groups.iter_mut() {
14260            if let Some(last_id) = group.stack.last() {
14261                last_added_item_per_group.insert(*last_id, group);
14262            }
14263        }
14264
14265        for selection in columnar_selections {
14266            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14267                if above == group.above {
14268                    let range = selection.display_range(&display_map).sorted();
14269                    debug_assert_eq!(range.start.row(), range.end.row());
14270                    let mut row = range.start.row();
14271                    let positions =
14272                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14273                            Pixels::from(start)..Pixels::from(end)
14274                        } else {
14275                            let start_x =
14276                                display_map.x_for_display_point(range.start, &text_layout_details);
14277                            let end_x =
14278                                display_map.x_for_display_point(range.end, &text_layout_details);
14279                            start_x.min(end_x)..start_x.max(end_x)
14280                        };
14281
14282                    let mut maybe_new_selection = None;
14283                    while row != end_row {
14284                        if above {
14285                            row.0 -= 1;
14286                        } else {
14287                            row.0 += 1;
14288                        }
14289                        if let Some(new_selection) = self.selections.build_columnar_selection(
14290                            &display_map,
14291                            row,
14292                            &positions,
14293                            selection.reversed,
14294                            &text_layout_details,
14295                        ) {
14296                            maybe_new_selection = Some(new_selection);
14297                            break;
14298                        }
14299                    }
14300
14301                    if let Some(new_selection) = maybe_new_selection {
14302                        group.stack.push(new_selection.id);
14303                        if above {
14304                            final_selections.push(new_selection);
14305                            final_selections.push(selection);
14306                        } else {
14307                            final_selections.push(selection);
14308                            final_selections.push(new_selection);
14309                        }
14310                    } else {
14311                        final_selections.push(selection);
14312                    }
14313                } else {
14314                    group.stack.pop();
14315                }
14316            } else {
14317                final_selections.push(selection);
14318            }
14319        }
14320
14321        self.change_selections(Default::default(), window, cx, |s| {
14322            s.select(final_selections);
14323        });
14324
14325        let final_selection_ids: HashSet<_> = self
14326            .selections
14327            .all::<Point>(cx)
14328            .iter()
14329            .map(|s| s.id)
14330            .collect();
14331        state.groups.retain_mut(|group| {
14332            // selections might get merged above so we remove invalid items from stacks
14333            group.stack.retain(|id| final_selection_ids.contains(id));
14334
14335            // single selection in stack can be treated as initial state
14336            group.stack.len() > 1
14337        });
14338
14339        if !state.groups.is_empty() {
14340            self.add_selections_state = Some(state);
14341        }
14342    }
14343
14344    fn select_match_ranges(
14345        &mut self,
14346        range: Range<usize>,
14347        reversed: bool,
14348        replace_newest: bool,
14349        auto_scroll: Option<Autoscroll>,
14350        window: &mut Window,
14351        cx: &mut Context<Editor>,
14352    ) {
14353        self.unfold_ranges(
14354            std::slice::from_ref(&range),
14355            false,
14356            auto_scroll.is_some(),
14357            cx,
14358        );
14359        let effects = if let Some(scroll) = auto_scroll {
14360            SelectionEffects::scroll(scroll)
14361        } else {
14362            SelectionEffects::no_scroll()
14363        };
14364        self.change_selections(effects, window, cx, |s| {
14365            if replace_newest {
14366                s.delete(s.newest_anchor().id);
14367            }
14368            if reversed {
14369                s.insert_range(range.end..range.start);
14370            } else {
14371                s.insert_range(range);
14372            }
14373        });
14374    }
14375
14376    pub fn select_next_match_internal(
14377        &mut self,
14378        display_map: &DisplaySnapshot,
14379        replace_newest: bool,
14380        autoscroll: Option<Autoscroll>,
14381        window: &mut Window,
14382        cx: &mut Context<Self>,
14383    ) -> Result<()> {
14384        let buffer = display_map.buffer_snapshot();
14385        let mut selections = self.selections.all::<usize>(cx);
14386        if let Some(mut select_next_state) = self.select_next_state.take() {
14387            let query = &select_next_state.query;
14388            if !select_next_state.done {
14389                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14390                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14391                let mut next_selected_range = None;
14392
14393                let bytes_after_last_selection =
14394                    buffer.bytes_in_range(last_selection.end..buffer.len());
14395                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14396                let query_matches = query
14397                    .stream_find_iter(bytes_after_last_selection)
14398                    .map(|result| (last_selection.end, result))
14399                    .chain(
14400                        query
14401                            .stream_find_iter(bytes_before_first_selection)
14402                            .map(|result| (0, result)),
14403                    );
14404
14405                for (start_offset, query_match) in query_matches {
14406                    let query_match = query_match.unwrap(); // can only fail due to I/O
14407                    let offset_range =
14408                        start_offset + query_match.start()..start_offset + query_match.end();
14409
14410                    if !select_next_state.wordwise
14411                        || (!buffer.is_inside_word(offset_range.start, None)
14412                            && !buffer.is_inside_word(offset_range.end, None))
14413                    {
14414                        // TODO: This is n^2, because we might check all the selections
14415                        if !selections
14416                            .iter()
14417                            .any(|selection| selection.range().overlaps(&offset_range))
14418                        {
14419                            next_selected_range = Some(offset_range);
14420                            break;
14421                        }
14422                    }
14423                }
14424
14425                if let Some(next_selected_range) = next_selected_range {
14426                    self.select_match_ranges(
14427                        next_selected_range,
14428                        last_selection.reversed,
14429                        replace_newest,
14430                        autoscroll,
14431                        window,
14432                        cx,
14433                    );
14434                } else {
14435                    select_next_state.done = true;
14436                }
14437            }
14438
14439            self.select_next_state = Some(select_next_state);
14440        } else {
14441            let mut only_carets = true;
14442            let mut same_text_selected = true;
14443            let mut selected_text = None;
14444
14445            let mut selections_iter = selections.iter().peekable();
14446            while let Some(selection) = selections_iter.next() {
14447                if selection.start != selection.end {
14448                    only_carets = false;
14449                }
14450
14451                if same_text_selected {
14452                    if selected_text.is_none() {
14453                        selected_text =
14454                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14455                    }
14456
14457                    if let Some(next_selection) = selections_iter.peek() {
14458                        if next_selection.range().len() == selection.range().len() {
14459                            let next_selected_text = buffer
14460                                .text_for_range(next_selection.range())
14461                                .collect::<String>();
14462                            if Some(next_selected_text) != selected_text {
14463                                same_text_selected = false;
14464                                selected_text = None;
14465                            }
14466                        } else {
14467                            same_text_selected = false;
14468                            selected_text = None;
14469                        }
14470                    }
14471                }
14472            }
14473
14474            if only_carets {
14475                for selection in &mut selections {
14476                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14477                    selection.start = word_range.start;
14478                    selection.end = word_range.end;
14479                    selection.goal = SelectionGoal::None;
14480                    selection.reversed = false;
14481                    self.select_match_ranges(
14482                        selection.start..selection.end,
14483                        selection.reversed,
14484                        replace_newest,
14485                        autoscroll,
14486                        window,
14487                        cx,
14488                    );
14489                }
14490
14491                if selections.len() == 1 {
14492                    let selection = selections
14493                        .last()
14494                        .expect("ensured that there's only one selection");
14495                    let query = buffer
14496                        .text_for_range(selection.start..selection.end)
14497                        .collect::<String>();
14498                    let is_empty = query.is_empty();
14499                    let select_state = SelectNextState {
14500                        query: AhoCorasick::new(&[query])?,
14501                        wordwise: true,
14502                        done: is_empty,
14503                    };
14504                    self.select_next_state = Some(select_state);
14505                } else {
14506                    self.select_next_state = None;
14507                }
14508            } else if let Some(selected_text) = selected_text {
14509                self.select_next_state = Some(SelectNextState {
14510                    query: AhoCorasick::new(&[selected_text])?,
14511                    wordwise: false,
14512                    done: false,
14513                });
14514                self.select_next_match_internal(
14515                    display_map,
14516                    replace_newest,
14517                    autoscroll,
14518                    window,
14519                    cx,
14520                )?;
14521            }
14522        }
14523        Ok(())
14524    }
14525
14526    pub fn select_all_matches(
14527        &mut self,
14528        _action: &SelectAllMatches,
14529        window: &mut Window,
14530        cx: &mut Context<Self>,
14531    ) -> Result<()> {
14532        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14533
14534        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14535
14536        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14537        let Some(select_next_state) = self.select_next_state.as_mut() else {
14538            return Ok(());
14539        };
14540        if select_next_state.done {
14541            return Ok(());
14542        }
14543
14544        let mut new_selections = Vec::new();
14545
14546        let reversed = self.selections.oldest::<usize>(cx).reversed;
14547        let buffer = display_map.buffer_snapshot();
14548        let query_matches = select_next_state
14549            .query
14550            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14551
14552        for query_match in query_matches.into_iter() {
14553            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14554            let offset_range = if reversed {
14555                query_match.end()..query_match.start()
14556            } else {
14557                query_match.start()..query_match.end()
14558            };
14559
14560            if !select_next_state.wordwise
14561                || (!buffer.is_inside_word(offset_range.start, None)
14562                    && !buffer.is_inside_word(offset_range.end, None))
14563            {
14564                new_selections.push(offset_range.start..offset_range.end);
14565            }
14566        }
14567
14568        select_next_state.done = true;
14569
14570        if new_selections.is_empty() {
14571            log::error!("bug: new_selections is empty in select_all_matches");
14572            return Ok(());
14573        }
14574
14575        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14576        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14577            selections.select_ranges(new_selections)
14578        });
14579
14580        Ok(())
14581    }
14582
14583    pub fn select_next(
14584        &mut self,
14585        action: &SelectNext,
14586        window: &mut Window,
14587        cx: &mut Context<Self>,
14588    ) -> Result<()> {
14589        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14590        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14591        self.select_next_match_internal(
14592            &display_map,
14593            action.replace_newest,
14594            Some(Autoscroll::newest()),
14595            window,
14596            cx,
14597        )?;
14598        Ok(())
14599    }
14600
14601    pub fn select_previous(
14602        &mut self,
14603        action: &SelectPrevious,
14604        window: &mut Window,
14605        cx: &mut Context<Self>,
14606    ) -> Result<()> {
14607        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14608        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14609        let buffer = display_map.buffer_snapshot();
14610        let mut selections = self.selections.all::<usize>(cx);
14611        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14612            let query = &select_prev_state.query;
14613            if !select_prev_state.done {
14614                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14615                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14616                let mut next_selected_range = None;
14617                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14618                let bytes_before_last_selection =
14619                    buffer.reversed_bytes_in_range(0..last_selection.start);
14620                let bytes_after_first_selection =
14621                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14622                let query_matches = query
14623                    .stream_find_iter(bytes_before_last_selection)
14624                    .map(|result| (last_selection.start, result))
14625                    .chain(
14626                        query
14627                            .stream_find_iter(bytes_after_first_selection)
14628                            .map(|result| (buffer.len(), result)),
14629                    );
14630                for (end_offset, query_match) in query_matches {
14631                    let query_match = query_match.unwrap(); // can only fail due to I/O
14632                    let offset_range =
14633                        end_offset - query_match.end()..end_offset - query_match.start();
14634
14635                    if !select_prev_state.wordwise
14636                        || (!buffer.is_inside_word(offset_range.start, None)
14637                            && !buffer.is_inside_word(offset_range.end, None))
14638                    {
14639                        next_selected_range = Some(offset_range);
14640                        break;
14641                    }
14642                }
14643
14644                if let Some(next_selected_range) = next_selected_range {
14645                    self.select_match_ranges(
14646                        next_selected_range,
14647                        last_selection.reversed,
14648                        action.replace_newest,
14649                        Some(Autoscroll::newest()),
14650                        window,
14651                        cx,
14652                    );
14653                } else {
14654                    select_prev_state.done = true;
14655                }
14656            }
14657
14658            self.select_prev_state = Some(select_prev_state);
14659        } else {
14660            let mut only_carets = true;
14661            let mut same_text_selected = true;
14662            let mut selected_text = None;
14663
14664            let mut selections_iter = selections.iter().peekable();
14665            while let Some(selection) = selections_iter.next() {
14666                if selection.start != selection.end {
14667                    only_carets = false;
14668                }
14669
14670                if same_text_selected {
14671                    if selected_text.is_none() {
14672                        selected_text =
14673                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14674                    }
14675
14676                    if let Some(next_selection) = selections_iter.peek() {
14677                        if next_selection.range().len() == selection.range().len() {
14678                            let next_selected_text = buffer
14679                                .text_for_range(next_selection.range())
14680                                .collect::<String>();
14681                            if Some(next_selected_text) != selected_text {
14682                                same_text_selected = false;
14683                                selected_text = None;
14684                            }
14685                        } else {
14686                            same_text_selected = false;
14687                            selected_text = None;
14688                        }
14689                    }
14690                }
14691            }
14692
14693            if only_carets {
14694                for selection in &mut selections {
14695                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14696                    selection.start = word_range.start;
14697                    selection.end = word_range.end;
14698                    selection.goal = SelectionGoal::None;
14699                    selection.reversed = false;
14700                    self.select_match_ranges(
14701                        selection.start..selection.end,
14702                        selection.reversed,
14703                        action.replace_newest,
14704                        Some(Autoscroll::newest()),
14705                        window,
14706                        cx,
14707                    );
14708                }
14709                if selections.len() == 1 {
14710                    let selection = selections
14711                        .last()
14712                        .expect("ensured that there's only one selection");
14713                    let query = buffer
14714                        .text_for_range(selection.start..selection.end)
14715                        .collect::<String>();
14716                    let is_empty = query.is_empty();
14717                    let select_state = SelectNextState {
14718                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14719                        wordwise: true,
14720                        done: is_empty,
14721                    };
14722                    self.select_prev_state = Some(select_state);
14723                } else {
14724                    self.select_prev_state = None;
14725                }
14726            } else if let Some(selected_text) = selected_text {
14727                self.select_prev_state = Some(SelectNextState {
14728                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14729                    wordwise: false,
14730                    done: false,
14731                });
14732                self.select_previous(action, window, cx)?;
14733            }
14734        }
14735        Ok(())
14736    }
14737
14738    pub fn find_next_match(
14739        &mut self,
14740        _: &FindNextMatch,
14741        window: &mut Window,
14742        cx: &mut Context<Self>,
14743    ) -> Result<()> {
14744        let selections = self.selections.disjoint_anchors_arc();
14745        match selections.first() {
14746            Some(first) if selections.len() >= 2 => {
14747                self.change_selections(Default::default(), window, cx, |s| {
14748                    s.select_ranges([first.range()]);
14749                });
14750            }
14751            _ => self.select_next(
14752                &SelectNext {
14753                    replace_newest: true,
14754                },
14755                window,
14756                cx,
14757            )?,
14758        }
14759        Ok(())
14760    }
14761
14762    pub fn find_previous_match(
14763        &mut self,
14764        _: &FindPreviousMatch,
14765        window: &mut Window,
14766        cx: &mut Context<Self>,
14767    ) -> Result<()> {
14768        let selections = self.selections.disjoint_anchors_arc();
14769        match selections.last() {
14770            Some(last) if selections.len() >= 2 => {
14771                self.change_selections(Default::default(), window, cx, |s| {
14772                    s.select_ranges([last.range()]);
14773                });
14774            }
14775            _ => self.select_previous(
14776                &SelectPrevious {
14777                    replace_newest: true,
14778                },
14779                window,
14780                cx,
14781            )?,
14782        }
14783        Ok(())
14784    }
14785
14786    pub fn toggle_comments(
14787        &mut self,
14788        action: &ToggleComments,
14789        window: &mut Window,
14790        cx: &mut Context<Self>,
14791    ) {
14792        if self.read_only(cx) {
14793            return;
14794        }
14795        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14796        let text_layout_details = &self.text_layout_details(window);
14797        self.transact(window, cx, |this, window, cx| {
14798            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14799            let mut edits = Vec::new();
14800            let mut selection_edit_ranges = Vec::new();
14801            let mut last_toggled_row = None;
14802            let snapshot = this.buffer.read(cx).read(cx);
14803            let empty_str: Arc<str> = Arc::default();
14804            let mut suffixes_inserted = Vec::new();
14805            let ignore_indent = action.ignore_indent;
14806
14807            fn comment_prefix_range(
14808                snapshot: &MultiBufferSnapshot,
14809                row: MultiBufferRow,
14810                comment_prefix: &str,
14811                comment_prefix_whitespace: &str,
14812                ignore_indent: bool,
14813            ) -> Range<Point> {
14814                let indent_size = if ignore_indent {
14815                    0
14816                } else {
14817                    snapshot.indent_size_for_line(row).len
14818                };
14819
14820                let start = Point::new(row.0, indent_size);
14821
14822                let mut line_bytes = snapshot
14823                    .bytes_in_range(start..snapshot.max_point())
14824                    .flatten()
14825                    .copied();
14826
14827                // If this line currently begins with the line comment prefix, then record
14828                // the range containing the prefix.
14829                if line_bytes
14830                    .by_ref()
14831                    .take(comment_prefix.len())
14832                    .eq(comment_prefix.bytes())
14833                {
14834                    // Include any whitespace that matches the comment prefix.
14835                    let matching_whitespace_len = line_bytes
14836                        .zip(comment_prefix_whitespace.bytes())
14837                        .take_while(|(a, b)| a == b)
14838                        .count() as u32;
14839                    let end = Point::new(
14840                        start.row,
14841                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14842                    );
14843                    start..end
14844                } else {
14845                    start..start
14846                }
14847            }
14848
14849            fn comment_suffix_range(
14850                snapshot: &MultiBufferSnapshot,
14851                row: MultiBufferRow,
14852                comment_suffix: &str,
14853                comment_suffix_has_leading_space: bool,
14854            ) -> Range<Point> {
14855                let end = Point::new(row.0, snapshot.line_len(row));
14856                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14857
14858                let mut line_end_bytes = snapshot
14859                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14860                    .flatten()
14861                    .copied();
14862
14863                let leading_space_len = if suffix_start_column > 0
14864                    && line_end_bytes.next() == Some(b' ')
14865                    && comment_suffix_has_leading_space
14866                {
14867                    1
14868                } else {
14869                    0
14870                };
14871
14872                // If this line currently begins with the line comment prefix, then record
14873                // the range containing the prefix.
14874                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14875                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14876                    start..end
14877                } else {
14878                    end..end
14879                }
14880            }
14881
14882            // TODO: Handle selections that cross excerpts
14883            for selection in &mut selections {
14884                let start_column = snapshot
14885                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14886                    .len;
14887                let language = if let Some(language) =
14888                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14889                {
14890                    language
14891                } else {
14892                    continue;
14893                };
14894
14895                selection_edit_ranges.clear();
14896
14897                // If multiple selections contain a given row, avoid processing that
14898                // row more than once.
14899                let mut start_row = MultiBufferRow(selection.start.row);
14900                if last_toggled_row == Some(start_row) {
14901                    start_row = start_row.next_row();
14902                }
14903                let end_row =
14904                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14905                        MultiBufferRow(selection.end.row - 1)
14906                    } else {
14907                        MultiBufferRow(selection.end.row)
14908                    };
14909                last_toggled_row = Some(end_row);
14910
14911                if start_row > end_row {
14912                    continue;
14913                }
14914
14915                // If the language has line comments, toggle those.
14916                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14917
14918                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14919                if ignore_indent {
14920                    full_comment_prefixes = full_comment_prefixes
14921                        .into_iter()
14922                        .map(|s| Arc::from(s.trim_end()))
14923                        .collect();
14924                }
14925
14926                if !full_comment_prefixes.is_empty() {
14927                    let first_prefix = full_comment_prefixes
14928                        .first()
14929                        .expect("prefixes is non-empty");
14930                    let prefix_trimmed_lengths = full_comment_prefixes
14931                        .iter()
14932                        .map(|p| p.trim_end_matches(' ').len())
14933                        .collect::<SmallVec<[usize; 4]>>();
14934
14935                    let mut all_selection_lines_are_comments = true;
14936
14937                    for row in start_row.0..=end_row.0 {
14938                        let row = MultiBufferRow(row);
14939                        if start_row < end_row && snapshot.is_line_blank(row) {
14940                            continue;
14941                        }
14942
14943                        let prefix_range = full_comment_prefixes
14944                            .iter()
14945                            .zip(prefix_trimmed_lengths.iter().copied())
14946                            .map(|(prefix, trimmed_prefix_len)| {
14947                                comment_prefix_range(
14948                                    snapshot.deref(),
14949                                    row,
14950                                    &prefix[..trimmed_prefix_len],
14951                                    &prefix[trimmed_prefix_len..],
14952                                    ignore_indent,
14953                                )
14954                            })
14955                            .max_by_key(|range| range.end.column - range.start.column)
14956                            .expect("prefixes is non-empty");
14957
14958                        if prefix_range.is_empty() {
14959                            all_selection_lines_are_comments = false;
14960                        }
14961
14962                        selection_edit_ranges.push(prefix_range);
14963                    }
14964
14965                    if all_selection_lines_are_comments {
14966                        edits.extend(
14967                            selection_edit_ranges
14968                                .iter()
14969                                .cloned()
14970                                .map(|range| (range, empty_str.clone())),
14971                        );
14972                    } else {
14973                        let min_column = selection_edit_ranges
14974                            .iter()
14975                            .map(|range| range.start.column)
14976                            .min()
14977                            .unwrap_or(0);
14978                        edits.extend(selection_edit_ranges.iter().map(|range| {
14979                            let position = Point::new(range.start.row, min_column);
14980                            (position..position, first_prefix.clone())
14981                        }));
14982                    }
14983                } else if let Some(BlockCommentConfig {
14984                    start: full_comment_prefix,
14985                    end: comment_suffix,
14986                    ..
14987                }) = language.block_comment()
14988                {
14989                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14990                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14991                    let prefix_range = comment_prefix_range(
14992                        snapshot.deref(),
14993                        start_row,
14994                        comment_prefix,
14995                        comment_prefix_whitespace,
14996                        ignore_indent,
14997                    );
14998                    let suffix_range = comment_suffix_range(
14999                        snapshot.deref(),
15000                        end_row,
15001                        comment_suffix.trim_start_matches(' '),
15002                        comment_suffix.starts_with(' '),
15003                    );
15004
15005                    if prefix_range.is_empty() || suffix_range.is_empty() {
15006                        edits.push((
15007                            prefix_range.start..prefix_range.start,
15008                            full_comment_prefix.clone(),
15009                        ));
15010                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15011                        suffixes_inserted.push((end_row, comment_suffix.len()));
15012                    } else {
15013                        edits.push((prefix_range, empty_str.clone()));
15014                        edits.push((suffix_range, empty_str.clone()));
15015                    }
15016                } else {
15017                    continue;
15018                }
15019            }
15020
15021            drop(snapshot);
15022            this.buffer.update(cx, |buffer, cx| {
15023                buffer.edit(edits, None, cx);
15024            });
15025
15026            // Adjust selections so that they end before any comment suffixes that
15027            // were inserted.
15028            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15029            let mut selections = this.selections.all::<Point>(cx);
15030            let snapshot = this.buffer.read(cx).read(cx);
15031            for selection in &mut selections {
15032                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15033                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15034                        Ordering::Less => {
15035                            suffixes_inserted.next();
15036                            continue;
15037                        }
15038                        Ordering::Greater => break,
15039                        Ordering::Equal => {
15040                            if selection.end.column == snapshot.line_len(row) {
15041                                if selection.is_empty() {
15042                                    selection.start.column -= suffix_len as u32;
15043                                }
15044                                selection.end.column -= suffix_len as u32;
15045                            }
15046                            break;
15047                        }
15048                    }
15049                }
15050            }
15051
15052            drop(snapshot);
15053            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15054
15055            let selections = this.selections.all::<Point>(cx);
15056            let selections_on_single_row = selections.windows(2).all(|selections| {
15057                selections[0].start.row == selections[1].start.row
15058                    && selections[0].end.row == selections[1].end.row
15059                    && selections[0].start.row == selections[0].end.row
15060            });
15061            let selections_selecting = selections
15062                .iter()
15063                .any(|selection| selection.start != selection.end);
15064            let advance_downwards = action.advance_downwards
15065                && selections_on_single_row
15066                && !selections_selecting
15067                && !matches!(this.mode, EditorMode::SingleLine);
15068
15069            if advance_downwards {
15070                let snapshot = this.buffer.read(cx).snapshot(cx);
15071
15072                this.change_selections(Default::default(), window, cx, |s| {
15073                    s.move_cursors_with(|display_snapshot, display_point, _| {
15074                        let mut point = display_point.to_point(display_snapshot);
15075                        point.row += 1;
15076                        point = snapshot.clip_point(point, Bias::Left);
15077                        let display_point = point.to_display_point(display_snapshot);
15078                        let goal = SelectionGoal::HorizontalPosition(
15079                            display_snapshot
15080                                .x_for_display_point(display_point, text_layout_details)
15081                                .into(),
15082                        );
15083                        (display_point, goal)
15084                    })
15085                });
15086            }
15087        });
15088    }
15089
15090    pub fn select_enclosing_symbol(
15091        &mut self,
15092        _: &SelectEnclosingSymbol,
15093        window: &mut Window,
15094        cx: &mut Context<Self>,
15095    ) {
15096        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15097
15098        let buffer = self.buffer.read(cx).snapshot(cx);
15099        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
15100
15101        fn update_selection(
15102            selection: &Selection<usize>,
15103            buffer_snap: &MultiBufferSnapshot,
15104        ) -> Option<Selection<usize>> {
15105            let cursor = selection.head();
15106            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15107            for symbol in symbols.iter().rev() {
15108                let start = symbol.range.start.to_offset(buffer_snap);
15109                let end = symbol.range.end.to_offset(buffer_snap);
15110                let new_range = start..end;
15111                if start < selection.start || end > selection.end {
15112                    return Some(Selection {
15113                        id: selection.id,
15114                        start: new_range.start,
15115                        end: new_range.end,
15116                        goal: SelectionGoal::None,
15117                        reversed: selection.reversed,
15118                    });
15119                }
15120            }
15121            None
15122        }
15123
15124        let mut selected_larger_symbol = false;
15125        let new_selections = old_selections
15126            .iter()
15127            .map(|selection| match update_selection(selection, &buffer) {
15128                Some(new_selection) => {
15129                    if new_selection.range() != selection.range() {
15130                        selected_larger_symbol = true;
15131                    }
15132                    new_selection
15133                }
15134                None => selection.clone(),
15135            })
15136            .collect::<Vec<_>>();
15137
15138        if selected_larger_symbol {
15139            self.change_selections(Default::default(), window, cx, |s| {
15140                s.select(new_selections);
15141            });
15142        }
15143    }
15144
15145    pub fn select_larger_syntax_node(
15146        &mut self,
15147        _: &SelectLargerSyntaxNode,
15148        window: &mut Window,
15149        cx: &mut Context<Self>,
15150    ) {
15151        let Some(visible_row_count) = self.visible_row_count() else {
15152            return;
15153        };
15154        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15155        if old_selections.is_empty() {
15156            return;
15157        }
15158
15159        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15160
15161        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15162        let buffer = self.buffer.read(cx).snapshot(cx);
15163
15164        let mut selected_larger_node = false;
15165        let mut new_selections = old_selections
15166            .iter()
15167            .map(|selection| {
15168                let old_range = selection.start..selection.end;
15169
15170                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15171                    // manually select word at selection
15172                    if ["string_content", "inline"].contains(&node.kind()) {
15173                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15174                        // ignore if word is already selected
15175                        if !word_range.is_empty() && old_range != word_range {
15176                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15177                            // only select word if start and end point belongs to same word
15178                            if word_range == last_word_range {
15179                                selected_larger_node = true;
15180                                return Selection {
15181                                    id: selection.id,
15182                                    start: word_range.start,
15183                                    end: word_range.end,
15184                                    goal: SelectionGoal::None,
15185                                    reversed: selection.reversed,
15186                                };
15187                            }
15188                        }
15189                    }
15190                }
15191
15192                let mut new_range = old_range.clone();
15193                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15194                    new_range = range;
15195                    if !node.is_named() {
15196                        continue;
15197                    }
15198                    if !display_map.intersects_fold(new_range.start)
15199                        && !display_map.intersects_fold(new_range.end)
15200                    {
15201                        break;
15202                    }
15203                }
15204
15205                selected_larger_node |= new_range != old_range;
15206                Selection {
15207                    id: selection.id,
15208                    start: new_range.start,
15209                    end: new_range.end,
15210                    goal: SelectionGoal::None,
15211                    reversed: selection.reversed,
15212                }
15213            })
15214            .collect::<Vec<_>>();
15215
15216        if !selected_larger_node {
15217            return; // don't put this call in the history
15218        }
15219
15220        // scroll based on transformation done to the last selection created by the user
15221        let (last_old, last_new) = old_selections
15222            .last()
15223            .zip(new_selections.last().cloned())
15224            .expect("old_selections isn't empty");
15225
15226        // revert selection
15227        let is_selection_reversed = {
15228            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15229            new_selections.last_mut().expect("checked above").reversed =
15230                should_newest_selection_be_reversed;
15231            should_newest_selection_be_reversed
15232        };
15233
15234        if selected_larger_node {
15235            self.select_syntax_node_history.disable_clearing = true;
15236            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15237                s.select(new_selections.clone());
15238            });
15239            self.select_syntax_node_history.disable_clearing = false;
15240        }
15241
15242        let start_row = last_new.start.to_display_point(&display_map).row().0;
15243        let end_row = last_new.end.to_display_point(&display_map).row().0;
15244        let selection_height = end_row - start_row + 1;
15245        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15246
15247        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15248        let scroll_behavior = if fits_on_the_screen {
15249            self.request_autoscroll(Autoscroll::fit(), cx);
15250            SelectSyntaxNodeScrollBehavior::FitSelection
15251        } else if is_selection_reversed {
15252            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15253            SelectSyntaxNodeScrollBehavior::CursorTop
15254        } else {
15255            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15256            SelectSyntaxNodeScrollBehavior::CursorBottom
15257        };
15258
15259        self.select_syntax_node_history.push((
15260            old_selections,
15261            scroll_behavior,
15262            is_selection_reversed,
15263        ));
15264    }
15265
15266    pub fn select_smaller_syntax_node(
15267        &mut self,
15268        _: &SelectSmallerSyntaxNode,
15269        window: &mut Window,
15270        cx: &mut Context<Self>,
15271    ) {
15272        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15273
15274        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15275            self.select_syntax_node_history.pop()
15276        {
15277            if let Some(selection) = selections.last_mut() {
15278                selection.reversed = is_selection_reversed;
15279            }
15280
15281            self.select_syntax_node_history.disable_clearing = true;
15282            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15283                s.select(selections.to_vec());
15284            });
15285            self.select_syntax_node_history.disable_clearing = false;
15286
15287            match scroll_behavior {
15288                SelectSyntaxNodeScrollBehavior::CursorTop => {
15289                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15290                }
15291                SelectSyntaxNodeScrollBehavior::FitSelection => {
15292                    self.request_autoscroll(Autoscroll::fit(), cx);
15293                }
15294                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15295                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15296                }
15297            }
15298        }
15299    }
15300
15301    pub fn unwrap_syntax_node(
15302        &mut self,
15303        _: &UnwrapSyntaxNode,
15304        window: &mut Window,
15305        cx: &mut Context<Self>,
15306    ) {
15307        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15308
15309        let buffer = self.buffer.read(cx).snapshot(cx);
15310        let selections = self
15311            .selections
15312            .all::<usize>(cx)
15313            .into_iter()
15314            // subtracting the offset requires sorting
15315            .sorted_by_key(|i| i.start);
15316
15317        let full_edits = selections
15318            .into_iter()
15319            .filter_map(|selection| {
15320                let child = if selection.is_empty()
15321                    && let Some((_, ancestor_range)) =
15322                        buffer.syntax_ancestor(selection.start..selection.end)
15323                {
15324                    ancestor_range
15325                } else {
15326                    selection.range()
15327                };
15328
15329                let mut parent = child.clone();
15330                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15331                    parent = ancestor_range;
15332                    if parent.start < child.start || parent.end > child.end {
15333                        break;
15334                    }
15335                }
15336
15337                if parent == child {
15338                    return None;
15339                }
15340                let text = buffer.text_for_range(child).collect::<String>();
15341                Some((selection.id, parent, text))
15342            })
15343            .collect::<Vec<_>>();
15344        if full_edits.is_empty() {
15345            return;
15346        }
15347
15348        self.transact(window, cx, |this, window, cx| {
15349            this.buffer.update(cx, |buffer, cx| {
15350                buffer.edit(
15351                    full_edits
15352                        .iter()
15353                        .map(|(_, p, t)| (p.clone(), t.clone()))
15354                        .collect::<Vec<_>>(),
15355                    None,
15356                    cx,
15357                );
15358            });
15359            this.change_selections(Default::default(), window, cx, |s| {
15360                let mut offset = 0;
15361                let mut selections = vec![];
15362                for (id, parent, text) in full_edits {
15363                    let start = parent.start - offset;
15364                    offset += parent.len() - text.len();
15365                    selections.push(Selection {
15366                        id,
15367                        start,
15368                        end: start + text.len(),
15369                        reversed: false,
15370                        goal: Default::default(),
15371                    });
15372                }
15373                s.select(selections);
15374            });
15375        });
15376    }
15377
15378    pub fn select_next_syntax_node(
15379        &mut self,
15380        _: &SelectNextSyntaxNode,
15381        window: &mut Window,
15382        cx: &mut Context<Self>,
15383    ) {
15384        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15385        if old_selections.is_empty() {
15386            return;
15387        }
15388
15389        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15390
15391        let buffer = self.buffer.read(cx).snapshot(cx);
15392        let mut selected_sibling = false;
15393
15394        let new_selections = old_selections
15395            .iter()
15396            .map(|selection| {
15397                let old_range = selection.start..selection.end;
15398
15399                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15400                    let new_range = node.byte_range();
15401                    selected_sibling = true;
15402                    Selection {
15403                        id: selection.id,
15404                        start: new_range.start,
15405                        end: new_range.end,
15406                        goal: SelectionGoal::None,
15407                        reversed: selection.reversed,
15408                    }
15409                } else {
15410                    selection.clone()
15411                }
15412            })
15413            .collect::<Vec<_>>();
15414
15415        if selected_sibling {
15416            self.change_selections(
15417                SelectionEffects::scroll(Autoscroll::fit()),
15418                window,
15419                cx,
15420                |s| {
15421                    s.select(new_selections);
15422                },
15423            );
15424        }
15425    }
15426
15427    pub fn select_prev_syntax_node(
15428        &mut self,
15429        _: &SelectPreviousSyntaxNode,
15430        window: &mut Window,
15431        cx: &mut Context<Self>,
15432    ) {
15433        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15434        if old_selections.is_empty() {
15435            return;
15436        }
15437
15438        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15439
15440        let buffer = self.buffer.read(cx).snapshot(cx);
15441        let mut selected_sibling = false;
15442
15443        let new_selections = old_selections
15444            .iter()
15445            .map(|selection| {
15446                let old_range = selection.start..selection.end;
15447
15448                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15449                    let new_range = node.byte_range();
15450                    selected_sibling = true;
15451                    Selection {
15452                        id: selection.id,
15453                        start: new_range.start,
15454                        end: new_range.end,
15455                        goal: SelectionGoal::None,
15456                        reversed: selection.reversed,
15457                    }
15458                } else {
15459                    selection.clone()
15460                }
15461            })
15462            .collect::<Vec<_>>();
15463
15464        if selected_sibling {
15465            self.change_selections(
15466                SelectionEffects::scroll(Autoscroll::fit()),
15467                window,
15468                cx,
15469                |s| {
15470                    s.select(new_selections);
15471                },
15472            );
15473        }
15474    }
15475
15476    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15477        if !EditorSettings::get_global(cx).gutter.runnables {
15478            self.clear_tasks();
15479            return Task::ready(());
15480        }
15481        let project = self.project().map(Entity::downgrade);
15482        let task_sources = self.lsp_task_sources(cx);
15483        let multi_buffer = self.buffer.downgrade();
15484        cx.spawn_in(window, async move |editor, cx| {
15485            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15486            let Some(project) = project.and_then(|p| p.upgrade()) else {
15487                return;
15488            };
15489            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15490                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15491            }) else {
15492                return;
15493            };
15494
15495            let hide_runnables = project
15496                .update(cx, |project, _| project.is_via_collab())
15497                .unwrap_or(true);
15498            if hide_runnables {
15499                return;
15500            }
15501            let new_rows =
15502                cx.background_spawn({
15503                    let snapshot = display_snapshot.clone();
15504                    async move {
15505                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15506                    }
15507                })
15508                    .await;
15509            let Ok(lsp_tasks) =
15510                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15511            else {
15512                return;
15513            };
15514            let lsp_tasks = lsp_tasks.await;
15515
15516            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15517                lsp_tasks
15518                    .into_iter()
15519                    .flat_map(|(kind, tasks)| {
15520                        tasks.into_iter().filter_map(move |(location, task)| {
15521                            Some((kind.clone(), location?, task))
15522                        })
15523                    })
15524                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15525                        let buffer = location.target.buffer;
15526                        let buffer_snapshot = buffer.read(cx).snapshot();
15527                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15528                            |(excerpt_id, snapshot, _)| {
15529                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15530                                    display_snapshot
15531                                        .buffer_snapshot()
15532                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15533                                } else {
15534                                    None
15535                                }
15536                            },
15537                        );
15538                        if let Some(offset) = offset {
15539                            let task_buffer_range =
15540                                location.target.range.to_point(&buffer_snapshot);
15541                            let context_buffer_range =
15542                                task_buffer_range.to_offset(&buffer_snapshot);
15543                            let context_range = BufferOffset(context_buffer_range.start)
15544                                ..BufferOffset(context_buffer_range.end);
15545
15546                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15547                                .or_insert_with(|| RunnableTasks {
15548                                    templates: Vec::new(),
15549                                    offset,
15550                                    column: task_buffer_range.start.column,
15551                                    extra_variables: HashMap::default(),
15552                                    context_range,
15553                                })
15554                                .templates
15555                                .push((kind, task.original_task().clone()));
15556                        }
15557
15558                        acc
15559                    })
15560            }) else {
15561                return;
15562            };
15563
15564            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15565                buffer.language_settings(cx).tasks.prefer_lsp
15566            }) else {
15567                return;
15568            };
15569
15570            let rows = Self::runnable_rows(
15571                project,
15572                display_snapshot,
15573                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15574                new_rows,
15575                cx.clone(),
15576            )
15577            .await;
15578            editor
15579                .update(cx, |editor, _| {
15580                    editor.clear_tasks();
15581                    for (key, mut value) in rows {
15582                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15583                            value.templates.extend(lsp_tasks.templates);
15584                        }
15585
15586                        editor.insert_tasks(key, value);
15587                    }
15588                    for (key, value) in lsp_tasks_by_rows {
15589                        editor.insert_tasks(key, value);
15590                    }
15591                })
15592                .ok();
15593        })
15594    }
15595    fn fetch_runnable_ranges(
15596        snapshot: &DisplaySnapshot,
15597        range: Range<Anchor>,
15598    ) -> Vec<language::RunnableRange> {
15599        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15600    }
15601
15602    fn runnable_rows(
15603        project: Entity<Project>,
15604        snapshot: DisplaySnapshot,
15605        prefer_lsp: bool,
15606        runnable_ranges: Vec<RunnableRange>,
15607        cx: AsyncWindowContext,
15608    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15609        cx.spawn(async move |cx| {
15610            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15611            for mut runnable in runnable_ranges {
15612                let Some(tasks) = cx
15613                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15614                    .ok()
15615                else {
15616                    continue;
15617                };
15618                let mut tasks = tasks.await;
15619
15620                if prefer_lsp {
15621                    tasks.retain(|(task_kind, _)| {
15622                        !matches!(task_kind, TaskSourceKind::Language { .. })
15623                    });
15624                }
15625                if tasks.is_empty() {
15626                    continue;
15627                }
15628
15629                let point = runnable
15630                    .run_range
15631                    .start
15632                    .to_point(&snapshot.buffer_snapshot());
15633                let Some(row) = snapshot
15634                    .buffer_snapshot()
15635                    .buffer_line_for_row(MultiBufferRow(point.row))
15636                    .map(|(_, range)| range.start.row)
15637                else {
15638                    continue;
15639                };
15640
15641                let context_range =
15642                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15643                runnable_rows.push((
15644                    (runnable.buffer_id, row),
15645                    RunnableTasks {
15646                        templates: tasks,
15647                        offset: snapshot
15648                            .buffer_snapshot()
15649                            .anchor_before(runnable.run_range.start),
15650                        context_range,
15651                        column: point.column,
15652                        extra_variables: runnable.extra_captures,
15653                    },
15654                ));
15655            }
15656            runnable_rows
15657        })
15658    }
15659
15660    fn templates_with_tags(
15661        project: &Entity<Project>,
15662        runnable: &mut Runnable,
15663        cx: &mut App,
15664    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15665        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15666            let (worktree_id, file) = project
15667                .buffer_for_id(runnable.buffer, cx)
15668                .and_then(|buffer| buffer.read(cx).file())
15669                .map(|file| (file.worktree_id(cx), file.clone()))
15670                .unzip();
15671
15672            (
15673                project.task_store().read(cx).task_inventory().cloned(),
15674                worktree_id,
15675                file,
15676            )
15677        });
15678
15679        let tags = mem::take(&mut runnable.tags);
15680        let language = runnable.language.clone();
15681        cx.spawn(async move |cx| {
15682            let mut templates_with_tags = Vec::new();
15683            if let Some(inventory) = inventory {
15684                for RunnableTag(tag) in tags {
15685                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15686                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15687                    }) else {
15688                        return templates_with_tags;
15689                    };
15690                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15691                        move |(_, template)| {
15692                            template.tags.iter().any(|source_tag| source_tag == &tag)
15693                        },
15694                    ));
15695                }
15696            }
15697            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15698
15699            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15700                // Strongest source wins; if we have worktree tag binding, prefer that to
15701                // global and language bindings;
15702                // if we have a global binding, prefer that to language binding.
15703                let first_mismatch = templates_with_tags
15704                    .iter()
15705                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15706                if let Some(index) = first_mismatch {
15707                    templates_with_tags.truncate(index);
15708                }
15709            }
15710
15711            templates_with_tags
15712        })
15713    }
15714
15715    pub fn move_to_enclosing_bracket(
15716        &mut self,
15717        _: &MoveToEnclosingBracket,
15718        window: &mut Window,
15719        cx: &mut Context<Self>,
15720    ) {
15721        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15722        self.change_selections(Default::default(), window, cx, |s| {
15723            s.move_offsets_with(|snapshot, selection| {
15724                let Some(enclosing_bracket_ranges) =
15725                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15726                else {
15727                    return;
15728                };
15729
15730                let mut best_length = usize::MAX;
15731                let mut best_inside = false;
15732                let mut best_in_bracket_range = false;
15733                let mut best_destination = None;
15734                for (open, close) in enclosing_bracket_ranges {
15735                    let close = close.to_inclusive();
15736                    let length = close.end() - open.start;
15737                    let inside = selection.start >= open.end && selection.end <= *close.start();
15738                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15739                        || close.contains(&selection.head());
15740
15741                    // If best is next to a bracket and current isn't, skip
15742                    if !in_bracket_range && best_in_bracket_range {
15743                        continue;
15744                    }
15745
15746                    // Prefer smaller lengths unless best is inside and current isn't
15747                    if length > best_length && (best_inside || !inside) {
15748                        continue;
15749                    }
15750
15751                    best_length = length;
15752                    best_inside = inside;
15753                    best_in_bracket_range = in_bracket_range;
15754                    best_destination = Some(
15755                        if close.contains(&selection.start) && close.contains(&selection.end) {
15756                            if inside { open.end } else { open.start }
15757                        } else if inside {
15758                            *close.start()
15759                        } else {
15760                            *close.end()
15761                        },
15762                    );
15763                }
15764
15765                if let Some(destination) = best_destination {
15766                    selection.collapse_to(destination, SelectionGoal::None);
15767                }
15768            })
15769        });
15770    }
15771
15772    pub fn undo_selection(
15773        &mut self,
15774        _: &UndoSelection,
15775        window: &mut Window,
15776        cx: &mut Context<Self>,
15777    ) {
15778        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15779        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15780            self.selection_history.mode = SelectionHistoryMode::Undoing;
15781            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15782                this.end_selection(window, cx);
15783                this.change_selections(
15784                    SelectionEffects::scroll(Autoscroll::newest()),
15785                    window,
15786                    cx,
15787                    |s| s.select_anchors(entry.selections.to_vec()),
15788                );
15789            });
15790            self.selection_history.mode = SelectionHistoryMode::Normal;
15791
15792            self.select_next_state = entry.select_next_state;
15793            self.select_prev_state = entry.select_prev_state;
15794            self.add_selections_state = entry.add_selections_state;
15795        }
15796    }
15797
15798    pub fn redo_selection(
15799        &mut self,
15800        _: &RedoSelection,
15801        window: &mut Window,
15802        cx: &mut Context<Self>,
15803    ) {
15804        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15805        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15806            self.selection_history.mode = SelectionHistoryMode::Redoing;
15807            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15808                this.end_selection(window, cx);
15809                this.change_selections(
15810                    SelectionEffects::scroll(Autoscroll::newest()),
15811                    window,
15812                    cx,
15813                    |s| s.select_anchors(entry.selections.to_vec()),
15814                );
15815            });
15816            self.selection_history.mode = SelectionHistoryMode::Normal;
15817
15818            self.select_next_state = entry.select_next_state;
15819            self.select_prev_state = entry.select_prev_state;
15820            self.add_selections_state = entry.add_selections_state;
15821        }
15822    }
15823
15824    pub fn expand_excerpts(
15825        &mut self,
15826        action: &ExpandExcerpts,
15827        _: &mut Window,
15828        cx: &mut Context<Self>,
15829    ) {
15830        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15831    }
15832
15833    pub fn expand_excerpts_down(
15834        &mut self,
15835        action: &ExpandExcerptsDown,
15836        _: &mut Window,
15837        cx: &mut Context<Self>,
15838    ) {
15839        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15840    }
15841
15842    pub fn expand_excerpts_up(
15843        &mut self,
15844        action: &ExpandExcerptsUp,
15845        _: &mut Window,
15846        cx: &mut Context<Self>,
15847    ) {
15848        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15849    }
15850
15851    pub fn expand_excerpts_for_direction(
15852        &mut self,
15853        lines: u32,
15854        direction: ExpandExcerptDirection,
15855
15856        cx: &mut Context<Self>,
15857    ) {
15858        let selections = self.selections.disjoint_anchors_arc();
15859
15860        let lines = if lines == 0 {
15861            EditorSettings::get_global(cx).expand_excerpt_lines
15862        } else {
15863            lines
15864        };
15865
15866        self.buffer.update(cx, |buffer, cx| {
15867            let snapshot = buffer.snapshot(cx);
15868            let mut excerpt_ids = selections
15869                .iter()
15870                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15871                .collect::<Vec<_>>();
15872            excerpt_ids.sort();
15873            excerpt_ids.dedup();
15874            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15875        })
15876    }
15877
15878    pub fn expand_excerpt(
15879        &mut self,
15880        excerpt: ExcerptId,
15881        direction: ExpandExcerptDirection,
15882        window: &mut Window,
15883        cx: &mut Context<Self>,
15884    ) {
15885        let current_scroll_position = self.scroll_position(cx);
15886        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15887        let mut should_scroll_up = false;
15888
15889        if direction == ExpandExcerptDirection::Down {
15890            let multi_buffer = self.buffer.read(cx);
15891            let snapshot = multi_buffer.snapshot(cx);
15892            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15893                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15894                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15895            {
15896                let buffer_snapshot = buffer.read(cx).snapshot();
15897                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15898                let last_row = buffer_snapshot.max_point().row;
15899                let lines_below = last_row.saturating_sub(excerpt_end_row);
15900                should_scroll_up = lines_below >= lines_to_expand;
15901            }
15902        }
15903
15904        self.buffer.update(cx, |buffer, cx| {
15905            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15906        });
15907
15908        if should_scroll_up {
15909            let new_scroll_position =
15910                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
15911            self.set_scroll_position(new_scroll_position, window, cx);
15912        }
15913    }
15914
15915    pub fn go_to_singleton_buffer_point(
15916        &mut self,
15917        point: Point,
15918        window: &mut Window,
15919        cx: &mut Context<Self>,
15920    ) {
15921        self.go_to_singleton_buffer_range(point..point, window, cx);
15922    }
15923
15924    pub fn go_to_singleton_buffer_range(
15925        &mut self,
15926        range: Range<Point>,
15927        window: &mut Window,
15928        cx: &mut Context<Self>,
15929    ) {
15930        let multibuffer = self.buffer().read(cx);
15931        let Some(buffer) = multibuffer.as_singleton() else {
15932            return;
15933        };
15934        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15935            return;
15936        };
15937        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15938            return;
15939        };
15940        self.change_selections(
15941            SelectionEffects::default().nav_history(true),
15942            window,
15943            cx,
15944            |s| s.select_anchor_ranges([start..end]),
15945        );
15946    }
15947
15948    pub fn go_to_diagnostic(
15949        &mut self,
15950        action: &GoToDiagnostic,
15951        window: &mut Window,
15952        cx: &mut Context<Self>,
15953    ) {
15954        if !self.diagnostics_enabled() {
15955            return;
15956        }
15957        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15958        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15959    }
15960
15961    pub fn go_to_prev_diagnostic(
15962        &mut self,
15963        action: &GoToPreviousDiagnostic,
15964        window: &mut Window,
15965        cx: &mut Context<Self>,
15966    ) {
15967        if !self.diagnostics_enabled() {
15968            return;
15969        }
15970        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15971        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15972    }
15973
15974    pub fn go_to_diagnostic_impl(
15975        &mut self,
15976        direction: Direction,
15977        severity: GoToDiagnosticSeverityFilter,
15978        window: &mut Window,
15979        cx: &mut Context<Self>,
15980    ) {
15981        let buffer = self.buffer.read(cx).snapshot(cx);
15982        let selection = self.selections.newest::<usize>(cx);
15983
15984        let mut active_group_id = None;
15985        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15986            && active_group.active_range.start.to_offset(&buffer) == selection.start
15987        {
15988            active_group_id = Some(active_group.group_id);
15989        }
15990
15991        fn filtered<'a>(
15992            snapshot: EditorSnapshot,
15993            severity: GoToDiagnosticSeverityFilter,
15994            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
15995        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
15996            diagnostics
15997                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15998                .filter(|entry| entry.range.start != entry.range.end)
15999                .filter(|entry| !entry.diagnostic.is_unnecessary)
16000                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
16001        }
16002
16003        let snapshot = self.snapshot(window, cx);
16004        let before = filtered(
16005            snapshot.clone(),
16006            severity,
16007            buffer
16008                .diagnostics_in_range(0..selection.start)
16009                .filter(|entry| entry.range.start <= selection.start),
16010        );
16011        let after = filtered(
16012            snapshot,
16013            severity,
16014            buffer
16015                .diagnostics_in_range(selection.start..buffer.len())
16016                .filter(|entry| entry.range.start >= selection.start),
16017        );
16018
16019        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16020        if direction == Direction::Prev {
16021            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16022            {
16023                for diagnostic in prev_diagnostics.into_iter().rev() {
16024                    if diagnostic.range.start != selection.start
16025                        || active_group_id
16026                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16027                    {
16028                        found = Some(diagnostic);
16029                        break 'outer;
16030                    }
16031                }
16032            }
16033        } else {
16034            for diagnostic in after.chain(before) {
16035                if diagnostic.range.start != selection.start
16036                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16037                {
16038                    found = Some(diagnostic);
16039                    break;
16040                }
16041            }
16042        }
16043        let Some(next_diagnostic) = found else {
16044            return;
16045        };
16046
16047        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16048        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16049            return;
16050        };
16051        self.change_selections(Default::default(), window, cx, |s| {
16052            s.select_ranges(vec![
16053                next_diagnostic.range.start..next_diagnostic.range.start,
16054            ])
16055        });
16056        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16057        self.refresh_edit_prediction(false, true, window, cx);
16058    }
16059
16060    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16061        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16062        let snapshot = self.snapshot(window, cx);
16063        let selection = self.selections.newest::<Point>(cx);
16064        self.go_to_hunk_before_or_after_position(
16065            &snapshot,
16066            selection.head(),
16067            Direction::Next,
16068            window,
16069            cx,
16070        );
16071    }
16072
16073    pub fn go_to_hunk_before_or_after_position(
16074        &mut self,
16075        snapshot: &EditorSnapshot,
16076        position: Point,
16077        direction: Direction,
16078        window: &mut Window,
16079        cx: &mut Context<Editor>,
16080    ) {
16081        let row = if direction == Direction::Next {
16082            self.hunk_after_position(snapshot, position)
16083                .map(|hunk| hunk.row_range.start)
16084        } else {
16085            self.hunk_before_position(snapshot, position)
16086        };
16087
16088        if let Some(row) = row {
16089            let destination = Point::new(row.0, 0);
16090            let autoscroll = Autoscroll::center();
16091
16092            self.unfold_ranges(&[destination..destination], false, false, cx);
16093            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16094                s.select_ranges([destination..destination]);
16095            });
16096        }
16097    }
16098
16099    fn hunk_after_position(
16100        &mut self,
16101        snapshot: &EditorSnapshot,
16102        position: Point,
16103    ) -> Option<MultiBufferDiffHunk> {
16104        snapshot
16105            .buffer_snapshot()
16106            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16107            .find(|hunk| hunk.row_range.start.0 > position.row)
16108            .or_else(|| {
16109                snapshot
16110                    .buffer_snapshot()
16111                    .diff_hunks_in_range(Point::zero()..position)
16112                    .find(|hunk| hunk.row_range.end.0 < position.row)
16113            })
16114    }
16115
16116    fn go_to_prev_hunk(
16117        &mut self,
16118        _: &GoToPreviousHunk,
16119        window: &mut Window,
16120        cx: &mut Context<Self>,
16121    ) {
16122        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16123        let snapshot = self.snapshot(window, cx);
16124        let selection = self.selections.newest::<Point>(cx);
16125        self.go_to_hunk_before_or_after_position(
16126            &snapshot,
16127            selection.head(),
16128            Direction::Prev,
16129            window,
16130            cx,
16131        );
16132    }
16133
16134    fn hunk_before_position(
16135        &mut self,
16136        snapshot: &EditorSnapshot,
16137        position: Point,
16138    ) -> Option<MultiBufferRow> {
16139        snapshot
16140            .buffer_snapshot()
16141            .diff_hunk_before(position)
16142            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16143    }
16144
16145    fn go_to_next_change(
16146        &mut self,
16147        _: &GoToNextChange,
16148        window: &mut Window,
16149        cx: &mut Context<Self>,
16150    ) {
16151        if let Some(selections) = self
16152            .change_list
16153            .next_change(1, Direction::Next)
16154            .map(|s| s.to_vec())
16155        {
16156            self.change_selections(Default::default(), window, cx, |s| {
16157                let map = s.display_map();
16158                s.select_display_ranges(selections.iter().map(|a| {
16159                    let point = a.to_display_point(&map);
16160                    point..point
16161                }))
16162            })
16163        }
16164    }
16165
16166    fn go_to_previous_change(
16167        &mut self,
16168        _: &GoToPreviousChange,
16169        window: &mut Window,
16170        cx: &mut Context<Self>,
16171    ) {
16172        if let Some(selections) = self
16173            .change_list
16174            .next_change(1, Direction::Prev)
16175            .map(|s| s.to_vec())
16176        {
16177            self.change_selections(Default::default(), window, cx, |s| {
16178                let map = s.display_map();
16179                s.select_display_ranges(selections.iter().map(|a| {
16180                    let point = a.to_display_point(&map);
16181                    point..point
16182                }))
16183            })
16184        }
16185    }
16186
16187    pub fn go_to_next_document_highlight(
16188        &mut self,
16189        _: &GoToNextDocumentHighlight,
16190        window: &mut Window,
16191        cx: &mut Context<Self>,
16192    ) {
16193        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16194    }
16195
16196    pub fn go_to_prev_document_highlight(
16197        &mut self,
16198        _: &GoToPreviousDocumentHighlight,
16199        window: &mut Window,
16200        cx: &mut Context<Self>,
16201    ) {
16202        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16203    }
16204
16205    pub fn go_to_document_highlight_before_or_after_position(
16206        &mut self,
16207        direction: Direction,
16208        window: &mut Window,
16209        cx: &mut Context<Editor>,
16210    ) {
16211        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16212        let snapshot = self.snapshot(window, cx);
16213        let buffer = &snapshot.buffer_snapshot();
16214        let position = self.selections.newest::<Point>(cx).head();
16215        let anchor_position = buffer.anchor_after(position);
16216
16217        // Get all document highlights (both read and write)
16218        let mut all_highlights = Vec::new();
16219
16220        if let Some((_, read_highlights)) = self
16221            .background_highlights
16222            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16223        {
16224            all_highlights.extend(read_highlights.iter());
16225        }
16226
16227        if let Some((_, write_highlights)) = self
16228            .background_highlights
16229            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16230        {
16231            all_highlights.extend(write_highlights.iter());
16232        }
16233
16234        if all_highlights.is_empty() {
16235            return;
16236        }
16237
16238        // Sort highlights by position
16239        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16240
16241        let target_highlight = match direction {
16242            Direction::Next => {
16243                // Find the first highlight after the current position
16244                all_highlights
16245                    .iter()
16246                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16247            }
16248            Direction::Prev => {
16249                // Find the last highlight before the current position
16250                all_highlights
16251                    .iter()
16252                    .rev()
16253                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16254            }
16255        };
16256
16257        if let Some(highlight) = target_highlight {
16258            let destination = highlight.start.to_point(buffer);
16259            let autoscroll = Autoscroll::center();
16260
16261            self.unfold_ranges(&[destination..destination], false, false, cx);
16262            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16263                s.select_ranges([destination..destination]);
16264            });
16265        }
16266    }
16267
16268    fn go_to_line<T: 'static>(
16269        &mut self,
16270        position: Anchor,
16271        highlight_color: Option<Hsla>,
16272        window: &mut Window,
16273        cx: &mut Context<Self>,
16274    ) {
16275        let snapshot = self.snapshot(window, cx).display_snapshot;
16276        let position = position.to_point(&snapshot.buffer_snapshot());
16277        let start = snapshot
16278            .buffer_snapshot()
16279            .clip_point(Point::new(position.row, 0), Bias::Left);
16280        let end = start + Point::new(1, 0);
16281        let start = snapshot.buffer_snapshot().anchor_before(start);
16282        let end = snapshot.buffer_snapshot().anchor_before(end);
16283
16284        self.highlight_rows::<T>(
16285            start..end,
16286            highlight_color
16287                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16288            Default::default(),
16289            cx,
16290        );
16291
16292        if self.buffer.read(cx).is_singleton() {
16293            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16294        }
16295    }
16296
16297    pub fn go_to_definition(
16298        &mut self,
16299        _: &GoToDefinition,
16300        window: &mut Window,
16301        cx: &mut Context<Self>,
16302    ) -> Task<Result<Navigated>> {
16303        let definition =
16304            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16305        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16306        cx.spawn_in(window, async move |editor, cx| {
16307            if definition.await? == Navigated::Yes {
16308                return Ok(Navigated::Yes);
16309            }
16310            match fallback_strategy {
16311                GoToDefinitionFallback::None => Ok(Navigated::No),
16312                GoToDefinitionFallback::FindAllReferences => {
16313                    match editor.update_in(cx, |editor, window, cx| {
16314                        editor.find_all_references(&FindAllReferences, window, cx)
16315                    })? {
16316                        Some(references) => references.await,
16317                        None => Ok(Navigated::No),
16318                    }
16319                }
16320            }
16321        })
16322    }
16323
16324    pub fn go_to_declaration(
16325        &mut self,
16326        _: &GoToDeclaration,
16327        window: &mut Window,
16328        cx: &mut Context<Self>,
16329    ) -> Task<Result<Navigated>> {
16330        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16331    }
16332
16333    pub fn go_to_declaration_split(
16334        &mut self,
16335        _: &GoToDeclaration,
16336        window: &mut Window,
16337        cx: &mut Context<Self>,
16338    ) -> Task<Result<Navigated>> {
16339        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16340    }
16341
16342    pub fn go_to_implementation(
16343        &mut self,
16344        _: &GoToImplementation,
16345        window: &mut Window,
16346        cx: &mut Context<Self>,
16347    ) -> Task<Result<Navigated>> {
16348        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16349    }
16350
16351    pub fn go_to_implementation_split(
16352        &mut self,
16353        _: &GoToImplementationSplit,
16354        window: &mut Window,
16355        cx: &mut Context<Self>,
16356    ) -> Task<Result<Navigated>> {
16357        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16358    }
16359
16360    pub fn go_to_type_definition(
16361        &mut self,
16362        _: &GoToTypeDefinition,
16363        window: &mut Window,
16364        cx: &mut Context<Self>,
16365    ) -> Task<Result<Navigated>> {
16366        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16367    }
16368
16369    pub fn go_to_definition_split(
16370        &mut self,
16371        _: &GoToDefinitionSplit,
16372        window: &mut Window,
16373        cx: &mut Context<Self>,
16374    ) -> Task<Result<Navigated>> {
16375        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16376    }
16377
16378    pub fn go_to_type_definition_split(
16379        &mut self,
16380        _: &GoToTypeDefinitionSplit,
16381        window: &mut Window,
16382        cx: &mut Context<Self>,
16383    ) -> Task<Result<Navigated>> {
16384        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16385    }
16386
16387    fn go_to_definition_of_kind(
16388        &mut self,
16389        kind: GotoDefinitionKind,
16390        split: bool,
16391        window: &mut Window,
16392        cx: &mut Context<Self>,
16393    ) -> Task<Result<Navigated>> {
16394        let Some(provider) = self.semantics_provider.clone() else {
16395            return Task::ready(Ok(Navigated::No));
16396        };
16397        let head = self.selections.newest::<usize>(cx).head();
16398        let buffer = self.buffer.read(cx);
16399        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16400            return Task::ready(Ok(Navigated::No));
16401        };
16402        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16403            return Task::ready(Ok(Navigated::No));
16404        };
16405
16406        cx.spawn_in(window, async move |editor, cx| {
16407            let Some(definitions) = definitions.await? else {
16408                return Ok(Navigated::No);
16409            };
16410            let navigated = editor
16411                .update_in(cx, |editor, window, cx| {
16412                    editor.navigate_to_hover_links(
16413                        Some(kind),
16414                        definitions
16415                            .into_iter()
16416                            .filter(|location| {
16417                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16418                            })
16419                            .map(HoverLink::Text)
16420                            .collect::<Vec<_>>(),
16421                        split,
16422                        window,
16423                        cx,
16424                    )
16425                })?
16426                .await?;
16427            anyhow::Ok(navigated)
16428        })
16429    }
16430
16431    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16432        let selection = self.selections.newest_anchor();
16433        let head = selection.head();
16434        let tail = selection.tail();
16435
16436        let Some((buffer, start_position)) =
16437            self.buffer.read(cx).text_anchor_for_position(head, cx)
16438        else {
16439            return;
16440        };
16441
16442        let end_position = if head != tail {
16443            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16444                return;
16445            };
16446            Some(pos)
16447        } else {
16448            None
16449        };
16450
16451        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16452            let url = if let Some(end_pos) = end_position {
16453                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16454            } else {
16455                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16456            };
16457
16458            if let Some(url) = url {
16459                cx.update(|window, cx| {
16460                    if parse_zed_link(&url, cx).is_some() {
16461                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16462                    } else {
16463                        cx.open_url(&url);
16464                    }
16465                })?;
16466            }
16467
16468            anyhow::Ok(())
16469        });
16470
16471        url_finder.detach();
16472    }
16473
16474    pub fn open_selected_filename(
16475        &mut self,
16476        _: &OpenSelectedFilename,
16477        window: &mut Window,
16478        cx: &mut Context<Self>,
16479    ) {
16480        let Some(workspace) = self.workspace() else {
16481            return;
16482        };
16483
16484        let position = self.selections.newest_anchor().head();
16485
16486        let Some((buffer, buffer_position)) =
16487            self.buffer.read(cx).text_anchor_for_position(position, cx)
16488        else {
16489            return;
16490        };
16491
16492        let project = self.project.clone();
16493
16494        cx.spawn_in(window, async move |_, cx| {
16495            let result = find_file(&buffer, project, buffer_position, cx).await;
16496
16497            if let Some((_, path)) = result {
16498                workspace
16499                    .update_in(cx, |workspace, window, cx| {
16500                        workspace.open_resolved_path(path, window, cx)
16501                    })?
16502                    .await?;
16503            }
16504            anyhow::Ok(())
16505        })
16506        .detach();
16507    }
16508
16509    pub(crate) fn navigate_to_hover_links(
16510        &mut self,
16511        kind: Option<GotoDefinitionKind>,
16512        definitions: Vec<HoverLink>,
16513        split: bool,
16514        window: &mut Window,
16515        cx: &mut Context<Editor>,
16516    ) -> Task<Result<Navigated>> {
16517        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16518        let mut first_url_or_file = None;
16519        let definitions: Vec<_> = definitions
16520            .into_iter()
16521            .filter_map(|def| match def {
16522                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16523                HoverLink::InlayHint(lsp_location, server_id) => {
16524                    let computation =
16525                        self.compute_target_location(lsp_location, server_id, window, cx);
16526                    Some(cx.background_spawn(computation))
16527                }
16528                HoverLink::Url(url) => {
16529                    first_url_or_file = Some(Either::Left(url));
16530                    None
16531                }
16532                HoverLink::File(path) => {
16533                    first_url_or_file = Some(Either::Right(path));
16534                    None
16535                }
16536            })
16537            .collect();
16538
16539        let workspace = self.workspace();
16540
16541        cx.spawn_in(window, async move |editor, cx| {
16542            let locations: Vec<Location> = future::join_all(definitions)
16543                .await
16544                .into_iter()
16545                .filter_map(|location| location.transpose())
16546                .collect::<Result<_>>()
16547                .context("location tasks")?;
16548            let mut locations = cx.update(|_, cx| {
16549                locations
16550                    .into_iter()
16551                    .map(|location| {
16552                        let buffer = location.buffer.read(cx);
16553                        (location.buffer, location.range.to_point(buffer))
16554                    })
16555                    .into_group_map()
16556            })?;
16557            let mut num_locations = 0;
16558            for ranges in locations.values_mut() {
16559                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16560                ranges.dedup();
16561                num_locations += ranges.len();
16562            }
16563
16564            if num_locations > 1 {
16565                let Some(workspace) = workspace else {
16566                    return Ok(Navigated::No);
16567                };
16568
16569                let tab_kind = match kind {
16570                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16571                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16572                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16573                    Some(GotoDefinitionKind::Type) => "Types",
16574                };
16575                let title = editor
16576                    .update_in(cx, |_, _, cx| {
16577                        let target = locations
16578                            .iter()
16579                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16580                            .map(|(buffer, location)| {
16581                                buffer
16582                                    .read(cx)
16583                                    .text_for_range(location.clone())
16584                                    .collect::<String>()
16585                            })
16586                            .filter(|text| !text.contains('\n'))
16587                            .unique()
16588                            .take(3)
16589                            .join(", ");
16590                        if target.is_empty() {
16591                            tab_kind.to_owned()
16592                        } else {
16593                            format!("{tab_kind} for {target}")
16594                        }
16595                    })
16596                    .context("buffer title")?;
16597
16598                let opened = workspace
16599                    .update_in(cx, |workspace, window, cx| {
16600                        Self::open_locations_in_multibuffer(
16601                            workspace,
16602                            locations,
16603                            title,
16604                            split,
16605                            MultibufferSelectionMode::First,
16606                            window,
16607                            cx,
16608                        )
16609                    })
16610                    .is_ok();
16611
16612                anyhow::Ok(Navigated::from_bool(opened))
16613            } else if num_locations == 0 {
16614                // If there is one url or file, open it directly
16615                match first_url_or_file {
16616                    Some(Either::Left(url)) => {
16617                        cx.update(|_, cx| cx.open_url(&url))?;
16618                        Ok(Navigated::Yes)
16619                    }
16620                    Some(Either::Right(path)) => {
16621                        let Some(workspace) = workspace else {
16622                            return Ok(Navigated::No);
16623                        };
16624
16625                        workspace
16626                            .update_in(cx, |workspace, window, cx| {
16627                                workspace.open_resolved_path(path, window, cx)
16628                            })?
16629                            .await?;
16630                        Ok(Navigated::Yes)
16631                    }
16632                    None => Ok(Navigated::No),
16633                }
16634            } else {
16635                let Some(workspace) = workspace else {
16636                    return Ok(Navigated::No);
16637                };
16638
16639                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16640                let target_range = target_ranges.first().unwrap().clone();
16641
16642                editor.update_in(cx, |editor, window, cx| {
16643                    let range = target_range.to_point(target_buffer.read(cx));
16644                    let range = editor.range_for_match(&range);
16645                    let range = collapse_multiline_range(range);
16646
16647                    if !split
16648                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16649                    {
16650                        editor.go_to_singleton_buffer_range(range, window, cx);
16651                    } else {
16652                        let pane = workspace.read(cx).active_pane().clone();
16653                        window.defer(cx, move |window, cx| {
16654                            let target_editor: Entity<Self> =
16655                                workspace.update(cx, |workspace, cx| {
16656                                    let pane = if split {
16657                                        workspace.adjacent_pane(window, cx)
16658                                    } else {
16659                                        workspace.active_pane().clone()
16660                                    };
16661
16662                                    workspace.open_project_item(
16663                                        pane,
16664                                        target_buffer.clone(),
16665                                        true,
16666                                        true,
16667                                        window,
16668                                        cx,
16669                                    )
16670                                });
16671                            target_editor.update(cx, |target_editor, cx| {
16672                                // When selecting a definition in a different buffer, disable the nav history
16673                                // to avoid creating a history entry at the previous cursor location.
16674                                pane.update(cx, |pane, _| pane.disable_history());
16675                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16676                                pane.update(cx, |pane, _| pane.enable_history());
16677                            });
16678                        });
16679                    }
16680                    Navigated::Yes
16681                })
16682            }
16683        })
16684    }
16685
16686    fn compute_target_location(
16687        &self,
16688        lsp_location: lsp::Location,
16689        server_id: LanguageServerId,
16690        window: &mut Window,
16691        cx: &mut Context<Self>,
16692    ) -> Task<anyhow::Result<Option<Location>>> {
16693        let Some(project) = self.project.clone() else {
16694            return Task::ready(Ok(None));
16695        };
16696
16697        cx.spawn_in(window, async move |editor, cx| {
16698            let location_task = editor.update(cx, |_, cx| {
16699                project.update(cx, |project, cx| {
16700                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16701                })
16702            })?;
16703            let location = Some({
16704                let target_buffer_handle = location_task.await.context("open local buffer")?;
16705                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16706                    let target_start = target_buffer
16707                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16708                    let target_end = target_buffer
16709                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16710                    target_buffer.anchor_after(target_start)
16711                        ..target_buffer.anchor_before(target_end)
16712                })?;
16713                Location {
16714                    buffer: target_buffer_handle,
16715                    range,
16716                }
16717            });
16718            Ok(location)
16719        })
16720    }
16721
16722    pub fn find_all_references(
16723        &mut self,
16724        _: &FindAllReferences,
16725        window: &mut Window,
16726        cx: &mut Context<Self>,
16727    ) -> Option<Task<Result<Navigated>>> {
16728        let selection = self.selections.newest::<usize>(cx);
16729        let multi_buffer = self.buffer.read(cx);
16730        let head = selection.head();
16731
16732        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16733        let head_anchor = multi_buffer_snapshot.anchor_at(
16734            head,
16735            if head < selection.tail() {
16736                Bias::Right
16737            } else {
16738                Bias::Left
16739            },
16740        );
16741
16742        match self
16743            .find_all_references_task_sources
16744            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16745        {
16746            Ok(_) => {
16747                log::info!(
16748                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16749                );
16750                return None;
16751            }
16752            Err(i) => {
16753                self.find_all_references_task_sources.insert(i, head_anchor);
16754            }
16755        }
16756
16757        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16758        let workspace = self.workspace()?;
16759        let project = workspace.read(cx).project().clone();
16760        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16761        Some(cx.spawn_in(window, async move |editor, cx| {
16762            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16763                if let Ok(i) = editor
16764                    .find_all_references_task_sources
16765                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16766                {
16767                    editor.find_all_references_task_sources.remove(i);
16768                }
16769            });
16770
16771            let Some(locations) = references.await? else {
16772                return anyhow::Ok(Navigated::No);
16773            };
16774            let mut locations = cx.update(|_, cx| {
16775                locations
16776                    .into_iter()
16777                    .map(|location| {
16778                        let buffer = location.buffer.read(cx);
16779                        (location.buffer, location.range.to_point(buffer))
16780                    })
16781                    .into_group_map()
16782            })?;
16783            if locations.is_empty() {
16784                return anyhow::Ok(Navigated::No);
16785            }
16786            for ranges in locations.values_mut() {
16787                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16788                ranges.dedup();
16789            }
16790
16791            workspace.update_in(cx, |workspace, window, cx| {
16792                let target = locations
16793                    .iter()
16794                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16795                    .map(|(buffer, location)| {
16796                        buffer
16797                            .read(cx)
16798                            .text_for_range(location.clone())
16799                            .collect::<String>()
16800                    })
16801                    .filter(|text| !text.contains('\n'))
16802                    .unique()
16803                    .take(3)
16804                    .join(", ");
16805                let title = if target.is_empty() {
16806                    "References".to_owned()
16807                } else {
16808                    format!("References to {target}")
16809                };
16810                Self::open_locations_in_multibuffer(
16811                    workspace,
16812                    locations,
16813                    title,
16814                    false,
16815                    MultibufferSelectionMode::First,
16816                    window,
16817                    cx,
16818                );
16819                Navigated::Yes
16820            })
16821        }))
16822    }
16823
16824    /// Opens a multibuffer with the given project locations in it
16825    pub fn open_locations_in_multibuffer(
16826        workspace: &mut Workspace,
16827        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16828        title: String,
16829        split: bool,
16830        multibuffer_selection_mode: MultibufferSelectionMode,
16831        window: &mut Window,
16832        cx: &mut Context<Workspace>,
16833    ) {
16834        if locations.is_empty() {
16835            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16836            return;
16837        }
16838
16839        let capability = workspace.project().read(cx).capability();
16840        let mut ranges = <Vec<Range<Anchor>>>::new();
16841
16842        // a key to find existing multibuffer editors with the same set of locations
16843        // to prevent us from opening more and more multibuffer tabs for searches and the like
16844        let mut key = (title.clone(), vec![]);
16845        let excerpt_buffer = cx.new(|cx| {
16846            let key = &mut key.1;
16847            let mut multibuffer = MultiBuffer::new(capability);
16848            for (buffer, mut ranges_for_buffer) in locations {
16849                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16850                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16851                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16852                    PathKey::for_buffer(&buffer, cx),
16853                    buffer.clone(),
16854                    ranges_for_buffer,
16855                    multibuffer_context_lines(cx),
16856                    cx,
16857                );
16858                ranges.extend(new_ranges)
16859            }
16860
16861            multibuffer.with_title(title)
16862        });
16863        let existing = workspace.active_pane().update(cx, |pane, cx| {
16864            pane.items()
16865                .filter_map(|item| item.downcast::<Editor>())
16866                .find(|editor| {
16867                    editor
16868                        .read(cx)
16869                        .lookup_key
16870                        .as_ref()
16871                        .and_then(|it| {
16872                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16873                        })
16874                        .is_some_and(|it| *it == key)
16875                })
16876        });
16877        let editor = existing.unwrap_or_else(|| {
16878            cx.new(|cx| {
16879                let mut editor = Editor::for_multibuffer(
16880                    excerpt_buffer,
16881                    Some(workspace.project().clone()),
16882                    window,
16883                    cx,
16884                );
16885                editor.lookup_key = Some(Box::new(key));
16886                editor
16887            })
16888        });
16889        editor.update(cx, |editor, cx| {
16890            match multibuffer_selection_mode {
16891                MultibufferSelectionMode::First => {
16892                    if let Some(first_range) = ranges.first() {
16893                        editor.change_selections(
16894                            SelectionEffects::no_scroll(),
16895                            window,
16896                            cx,
16897                            |selections| {
16898                                selections.clear_disjoint();
16899                                selections
16900                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16901                            },
16902                        );
16903                    }
16904                    editor.highlight_background::<Self>(
16905                        &ranges,
16906                        |theme| theme.colors().editor_highlighted_line_background,
16907                        cx,
16908                    );
16909                }
16910                MultibufferSelectionMode::All => {
16911                    editor.change_selections(
16912                        SelectionEffects::no_scroll(),
16913                        window,
16914                        cx,
16915                        |selections| {
16916                            selections.clear_disjoint();
16917                            selections.select_anchor_ranges(ranges);
16918                        },
16919                    );
16920                }
16921            }
16922            editor.register_buffers_with_language_servers(cx);
16923        });
16924
16925        let item = Box::new(editor);
16926        let item_id = item.item_id();
16927
16928        if split {
16929            let pane = workspace.adjacent_pane(window, cx);
16930            workspace.add_item(pane, item, None, true, true, window, cx);
16931        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16932            let (preview_item_id, preview_item_idx) =
16933                workspace.active_pane().read_with(cx, |pane, _| {
16934                    (pane.preview_item_id(), pane.preview_item_idx())
16935                });
16936
16937            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16938
16939            if let Some(preview_item_id) = preview_item_id {
16940                workspace.active_pane().update(cx, |pane, cx| {
16941                    pane.remove_item(preview_item_id, false, false, window, cx);
16942                });
16943            }
16944        } else {
16945            workspace.add_item_to_active_pane(item, None, true, window, cx);
16946        }
16947        workspace.active_pane().update(cx, |pane, cx| {
16948            pane.set_preview_item_id(Some(item_id), cx);
16949        });
16950    }
16951
16952    pub fn rename(
16953        &mut self,
16954        _: &Rename,
16955        window: &mut Window,
16956        cx: &mut Context<Self>,
16957    ) -> Option<Task<Result<()>>> {
16958        use language::ToOffset as _;
16959
16960        let provider = self.semantics_provider.clone()?;
16961        let selection = self.selections.newest_anchor().clone();
16962        let (cursor_buffer, cursor_buffer_position) = self
16963            .buffer
16964            .read(cx)
16965            .text_anchor_for_position(selection.head(), cx)?;
16966        let (tail_buffer, cursor_buffer_position_end) = self
16967            .buffer
16968            .read(cx)
16969            .text_anchor_for_position(selection.tail(), cx)?;
16970        if tail_buffer != cursor_buffer {
16971            return None;
16972        }
16973
16974        let snapshot = cursor_buffer.read(cx).snapshot();
16975        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16976        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16977        let prepare_rename = provider
16978            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16979            .unwrap_or_else(|| Task::ready(Ok(None)));
16980        drop(snapshot);
16981
16982        Some(cx.spawn_in(window, async move |this, cx| {
16983            let rename_range = if let Some(range) = prepare_rename.await? {
16984                Some(range)
16985            } else {
16986                this.update(cx, |this, cx| {
16987                    let buffer = this.buffer.read(cx).snapshot(cx);
16988                    let mut buffer_highlights = this
16989                        .document_highlights_for_position(selection.head(), &buffer)
16990                        .filter(|highlight| {
16991                            highlight.start.excerpt_id == selection.head().excerpt_id
16992                                && highlight.end.excerpt_id == selection.head().excerpt_id
16993                        });
16994                    buffer_highlights
16995                        .next()
16996                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16997                })?
16998            };
16999            if let Some(rename_range) = rename_range {
17000                this.update_in(cx, |this, window, cx| {
17001                    let snapshot = cursor_buffer.read(cx).snapshot();
17002                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17003                    let cursor_offset_in_rename_range =
17004                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17005                    let cursor_offset_in_rename_range_end =
17006                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17007
17008                    this.take_rename(false, window, cx);
17009                    let buffer = this.buffer.read(cx).read(cx);
17010                    let cursor_offset = selection.head().to_offset(&buffer);
17011                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17012                    let rename_end = rename_start + rename_buffer_range.len();
17013                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17014                    let mut old_highlight_id = None;
17015                    let old_name: Arc<str> = buffer
17016                        .chunks(rename_start..rename_end, true)
17017                        .map(|chunk| {
17018                            if old_highlight_id.is_none() {
17019                                old_highlight_id = chunk.syntax_highlight_id;
17020                            }
17021                            chunk.text
17022                        })
17023                        .collect::<String>()
17024                        .into();
17025
17026                    drop(buffer);
17027
17028                    // Position the selection in the rename editor so that it matches the current selection.
17029                    this.show_local_selections = false;
17030                    let rename_editor = cx.new(|cx| {
17031                        let mut editor = Editor::single_line(window, cx);
17032                        editor.buffer.update(cx, |buffer, cx| {
17033                            buffer.edit([(0..0, old_name.clone())], None, cx)
17034                        });
17035                        let rename_selection_range = match cursor_offset_in_rename_range
17036                            .cmp(&cursor_offset_in_rename_range_end)
17037                        {
17038                            Ordering::Equal => {
17039                                editor.select_all(&SelectAll, window, cx);
17040                                return editor;
17041                            }
17042                            Ordering::Less => {
17043                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17044                            }
17045                            Ordering::Greater => {
17046                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17047                            }
17048                        };
17049                        if rename_selection_range.end > old_name.len() {
17050                            editor.select_all(&SelectAll, window, cx);
17051                        } else {
17052                            editor.change_selections(Default::default(), window, cx, |s| {
17053                                s.select_ranges([rename_selection_range]);
17054                            });
17055                        }
17056                        editor
17057                    });
17058                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17059                        if e == &EditorEvent::Focused {
17060                            cx.emit(EditorEvent::FocusedIn)
17061                        }
17062                    })
17063                    .detach();
17064
17065                    let write_highlights =
17066                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17067                    let read_highlights =
17068                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17069                    let ranges = write_highlights
17070                        .iter()
17071                        .flat_map(|(_, ranges)| ranges.iter())
17072                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17073                        .cloned()
17074                        .collect();
17075
17076                    this.highlight_text::<Rename>(
17077                        ranges,
17078                        HighlightStyle {
17079                            fade_out: Some(0.6),
17080                            ..Default::default()
17081                        },
17082                        cx,
17083                    );
17084                    let rename_focus_handle = rename_editor.focus_handle(cx);
17085                    window.focus(&rename_focus_handle);
17086                    let block_id = this.insert_blocks(
17087                        [BlockProperties {
17088                            style: BlockStyle::Flex,
17089                            placement: BlockPlacement::Below(range.start),
17090                            height: Some(1),
17091                            render: Arc::new({
17092                                let rename_editor = rename_editor.clone();
17093                                move |cx: &mut BlockContext| {
17094                                    let mut text_style = cx.editor_style.text.clone();
17095                                    if let Some(highlight_style) = old_highlight_id
17096                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17097                                    {
17098                                        text_style = text_style.highlight(highlight_style);
17099                                    }
17100                                    div()
17101                                        .block_mouse_except_scroll()
17102                                        .pl(cx.anchor_x)
17103                                        .child(EditorElement::new(
17104                                            &rename_editor,
17105                                            EditorStyle {
17106                                                background: cx.theme().system().transparent,
17107                                                local_player: cx.editor_style.local_player,
17108                                                text: text_style,
17109                                                scrollbar_width: cx.editor_style.scrollbar_width,
17110                                                syntax: cx.editor_style.syntax.clone(),
17111                                                status: cx.editor_style.status.clone(),
17112                                                inlay_hints_style: HighlightStyle {
17113                                                    font_weight: Some(FontWeight::BOLD),
17114                                                    ..make_inlay_hints_style(cx.app)
17115                                                },
17116                                                edit_prediction_styles: make_suggestion_styles(
17117                                                    cx.app,
17118                                                ),
17119                                                ..EditorStyle::default()
17120                                            },
17121                                        ))
17122                                        .into_any_element()
17123                                }
17124                            }),
17125                            priority: 0,
17126                        }],
17127                        Some(Autoscroll::fit()),
17128                        cx,
17129                    )[0];
17130                    this.pending_rename = Some(RenameState {
17131                        range,
17132                        old_name,
17133                        editor: rename_editor,
17134                        block_id,
17135                    });
17136                })?;
17137            }
17138
17139            Ok(())
17140        }))
17141    }
17142
17143    pub fn confirm_rename(
17144        &mut self,
17145        _: &ConfirmRename,
17146        window: &mut Window,
17147        cx: &mut Context<Self>,
17148    ) -> Option<Task<Result<()>>> {
17149        let rename = self.take_rename(false, window, cx)?;
17150        let workspace = self.workspace()?.downgrade();
17151        let (buffer, start) = self
17152            .buffer
17153            .read(cx)
17154            .text_anchor_for_position(rename.range.start, cx)?;
17155        let (end_buffer, _) = self
17156            .buffer
17157            .read(cx)
17158            .text_anchor_for_position(rename.range.end, cx)?;
17159        if buffer != end_buffer {
17160            return None;
17161        }
17162
17163        let old_name = rename.old_name;
17164        let new_name = rename.editor.read(cx).text(cx);
17165
17166        let rename = self.semantics_provider.as_ref()?.perform_rename(
17167            &buffer,
17168            start,
17169            new_name.clone(),
17170            cx,
17171        )?;
17172
17173        Some(cx.spawn_in(window, async move |editor, cx| {
17174            let project_transaction = rename.await?;
17175            Self::open_project_transaction(
17176                &editor,
17177                workspace,
17178                project_transaction,
17179                format!("Rename: {}{}", old_name, new_name),
17180                cx,
17181            )
17182            .await?;
17183
17184            editor.update(cx, |editor, cx| {
17185                editor.refresh_document_highlights(cx);
17186            })?;
17187            Ok(())
17188        }))
17189    }
17190
17191    fn take_rename(
17192        &mut self,
17193        moving_cursor: bool,
17194        window: &mut Window,
17195        cx: &mut Context<Self>,
17196    ) -> Option<RenameState> {
17197        let rename = self.pending_rename.take()?;
17198        if rename.editor.focus_handle(cx).is_focused(window) {
17199            window.focus(&self.focus_handle);
17200        }
17201
17202        self.remove_blocks(
17203            [rename.block_id].into_iter().collect(),
17204            Some(Autoscroll::fit()),
17205            cx,
17206        );
17207        self.clear_highlights::<Rename>(cx);
17208        self.show_local_selections = true;
17209
17210        if moving_cursor {
17211            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17212                editor.selections.newest::<usize>(cx).head()
17213            });
17214
17215            // Update the selection to match the position of the selection inside
17216            // the rename editor.
17217            let snapshot = self.buffer.read(cx).read(cx);
17218            let rename_range = rename.range.to_offset(&snapshot);
17219            let cursor_in_editor = snapshot
17220                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17221                .min(rename_range.end);
17222            drop(snapshot);
17223
17224            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17225                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17226            });
17227        } else {
17228            self.refresh_document_highlights(cx);
17229        }
17230
17231        Some(rename)
17232    }
17233
17234    pub fn pending_rename(&self) -> Option<&RenameState> {
17235        self.pending_rename.as_ref()
17236    }
17237
17238    fn format(
17239        &mut self,
17240        _: &Format,
17241        window: &mut Window,
17242        cx: &mut Context<Self>,
17243    ) -> Option<Task<Result<()>>> {
17244        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17245
17246        let project = match &self.project {
17247            Some(project) => project.clone(),
17248            None => return None,
17249        };
17250
17251        Some(self.perform_format(
17252            project,
17253            FormatTrigger::Manual,
17254            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17255            window,
17256            cx,
17257        ))
17258    }
17259
17260    fn format_selections(
17261        &mut self,
17262        _: &FormatSelections,
17263        window: &mut Window,
17264        cx: &mut Context<Self>,
17265    ) -> Option<Task<Result<()>>> {
17266        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17267
17268        let project = match &self.project {
17269            Some(project) => project.clone(),
17270            None => return None,
17271        };
17272
17273        let ranges = self
17274            .selections
17275            .all_adjusted(cx)
17276            .into_iter()
17277            .map(|selection| selection.range())
17278            .collect_vec();
17279
17280        Some(self.perform_format(
17281            project,
17282            FormatTrigger::Manual,
17283            FormatTarget::Ranges(ranges),
17284            window,
17285            cx,
17286        ))
17287    }
17288
17289    fn perform_format(
17290        &mut self,
17291        project: Entity<Project>,
17292        trigger: FormatTrigger,
17293        target: FormatTarget,
17294        window: &mut Window,
17295        cx: &mut Context<Self>,
17296    ) -> Task<Result<()>> {
17297        let buffer = self.buffer.clone();
17298        let (buffers, target) = match target {
17299            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17300            FormatTarget::Ranges(selection_ranges) => {
17301                let multi_buffer = buffer.read(cx);
17302                let snapshot = multi_buffer.read(cx);
17303                let mut buffers = HashSet::default();
17304                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17305                    BTreeMap::new();
17306                for selection_range in selection_ranges {
17307                    for (buffer, buffer_range, _) in
17308                        snapshot.range_to_buffer_ranges(selection_range)
17309                    {
17310                        let buffer_id = buffer.remote_id();
17311                        let start = buffer.anchor_before(buffer_range.start);
17312                        let end = buffer.anchor_after(buffer_range.end);
17313                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17314                        buffer_id_to_ranges
17315                            .entry(buffer_id)
17316                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17317                            .or_insert_with(|| vec![start..end]);
17318                    }
17319                }
17320                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17321            }
17322        };
17323
17324        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17325        let selections_prev = transaction_id_prev
17326            .and_then(|transaction_id_prev| {
17327                // default to selections as they were after the last edit, if we have them,
17328                // instead of how they are now.
17329                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17330                // will take you back to where you made the last edit, instead of staying where you scrolled
17331                self.selection_history
17332                    .transaction(transaction_id_prev)
17333                    .map(|t| t.0.clone())
17334            })
17335            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17336
17337        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17338        let format = project.update(cx, |project, cx| {
17339            project.format(buffers, target, true, trigger, cx)
17340        });
17341
17342        cx.spawn_in(window, async move |editor, cx| {
17343            let transaction = futures::select_biased! {
17344                transaction = format.log_err().fuse() => transaction,
17345                () = timeout => {
17346                    log::warn!("timed out waiting for formatting");
17347                    None
17348                }
17349            };
17350
17351            buffer
17352                .update(cx, |buffer, cx| {
17353                    if let Some(transaction) = transaction
17354                        && !buffer.is_singleton()
17355                    {
17356                        buffer.push_transaction(&transaction.0, cx);
17357                    }
17358                    cx.notify();
17359                })
17360                .ok();
17361
17362            if let Some(transaction_id_now) =
17363                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17364            {
17365                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17366                if has_new_transaction {
17367                    _ = editor.update(cx, |editor, _| {
17368                        editor
17369                            .selection_history
17370                            .insert_transaction(transaction_id_now, selections_prev);
17371                    });
17372                }
17373            }
17374
17375            Ok(())
17376        })
17377    }
17378
17379    fn organize_imports(
17380        &mut self,
17381        _: &OrganizeImports,
17382        window: &mut Window,
17383        cx: &mut Context<Self>,
17384    ) -> Option<Task<Result<()>>> {
17385        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17386        let project = match &self.project {
17387            Some(project) => project.clone(),
17388            None => return None,
17389        };
17390        Some(self.perform_code_action_kind(
17391            project,
17392            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17393            window,
17394            cx,
17395        ))
17396    }
17397
17398    fn perform_code_action_kind(
17399        &mut self,
17400        project: Entity<Project>,
17401        kind: CodeActionKind,
17402        window: &mut Window,
17403        cx: &mut Context<Self>,
17404    ) -> Task<Result<()>> {
17405        let buffer = self.buffer.clone();
17406        let buffers = buffer.read(cx).all_buffers();
17407        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17408        let apply_action = project.update(cx, |project, cx| {
17409            project.apply_code_action_kind(buffers, kind, true, cx)
17410        });
17411        cx.spawn_in(window, async move |_, cx| {
17412            let transaction = futures::select_biased! {
17413                () = timeout => {
17414                    log::warn!("timed out waiting for executing code action");
17415                    None
17416                }
17417                transaction = apply_action.log_err().fuse() => transaction,
17418            };
17419            buffer
17420                .update(cx, |buffer, cx| {
17421                    // check if we need this
17422                    if let Some(transaction) = transaction
17423                        && !buffer.is_singleton()
17424                    {
17425                        buffer.push_transaction(&transaction.0, cx);
17426                    }
17427                    cx.notify();
17428                })
17429                .ok();
17430            Ok(())
17431        })
17432    }
17433
17434    pub fn restart_language_server(
17435        &mut self,
17436        _: &RestartLanguageServer,
17437        _: &mut Window,
17438        cx: &mut Context<Self>,
17439    ) {
17440        if let Some(project) = self.project.clone() {
17441            self.buffer.update(cx, |multi_buffer, cx| {
17442                project.update(cx, |project, cx| {
17443                    project.restart_language_servers_for_buffers(
17444                        multi_buffer.all_buffers().into_iter().collect(),
17445                        HashSet::default(),
17446                        cx,
17447                    );
17448                });
17449            })
17450        }
17451    }
17452
17453    pub fn stop_language_server(
17454        &mut self,
17455        _: &StopLanguageServer,
17456        _: &mut Window,
17457        cx: &mut Context<Self>,
17458    ) {
17459        if let Some(project) = self.project.clone() {
17460            self.buffer.update(cx, |multi_buffer, cx| {
17461                project.update(cx, |project, cx| {
17462                    project.stop_language_servers_for_buffers(
17463                        multi_buffer.all_buffers().into_iter().collect(),
17464                        HashSet::default(),
17465                        cx,
17466                    );
17467                    cx.emit(project::Event::RefreshInlayHints);
17468                });
17469            });
17470        }
17471    }
17472
17473    fn cancel_language_server_work(
17474        workspace: &mut Workspace,
17475        _: &actions::CancelLanguageServerWork,
17476        _: &mut Window,
17477        cx: &mut Context<Workspace>,
17478    ) {
17479        let project = workspace.project();
17480        let buffers = workspace
17481            .active_item(cx)
17482            .and_then(|item| item.act_as::<Editor>(cx))
17483            .map_or(HashSet::default(), |editor| {
17484                editor.read(cx).buffer.read(cx).all_buffers()
17485            });
17486        project.update(cx, |project, cx| {
17487            project.cancel_language_server_work_for_buffers(buffers, cx);
17488        });
17489    }
17490
17491    fn show_character_palette(
17492        &mut self,
17493        _: &ShowCharacterPalette,
17494        window: &mut Window,
17495        _: &mut Context<Self>,
17496    ) {
17497        window.show_character_palette();
17498    }
17499
17500    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17501        if !self.diagnostics_enabled() {
17502            return;
17503        }
17504
17505        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17506            let buffer = self.buffer.read(cx).snapshot(cx);
17507            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17508            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17509            let is_valid = buffer
17510                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17511                .any(|entry| {
17512                    entry.diagnostic.is_primary
17513                        && !entry.range.is_empty()
17514                        && entry.range.start == primary_range_start
17515                        && entry.diagnostic.message == active_diagnostics.active_message
17516                });
17517
17518            if !is_valid {
17519                self.dismiss_diagnostics(cx);
17520            }
17521        }
17522    }
17523
17524    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17525        match &self.active_diagnostics {
17526            ActiveDiagnostic::Group(group) => Some(group),
17527            _ => None,
17528        }
17529    }
17530
17531    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17532        if !self.diagnostics_enabled() {
17533            return;
17534        }
17535        self.dismiss_diagnostics(cx);
17536        self.active_diagnostics = ActiveDiagnostic::All;
17537    }
17538
17539    fn activate_diagnostics(
17540        &mut self,
17541        buffer_id: BufferId,
17542        diagnostic: DiagnosticEntryRef<'_, usize>,
17543        window: &mut Window,
17544        cx: &mut Context<Self>,
17545    ) {
17546        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17547            return;
17548        }
17549        self.dismiss_diagnostics(cx);
17550        let snapshot = self.snapshot(window, cx);
17551        let buffer = self.buffer.read(cx).snapshot(cx);
17552        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17553            return;
17554        };
17555
17556        let diagnostic_group = buffer
17557            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17558            .collect::<Vec<_>>();
17559
17560        let blocks =
17561            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17562
17563        let blocks = self.display_map.update(cx, |display_map, cx| {
17564            display_map.insert_blocks(blocks, cx).into_iter().collect()
17565        });
17566        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17567            active_range: buffer.anchor_before(diagnostic.range.start)
17568                ..buffer.anchor_after(diagnostic.range.end),
17569            active_message: diagnostic.diagnostic.message.clone(),
17570            group_id: diagnostic.diagnostic.group_id,
17571            blocks,
17572        });
17573        cx.notify();
17574    }
17575
17576    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17577        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17578            return;
17579        };
17580
17581        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17582        if let ActiveDiagnostic::Group(group) = prev {
17583            self.display_map.update(cx, |display_map, cx| {
17584                display_map.remove_blocks(group.blocks, cx);
17585            });
17586            cx.notify();
17587        }
17588    }
17589
17590    /// Disable inline diagnostics rendering for this editor.
17591    pub fn disable_inline_diagnostics(&mut self) {
17592        self.inline_diagnostics_enabled = false;
17593        self.inline_diagnostics_update = Task::ready(());
17594        self.inline_diagnostics.clear();
17595    }
17596
17597    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17598        self.diagnostics_enabled = false;
17599        self.dismiss_diagnostics(cx);
17600        self.inline_diagnostics_update = Task::ready(());
17601        self.inline_diagnostics.clear();
17602    }
17603
17604    pub fn disable_word_completions(&mut self) {
17605        self.word_completions_enabled = false;
17606    }
17607
17608    pub fn diagnostics_enabled(&self) -> bool {
17609        self.diagnostics_enabled && self.mode.is_full()
17610    }
17611
17612    pub fn inline_diagnostics_enabled(&self) -> bool {
17613        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17614    }
17615
17616    pub fn show_inline_diagnostics(&self) -> bool {
17617        self.show_inline_diagnostics
17618    }
17619
17620    pub fn toggle_inline_diagnostics(
17621        &mut self,
17622        _: &ToggleInlineDiagnostics,
17623        window: &mut Window,
17624        cx: &mut Context<Editor>,
17625    ) {
17626        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17627        self.refresh_inline_diagnostics(false, window, cx);
17628    }
17629
17630    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17631        self.diagnostics_max_severity = severity;
17632        self.display_map.update(cx, |display_map, _| {
17633            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17634        });
17635    }
17636
17637    pub fn toggle_diagnostics(
17638        &mut self,
17639        _: &ToggleDiagnostics,
17640        window: &mut Window,
17641        cx: &mut Context<Editor>,
17642    ) {
17643        if !self.diagnostics_enabled() {
17644            return;
17645        }
17646
17647        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17648            EditorSettings::get_global(cx)
17649                .diagnostics_max_severity
17650                .filter(|severity| severity != &DiagnosticSeverity::Off)
17651                .unwrap_or(DiagnosticSeverity::Hint)
17652        } else {
17653            DiagnosticSeverity::Off
17654        };
17655        self.set_max_diagnostics_severity(new_severity, cx);
17656        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17657            self.active_diagnostics = ActiveDiagnostic::None;
17658            self.inline_diagnostics_update = Task::ready(());
17659            self.inline_diagnostics.clear();
17660        } else {
17661            self.refresh_inline_diagnostics(false, window, cx);
17662        }
17663
17664        cx.notify();
17665    }
17666
17667    pub fn toggle_minimap(
17668        &mut self,
17669        _: &ToggleMinimap,
17670        window: &mut Window,
17671        cx: &mut Context<Editor>,
17672    ) {
17673        if self.supports_minimap(cx) {
17674            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17675        }
17676    }
17677
17678    fn refresh_inline_diagnostics(
17679        &mut self,
17680        debounce: bool,
17681        window: &mut Window,
17682        cx: &mut Context<Self>,
17683    ) {
17684        let max_severity = ProjectSettings::get_global(cx)
17685            .diagnostics
17686            .inline
17687            .max_severity
17688            .unwrap_or(self.diagnostics_max_severity);
17689
17690        if !self.inline_diagnostics_enabled()
17691            || !self.show_inline_diagnostics
17692            || max_severity == DiagnosticSeverity::Off
17693        {
17694            self.inline_diagnostics_update = Task::ready(());
17695            self.inline_diagnostics.clear();
17696            return;
17697        }
17698
17699        let debounce_ms = ProjectSettings::get_global(cx)
17700            .diagnostics
17701            .inline
17702            .update_debounce_ms;
17703        let debounce = if debounce && debounce_ms > 0 {
17704            Some(Duration::from_millis(debounce_ms))
17705        } else {
17706            None
17707        };
17708        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17709            if let Some(debounce) = debounce {
17710                cx.background_executor().timer(debounce).await;
17711            }
17712            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17713                editor
17714                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17715                    .ok()
17716            }) else {
17717                return;
17718            };
17719
17720            let new_inline_diagnostics = cx
17721                .background_spawn(async move {
17722                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17723                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17724                        let message = diagnostic_entry
17725                            .diagnostic
17726                            .message
17727                            .split_once('\n')
17728                            .map(|(line, _)| line)
17729                            .map(SharedString::new)
17730                            .unwrap_or_else(|| {
17731                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17732                            });
17733                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17734                        let (Ok(i) | Err(i)) = inline_diagnostics
17735                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17736                        inline_diagnostics.insert(
17737                            i,
17738                            (
17739                                start_anchor,
17740                                InlineDiagnostic {
17741                                    message,
17742                                    group_id: diagnostic_entry.diagnostic.group_id,
17743                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17744                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17745                                    severity: diagnostic_entry.diagnostic.severity,
17746                                },
17747                            ),
17748                        );
17749                    }
17750                    inline_diagnostics
17751                })
17752                .await;
17753
17754            editor
17755                .update(cx, |editor, cx| {
17756                    editor.inline_diagnostics = new_inline_diagnostics;
17757                    cx.notify();
17758                })
17759                .ok();
17760        });
17761    }
17762
17763    fn pull_diagnostics(
17764        &mut self,
17765        buffer_id: Option<BufferId>,
17766        window: &Window,
17767        cx: &mut Context<Self>,
17768    ) -> Option<()> {
17769        if !self.mode().is_full() {
17770            return None;
17771        }
17772        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17773            .diagnostics
17774            .lsp_pull_diagnostics;
17775        if !pull_diagnostics_settings.enabled {
17776            return None;
17777        }
17778        let project = self.project()?.downgrade();
17779        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17780        let mut buffers = self.buffer.read(cx).all_buffers();
17781        if let Some(buffer_id) = buffer_id {
17782            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17783        }
17784
17785        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17786            cx.background_executor().timer(debounce).await;
17787
17788            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17789                buffers
17790                    .into_iter()
17791                    .filter_map(|buffer| {
17792                        project
17793                            .update(cx, |project, cx| {
17794                                project.lsp_store().update(cx, |lsp_store, cx| {
17795                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17796                                })
17797                            })
17798                            .ok()
17799                    })
17800                    .collect::<FuturesUnordered<_>>()
17801            }) else {
17802                return;
17803            };
17804
17805            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17806                match pull_task {
17807                    Ok(()) => {
17808                        if editor
17809                            .update_in(cx, |editor, window, cx| {
17810                                editor.update_diagnostics_state(window, cx);
17811                            })
17812                            .is_err()
17813                        {
17814                            return;
17815                        }
17816                    }
17817                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17818                }
17819            }
17820        });
17821
17822        Some(())
17823    }
17824
17825    pub fn set_selections_from_remote(
17826        &mut self,
17827        selections: Vec<Selection<Anchor>>,
17828        pending_selection: Option<Selection<Anchor>>,
17829        window: &mut Window,
17830        cx: &mut Context<Self>,
17831    ) {
17832        let old_cursor_position = self.selections.newest_anchor().head();
17833        self.selections.change_with(cx, |s| {
17834            s.select_anchors(selections);
17835            if let Some(pending_selection) = pending_selection {
17836                s.set_pending(pending_selection, SelectMode::Character);
17837            } else {
17838                s.clear_pending();
17839            }
17840        });
17841        self.selections_did_change(
17842            false,
17843            &old_cursor_position,
17844            SelectionEffects::default(),
17845            window,
17846            cx,
17847        );
17848    }
17849
17850    pub fn transact(
17851        &mut self,
17852        window: &mut Window,
17853        cx: &mut Context<Self>,
17854        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17855    ) -> Option<TransactionId> {
17856        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17857            this.start_transaction_at(Instant::now(), window, cx);
17858            update(this, window, cx);
17859            this.end_transaction_at(Instant::now(), cx)
17860        })
17861    }
17862
17863    pub fn start_transaction_at(
17864        &mut self,
17865        now: Instant,
17866        window: &mut Window,
17867        cx: &mut Context<Self>,
17868    ) -> Option<TransactionId> {
17869        self.end_selection(window, cx);
17870        if let Some(tx_id) = self
17871            .buffer
17872            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17873        {
17874            self.selection_history
17875                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17876            cx.emit(EditorEvent::TransactionBegun {
17877                transaction_id: tx_id,
17878            });
17879            Some(tx_id)
17880        } else {
17881            None
17882        }
17883    }
17884
17885    pub fn end_transaction_at(
17886        &mut self,
17887        now: Instant,
17888        cx: &mut Context<Self>,
17889    ) -> Option<TransactionId> {
17890        if let Some(transaction_id) = self
17891            .buffer
17892            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17893        {
17894            if let Some((_, end_selections)) =
17895                self.selection_history.transaction_mut(transaction_id)
17896            {
17897                *end_selections = Some(self.selections.disjoint_anchors_arc());
17898            } else {
17899                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17900            }
17901
17902            cx.emit(EditorEvent::Edited { transaction_id });
17903            Some(transaction_id)
17904        } else {
17905            None
17906        }
17907    }
17908
17909    pub fn modify_transaction_selection_history(
17910        &mut self,
17911        transaction_id: TransactionId,
17912        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17913    ) -> bool {
17914        self.selection_history
17915            .transaction_mut(transaction_id)
17916            .map(modify)
17917            .is_some()
17918    }
17919
17920    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17921        if self.selection_mark_mode {
17922            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17923                s.move_with(|_, sel| {
17924                    sel.collapse_to(sel.head(), SelectionGoal::None);
17925                });
17926            })
17927        }
17928        self.selection_mark_mode = true;
17929        cx.notify();
17930    }
17931
17932    pub fn swap_selection_ends(
17933        &mut self,
17934        _: &actions::SwapSelectionEnds,
17935        window: &mut Window,
17936        cx: &mut Context<Self>,
17937    ) {
17938        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17939            s.move_with(|_, sel| {
17940                if sel.start != sel.end {
17941                    sel.reversed = !sel.reversed
17942                }
17943            });
17944        });
17945        self.request_autoscroll(Autoscroll::newest(), cx);
17946        cx.notify();
17947    }
17948
17949    pub fn toggle_focus(
17950        workspace: &mut Workspace,
17951        _: &actions::ToggleFocus,
17952        window: &mut Window,
17953        cx: &mut Context<Workspace>,
17954    ) {
17955        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17956            return;
17957        };
17958        workspace.activate_item(&item, true, true, window, cx);
17959    }
17960
17961    pub fn toggle_fold(
17962        &mut self,
17963        _: &actions::ToggleFold,
17964        window: &mut Window,
17965        cx: &mut Context<Self>,
17966    ) {
17967        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
17968            let selection = self.selections.newest::<Point>(cx);
17969
17970            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17971            let range = if selection.is_empty() {
17972                let point = selection.head().to_display_point(&display_map);
17973                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17974                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17975                    .to_point(&display_map);
17976                start..end
17977            } else {
17978                selection.range()
17979            };
17980            if display_map.folds_in_range(range).next().is_some() {
17981                self.unfold_lines(&Default::default(), window, cx)
17982            } else {
17983                self.fold(&Default::default(), window, cx)
17984            }
17985        } else {
17986            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17987            let buffer_ids: HashSet<_> = self
17988                .selections
17989                .disjoint_anchor_ranges()
17990                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17991                .collect();
17992
17993            let should_unfold = buffer_ids
17994                .iter()
17995                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17996
17997            for buffer_id in buffer_ids {
17998                if should_unfold {
17999                    self.unfold_buffer(buffer_id, cx);
18000                } else {
18001                    self.fold_buffer(buffer_id, cx);
18002                }
18003            }
18004        }
18005    }
18006
18007    pub fn toggle_fold_recursive(
18008        &mut self,
18009        _: &actions::ToggleFoldRecursive,
18010        window: &mut Window,
18011        cx: &mut Context<Self>,
18012    ) {
18013        let selection = self.selections.newest::<Point>(cx);
18014
18015        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18016        let range = if selection.is_empty() {
18017            let point = selection.head().to_display_point(&display_map);
18018            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18019            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18020                .to_point(&display_map);
18021            start..end
18022        } else {
18023            selection.range()
18024        };
18025        if display_map.folds_in_range(range).next().is_some() {
18026            self.unfold_recursive(&Default::default(), window, cx)
18027        } else {
18028            self.fold_recursive(&Default::default(), window, cx)
18029        }
18030    }
18031
18032    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18033        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18034            let mut to_fold = Vec::new();
18035            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18036            let selections = self.selections.all_adjusted(cx);
18037
18038            for selection in selections {
18039                let range = selection.range().sorted();
18040                let buffer_start_row = range.start.row;
18041
18042                if range.start.row != range.end.row {
18043                    let mut found = false;
18044                    let mut row = range.start.row;
18045                    while row <= range.end.row {
18046                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18047                        {
18048                            found = true;
18049                            row = crease.range().end.row + 1;
18050                            to_fold.push(crease);
18051                        } else {
18052                            row += 1
18053                        }
18054                    }
18055                    if found {
18056                        continue;
18057                    }
18058                }
18059
18060                for row in (0..=range.start.row).rev() {
18061                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18062                        && crease.range().end.row >= buffer_start_row
18063                    {
18064                        to_fold.push(crease);
18065                        if row <= range.start.row {
18066                            break;
18067                        }
18068                    }
18069                }
18070            }
18071
18072            self.fold_creases(to_fold, true, window, cx);
18073        } else {
18074            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18075            let buffer_ids = self
18076                .selections
18077                .disjoint_anchor_ranges()
18078                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18079                .collect::<HashSet<_>>();
18080            for buffer_id in buffer_ids {
18081                self.fold_buffer(buffer_id, cx);
18082            }
18083        }
18084    }
18085
18086    pub fn toggle_fold_all(
18087        &mut self,
18088        _: &actions::ToggleFoldAll,
18089        window: &mut Window,
18090        cx: &mut Context<Self>,
18091    ) {
18092        if self.buffer.read(cx).is_singleton() {
18093            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18094            let has_folds = display_map
18095                .folds_in_range(0..display_map.buffer_snapshot().len())
18096                .next()
18097                .is_some();
18098
18099            if has_folds {
18100                self.unfold_all(&actions::UnfoldAll, window, cx);
18101            } else {
18102                self.fold_all(&actions::FoldAll, window, cx);
18103            }
18104        } else {
18105            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18106            let should_unfold = buffer_ids
18107                .iter()
18108                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18109
18110            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18111                editor
18112                    .update_in(cx, |editor, _, cx| {
18113                        for buffer_id in buffer_ids {
18114                            if should_unfold {
18115                                editor.unfold_buffer(buffer_id, cx);
18116                            } else {
18117                                editor.fold_buffer(buffer_id, cx);
18118                            }
18119                        }
18120                    })
18121                    .ok();
18122            });
18123        }
18124    }
18125
18126    fn fold_at_level(
18127        &mut self,
18128        fold_at: &FoldAtLevel,
18129        window: &mut Window,
18130        cx: &mut Context<Self>,
18131    ) {
18132        if !self.buffer.read(cx).is_singleton() {
18133            return;
18134        }
18135
18136        let fold_at_level = fold_at.0;
18137        let snapshot = self.buffer.read(cx).snapshot(cx);
18138        let mut to_fold = Vec::new();
18139        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18140
18141        let row_ranges_to_keep: Vec<Range<u32>> = self
18142            .selections
18143            .all::<Point>(cx)
18144            .into_iter()
18145            .map(|sel| sel.start.row..sel.end.row)
18146            .collect();
18147
18148        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18149            while start_row < end_row {
18150                match self
18151                    .snapshot(window, cx)
18152                    .crease_for_buffer_row(MultiBufferRow(start_row))
18153                {
18154                    Some(crease) => {
18155                        let nested_start_row = crease.range().start.row + 1;
18156                        let nested_end_row = crease.range().end.row;
18157
18158                        if current_level < fold_at_level {
18159                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18160                        } else if current_level == fold_at_level {
18161                            // Fold iff there is no selection completely contained within the fold region
18162                            if !row_ranges_to_keep.iter().any(|selection| {
18163                                selection.end >= nested_start_row
18164                                    && selection.start <= nested_end_row
18165                            }) {
18166                                to_fold.push(crease);
18167                            }
18168                        }
18169
18170                        start_row = nested_end_row + 1;
18171                    }
18172                    None => start_row += 1,
18173                }
18174            }
18175        }
18176
18177        self.fold_creases(to_fold, true, window, cx);
18178    }
18179
18180    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18181        if self.buffer.read(cx).is_singleton() {
18182            let mut fold_ranges = Vec::new();
18183            let snapshot = self.buffer.read(cx).snapshot(cx);
18184
18185            for row in 0..snapshot.max_row().0 {
18186                if let Some(foldable_range) = self
18187                    .snapshot(window, cx)
18188                    .crease_for_buffer_row(MultiBufferRow(row))
18189                {
18190                    fold_ranges.push(foldable_range);
18191                }
18192            }
18193
18194            self.fold_creases(fold_ranges, true, window, cx);
18195        } else {
18196            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18197                editor
18198                    .update_in(cx, |editor, _, cx| {
18199                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18200                            editor.fold_buffer(buffer_id, cx);
18201                        }
18202                    })
18203                    .ok();
18204            });
18205        }
18206    }
18207
18208    pub fn fold_function_bodies(
18209        &mut self,
18210        _: &actions::FoldFunctionBodies,
18211        window: &mut Window,
18212        cx: &mut Context<Self>,
18213    ) {
18214        let snapshot = self.buffer.read(cx).snapshot(cx);
18215
18216        let ranges = snapshot
18217            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18218            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18219            .collect::<Vec<_>>();
18220
18221        let creases = ranges
18222            .into_iter()
18223            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18224            .collect();
18225
18226        self.fold_creases(creases, true, window, cx);
18227    }
18228
18229    pub fn fold_recursive(
18230        &mut self,
18231        _: &actions::FoldRecursive,
18232        window: &mut Window,
18233        cx: &mut Context<Self>,
18234    ) {
18235        let mut to_fold = Vec::new();
18236        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18237        let selections = self.selections.all_adjusted(cx);
18238
18239        for selection in selections {
18240            let range = selection.range().sorted();
18241            let buffer_start_row = range.start.row;
18242
18243            if range.start.row != range.end.row {
18244                let mut found = false;
18245                for row in range.start.row..=range.end.row {
18246                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18247                        found = true;
18248                        to_fold.push(crease);
18249                    }
18250                }
18251                if found {
18252                    continue;
18253                }
18254            }
18255
18256            for row in (0..=range.start.row).rev() {
18257                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18258                    if crease.range().end.row >= buffer_start_row {
18259                        to_fold.push(crease);
18260                    } else {
18261                        break;
18262                    }
18263                }
18264            }
18265        }
18266
18267        self.fold_creases(to_fold, true, window, cx);
18268    }
18269
18270    pub fn fold_at(
18271        &mut self,
18272        buffer_row: MultiBufferRow,
18273        window: &mut Window,
18274        cx: &mut Context<Self>,
18275    ) {
18276        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18277
18278        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18279            let autoscroll = self
18280                .selections
18281                .all::<Point>(cx)
18282                .iter()
18283                .any(|selection| crease.range().overlaps(&selection.range()));
18284
18285            self.fold_creases(vec![crease], autoscroll, window, cx);
18286        }
18287    }
18288
18289    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18290        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18291            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18292            let buffer = display_map.buffer_snapshot();
18293            let selections = self.selections.all::<Point>(cx);
18294            let ranges = selections
18295                .iter()
18296                .map(|s| {
18297                    let range = s.display_range(&display_map).sorted();
18298                    let mut start = range.start.to_point(&display_map);
18299                    let mut end = range.end.to_point(&display_map);
18300                    start.column = 0;
18301                    end.column = buffer.line_len(MultiBufferRow(end.row));
18302                    start..end
18303                })
18304                .collect::<Vec<_>>();
18305
18306            self.unfold_ranges(&ranges, true, true, cx);
18307        } else {
18308            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18309            let buffer_ids = self
18310                .selections
18311                .disjoint_anchor_ranges()
18312                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18313                .collect::<HashSet<_>>();
18314            for buffer_id in buffer_ids {
18315                self.unfold_buffer(buffer_id, cx);
18316            }
18317        }
18318    }
18319
18320    pub fn unfold_recursive(
18321        &mut self,
18322        _: &UnfoldRecursive,
18323        _window: &mut Window,
18324        cx: &mut Context<Self>,
18325    ) {
18326        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18327        let selections = self.selections.all::<Point>(cx);
18328        let ranges = selections
18329            .iter()
18330            .map(|s| {
18331                let mut range = s.display_range(&display_map).sorted();
18332                *range.start.column_mut() = 0;
18333                *range.end.column_mut() = display_map.line_len(range.end.row());
18334                let start = range.start.to_point(&display_map);
18335                let end = range.end.to_point(&display_map);
18336                start..end
18337            })
18338            .collect::<Vec<_>>();
18339
18340        self.unfold_ranges(&ranges, true, true, cx);
18341    }
18342
18343    pub fn unfold_at(
18344        &mut self,
18345        buffer_row: MultiBufferRow,
18346        _window: &mut Window,
18347        cx: &mut Context<Self>,
18348    ) {
18349        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18350
18351        let intersection_range = Point::new(buffer_row.0, 0)
18352            ..Point::new(
18353                buffer_row.0,
18354                display_map.buffer_snapshot().line_len(buffer_row),
18355            );
18356
18357        let autoscroll = self
18358            .selections
18359            .all::<Point>(cx)
18360            .iter()
18361            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18362
18363        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18364    }
18365
18366    pub fn unfold_all(
18367        &mut self,
18368        _: &actions::UnfoldAll,
18369        _window: &mut Window,
18370        cx: &mut Context<Self>,
18371    ) {
18372        if self.buffer.read(cx).is_singleton() {
18373            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18374            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18375        } else {
18376            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18377                editor
18378                    .update(cx, |editor, cx| {
18379                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18380                            editor.unfold_buffer(buffer_id, cx);
18381                        }
18382                    })
18383                    .ok();
18384            });
18385        }
18386    }
18387
18388    pub fn fold_selected_ranges(
18389        &mut self,
18390        _: &FoldSelectedRanges,
18391        window: &mut Window,
18392        cx: &mut Context<Self>,
18393    ) {
18394        let selections = self.selections.all_adjusted(cx);
18395        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18396        let ranges = selections
18397            .into_iter()
18398            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18399            .collect::<Vec<_>>();
18400        self.fold_creases(ranges, true, window, cx);
18401    }
18402
18403    pub fn fold_ranges<T: ToOffset + Clone>(
18404        &mut self,
18405        ranges: Vec<Range<T>>,
18406        auto_scroll: bool,
18407        window: &mut Window,
18408        cx: &mut Context<Self>,
18409    ) {
18410        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18411        let ranges = ranges
18412            .into_iter()
18413            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18414            .collect::<Vec<_>>();
18415        self.fold_creases(ranges, auto_scroll, window, cx);
18416    }
18417
18418    pub fn fold_creases<T: ToOffset + Clone>(
18419        &mut self,
18420        creases: Vec<Crease<T>>,
18421        auto_scroll: bool,
18422        _window: &mut Window,
18423        cx: &mut Context<Self>,
18424    ) {
18425        if creases.is_empty() {
18426            return;
18427        }
18428
18429        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18430
18431        if auto_scroll {
18432            self.request_autoscroll(Autoscroll::fit(), cx);
18433        }
18434
18435        cx.notify();
18436
18437        self.scrollbar_marker_state.dirty = true;
18438        self.folds_did_change(cx);
18439    }
18440
18441    /// Removes any folds whose ranges intersect any of the given ranges.
18442    pub fn unfold_ranges<T: ToOffset + Clone>(
18443        &mut self,
18444        ranges: &[Range<T>],
18445        inclusive: bool,
18446        auto_scroll: bool,
18447        cx: &mut Context<Self>,
18448    ) {
18449        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18450            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18451        });
18452        self.folds_did_change(cx);
18453    }
18454
18455    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18456        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18457            return;
18458        }
18459        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18460        self.display_map.update(cx, |display_map, cx| {
18461            display_map.fold_buffers([buffer_id], cx)
18462        });
18463        cx.emit(EditorEvent::BufferFoldToggled {
18464            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18465            folded: true,
18466        });
18467        cx.notify();
18468    }
18469
18470    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18471        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18472            return;
18473        }
18474        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18475        self.display_map.update(cx, |display_map, cx| {
18476            display_map.unfold_buffers([buffer_id], cx);
18477        });
18478        cx.emit(EditorEvent::BufferFoldToggled {
18479            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18480            folded: false,
18481        });
18482        cx.notify();
18483    }
18484
18485    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18486        self.display_map.read(cx).is_buffer_folded(buffer)
18487    }
18488
18489    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18490        self.display_map.read(cx).folded_buffers()
18491    }
18492
18493    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18494        self.display_map.update(cx, |display_map, cx| {
18495            display_map.disable_header_for_buffer(buffer_id, cx);
18496        });
18497        cx.notify();
18498    }
18499
18500    /// Removes any folds with the given ranges.
18501    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18502        &mut self,
18503        ranges: &[Range<T>],
18504        type_id: TypeId,
18505        auto_scroll: bool,
18506        cx: &mut Context<Self>,
18507    ) {
18508        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18509            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18510        });
18511        self.folds_did_change(cx);
18512    }
18513
18514    fn remove_folds_with<T: ToOffset + Clone>(
18515        &mut self,
18516        ranges: &[Range<T>],
18517        auto_scroll: bool,
18518        cx: &mut Context<Self>,
18519        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18520    ) {
18521        if ranges.is_empty() {
18522            return;
18523        }
18524
18525        let mut buffers_affected = HashSet::default();
18526        let multi_buffer = self.buffer().read(cx);
18527        for range in ranges {
18528            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18529                buffers_affected.insert(buffer.read(cx).remote_id());
18530            };
18531        }
18532
18533        self.display_map.update(cx, update);
18534
18535        if auto_scroll {
18536            self.request_autoscroll(Autoscroll::fit(), cx);
18537        }
18538
18539        cx.notify();
18540        self.scrollbar_marker_state.dirty = true;
18541        self.active_indent_guides_state.dirty = true;
18542    }
18543
18544    pub fn update_renderer_widths(
18545        &mut self,
18546        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18547        cx: &mut Context<Self>,
18548    ) -> bool {
18549        self.display_map
18550            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18551    }
18552
18553    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18554        self.display_map.read(cx).fold_placeholder.clone()
18555    }
18556
18557    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18558        self.buffer.update(cx, |buffer, cx| {
18559            buffer.set_all_diff_hunks_expanded(cx);
18560        });
18561    }
18562
18563    pub fn expand_all_diff_hunks(
18564        &mut self,
18565        _: &ExpandAllDiffHunks,
18566        _window: &mut Window,
18567        cx: &mut Context<Self>,
18568    ) {
18569        self.buffer.update(cx, |buffer, cx| {
18570            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18571        });
18572    }
18573
18574    pub fn toggle_selected_diff_hunks(
18575        &mut self,
18576        _: &ToggleSelectedDiffHunks,
18577        _window: &mut Window,
18578        cx: &mut Context<Self>,
18579    ) {
18580        let ranges: Vec<_> = self
18581            .selections
18582            .disjoint_anchors()
18583            .iter()
18584            .map(|s| s.range())
18585            .collect();
18586        self.toggle_diff_hunks_in_ranges(ranges, cx);
18587    }
18588
18589    pub fn diff_hunks_in_ranges<'a>(
18590        &'a self,
18591        ranges: &'a [Range<Anchor>],
18592        buffer: &'a MultiBufferSnapshot,
18593    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18594        ranges.iter().flat_map(move |range| {
18595            let end_excerpt_id = range.end.excerpt_id;
18596            let range = range.to_point(buffer);
18597            let mut peek_end = range.end;
18598            if range.end.row < buffer.max_row().0 {
18599                peek_end = Point::new(range.end.row + 1, 0);
18600            }
18601            buffer
18602                .diff_hunks_in_range(range.start..peek_end)
18603                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18604        })
18605    }
18606
18607    pub fn has_stageable_diff_hunks_in_ranges(
18608        &self,
18609        ranges: &[Range<Anchor>],
18610        snapshot: &MultiBufferSnapshot,
18611    ) -> bool {
18612        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18613        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18614    }
18615
18616    pub fn toggle_staged_selected_diff_hunks(
18617        &mut self,
18618        _: &::git::ToggleStaged,
18619        _: &mut Window,
18620        cx: &mut Context<Self>,
18621    ) {
18622        let snapshot = self.buffer.read(cx).snapshot(cx);
18623        let ranges: Vec<_> = self
18624            .selections
18625            .disjoint_anchors()
18626            .iter()
18627            .map(|s| s.range())
18628            .collect();
18629        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18630        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18631    }
18632
18633    pub fn set_render_diff_hunk_controls(
18634        &mut self,
18635        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18636        cx: &mut Context<Self>,
18637    ) {
18638        self.render_diff_hunk_controls = render_diff_hunk_controls;
18639        cx.notify();
18640    }
18641
18642    pub fn stage_and_next(
18643        &mut self,
18644        _: &::git::StageAndNext,
18645        window: &mut Window,
18646        cx: &mut Context<Self>,
18647    ) {
18648        self.do_stage_or_unstage_and_next(true, window, cx);
18649    }
18650
18651    pub fn unstage_and_next(
18652        &mut self,
18653        _: &::git::UnstageAndNext,
18654        window: &mut Window,
18655        cx: &mut Context<Self>,
18656    ) {
18657        self.do_stage_or_unstage_and_next(false, window, cx);
18658    }
18659
18660    pub fn stage_or_unstage_diff_hunks(
18661        &mut self,
18662        stage: bool,
18663        ranges: Vec<Range<Anchor>>,
18664        cx: &mut Context<Self>,
18665    ) {
18666        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18667        cx.spawn(async move |this, cx| {
18668            task.await?;
18669            this.update(cx, |this, cx| {
18670                let snapshot = this.buffer.read(cx).snapshot(cx);
18671                let chunk_by = this
18672                    .diff_hunks_in_ranges(&ranges, &snapshot)
18673                    .chunk_by(|hunk| hunk.buffer_id);
18674                for (buffer_id, hunks) in &chunk_by {
18675                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18676                }
18677            })
18678        })
18679        .detach_and_log_err(cx);
18680    }
18681
18682    fn save_buffers_for_ranges_if_needed(
18683        &mut self,
18684        ranges: &[Range<Anchor>],
18685        cx: &mut Context<Editor>,
18686    ) -> Task<Result<()>> {
18687        let multibuffer = self.buffer.read(cx);
18688        let snapshot = multibuffer.read(cx);
18689        let buffer_ids: HashSet<_> = ranges
18690            .iter()
18691            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18692            .collect();
18693        drop(snapshot);
18694
18695        let mut buffers = HashSet::default();
18696        for buffer_id in buffer_ids {
18697            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18698                let buffer = buffer_entity.read(cx);
18699                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18700                {
18701                    buffers.insert(buffer_entity);
18702                }
18703            }
18704        }
18705
18706        if let Some(project) = &self.project {
18707            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18708        } else {
18709            Task::ready(Ok(()))
18710        }
18711    }
18712
18713    fn do_stage_or_unstage_and_next(
18714        &mut self,
18715        stage: bool,
18716        window: &mut Window,
18717        cx: &mut Context<Self>,
18718    ) {
18719        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18720
18721        if ranges.iter().any(|range| range.start != range.end) {
18722            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18723            return;
18724        }
18725
18726        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18727        let snapshot = self.snapshot(window, cx);
18728        let position = self.selections.newest::<Point>(cx).head();
18729        let mut row = snapshot
18730            .buffer_snapshot()
18731            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18732            .find(|hunk| hunk.row_range.start.0 > position.row)
18733            .map(|hunk| hunk.row_range.start);
18734
18735        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18736        // Outside of the project diff editor, wrap around to the beginning.
18737        if !all_diff_hunks_expanded {
18738            row = row.or_else(|| {
18739                snapshot
18740                    .buffer_snapshot()
18741                    .diff_hunks_in_range(Point::zero()..position)
18742                    .find(|hunk| hunk.row_range.end.0 < position.row)
18743                    .map(|hunk| hunk.row_range.start)
18744            });
18745        }
18746
18747        if let Some(row) = row {
18748            let destination = Point::new(row.0, 0);
18749            let autoscroll = Autoscroll::center();
18750
18751            self.unfold_ranges(&[destination..destination], false, false, cx);
18752            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18753                s.select_ranges([destination..destination]);
18754            });
18755        }
18756    }
18757
18758    fn do_stage_or_unstage(
18759        &self,
18760        stage: bool,
18761        buffer_id: BufferId,
18762        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18763        cx: &mut App,
18764    ) -> Option<()> {
18765        let project = self.project()?;
18766        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18767        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18768        let buffer_snapshot = buffer.read(cx).snapshot();
18769        let file_exists = buffer_snapshot
18770            .file()
18771            .is_some_and(|file| file.disk_state().exists());
18772        diff.update(cx, |diff, cx| {
18773            diff.stage_or_unstage_hunks(
18774                stage,
18775                &hunks
18776                    .map(|hunk| buffer_diff::DiffHunk {
18777                        buffer_range: hunk.buffer_range,
18778                        diff_base_byte_range: hunk.diff_base_byte_range,
18779                        secondary_status: hunk.secondary_status,
18780                        range: Point::zero()..Point::zero(), // unused
18781                    })
18782                    .collect::<Vec<_>>(),
18783                &buffer_snapshot,
18784                file_exists,
18785                cx,
18786            )
18787        });
18788        None
18789    }
18790
18791    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18792        let ranges: Vec<_> = self
18793            .selections
18794            .disjoint_anchors()
18795            .iter()
18796            .map(|s| s.range())
18797            .collect();
18798        self.buffer
18799            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18800    }
18801
18802    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18803        self.buffer.update(cx, |buffer, cx| {
18804            let ranges = vec![Anchor::min()..Anchor::max()];
18805            if !buffer.all_diff_hunks_expanded()
18806                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18807            {
18808                buffer.collapse_diff_hunks(ranges, cx);
18809                true
18810            } else {
18811                false
18812            }
18813        })
18814    }
18815
18816    fn toggle_diff_hunks_in_ranges(
18817        &mut self,
18818        ranges: Vec<Range<Anchor>>,
18819        cx: &mut Context<Editor>,
18820    ) {
18821        self.buffer.update(cx, |buffer, cx| {
18822            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18823            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18824        })
18825    }
18826
18827    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18828        self.buffer.update(cx, |buffer, cx| {
18829            let snapshot = buffer.snapshot(cx);
18830            let excerpt_id = range.end.excerpt_id;
18831            let point_range = range.to_point(&snapshot);
18832            let expand = !buffer.single_hunk_is_expanded(range, cx);
18833            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18834        })
18835    }
18836
18837    pub(crate) fn apply_all_diff_hunks(
18838        &mut self,
18839        _: &ApplyAllDiffHunks,
18840        window: &mut Window,
18841        cx: &mut Context<Self>,
18842    ) {
18843        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18844
18845        let buffers = self.buffer.read(cx).all_buffers();
18846        for branch_buffer in buffers {
18847            branch_buffer.update(cx, |branch_buffer, cx| {
18848                branch_buffer.merge_into_base(Vec::new(), cx);
18849            });
18850        }
18851
18852        if let Some(project) = self.project.clone() {
18853            self.save(
18854                SaveOptions {
18855                    format: true,
18856                    autosave: false,
18857                },
18858                project,
18859                window,
18860                cx,
18861            )
18862            .detach_and_log_err(cx);
18863        }
18864    }
18865
18866    pub(crate) fn apply_selected_diff_hunks(
18867        &mut self,
18868        _: &ApplyDiffHunk,
18869        window: &mut Window,
18870        cx: &mut Context<Self>,
18871    ) {
18872        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18873        let snapshot = self.snapshot(window, cx);
18874        let hunks = snapshot.hunks_for_ranges(
18875            self.selections
18876                .all(cx)
18877                .into_iter()
18878                .map(|selection| selection.range()),
18879        );
18880        let mut ranges_by_buffer = HashMap::default();
18881        self.transact(window, cx, |editor, _window, cx| {
18882            for hunk in hunks {
18883                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18884                    ranges_by_buffer
18885                        .entry(buffer.clone())
18886                        .or_insert_with(Vec::new)
18887                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18888                }
18889            }
18890
18891            for (buffer, ranges) in ranges_by_buffer {
18892                buffer.update(cx, |buffer, cx| {
18893                    buffer.merge_into_base(ranges, cx);
18894                });
18895            }
18896        });
18897
18898        if let Some(project) = self.project.clone() {
18899            self.save(
18900                SaveOptions {
18901                    format: true,
18902                    autosave: false,
18903                },
18904                project,
18905                window,
18906                cx,
18907            )
18908            .detach_and_log_err(cx);
18909        }
18910    }
18911
18912    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18913        if hovered != self.gutter_hovered {
18914            self.gutter_hovered = hovered;
18915            cx.notify();
18916        }
18917    }
18918
18919    pub fn insert_blocks(
18920        &mut self,
18921        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18922        autoscroll: Option<Autoscroll>,
18923        cx: &mut Context<Self>,
18924    ) -> Vec<CustomBlockId> {
18925        let blocks = self
18926            .display_map
18927            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18928        if let Some(autoscroll) = autoscroll {
18929            self.request_autoscroll(autoscroll, cx);
18930        }
18931        cx.notify();
18932        blocks
18933    }
18934
18935    pub fn resize_blocks(
18936        &mut self,
18937        heights: HashMap<CustomBlockId, u32>,
18938        autoscroll: Option<Autoscroll>,
18939        cx: &mut Context<Self>,
18940    ) {
18941        self.display_map
18942            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18943        if let Some(autoscroll) = autoscroll {
18944            self.request_autoscroll(autoscroll, cx);
18945        }
18946        cx.notify();
18947    }
18948
18949    pub fn replace_blocks(
18950        &mut self,
18951        renderers: HashMap<CustomBlockId, RenderBlock>,
18952        autoscroll: Option<Autoscroll>,
18953        cx: &mut Context<Self>,
18954    ) {
18955        self.display_map
18956            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18957        if let Some(autoscroll) = autoscroll {
18958            self.request_autoscroll(autoscroll, cx);
18959        }
18960        cx.notify();
18961    }
18962
18963    pub fn remove_blocks(
18964        &mut self,
18965        block_ids: HashSet<CustomBlockId>,
18966        autoscroll: Option<Autoscroll>,
18967        cx: &mut Context<Self>,
18968    ) {
18969        self.display_map.update(cx, |display_map, cx| {
18970            display_map.remove_blocks(block_ids, cx)
18971        });
18972        if let Some(autoscroll) = autoscroll {
18973            self.request_autoscroll(autoscroll, cx);
18974        }
18975        cx.notify();
18976    }
18977
18978    pub fn row_for_block(
18979        &self,
18980        block_id: CustomBlockId,
18981        cx: &mut Context<Self>,
18982    ) -> Option<DisplayRow> {
18983        self.display_map
18984            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18985    }
18986
18987    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18988        self.focused_block = Some(focused_block);
18989    }
18990
18991    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18992        self.focused_block.take()
18993    }
18994
18995    pub fn insert_creases(
18996        &mut self,
18997        creases: impl IntoIterator<Item = Crease<Anchor>>,
18998        cx: &mut Context<Self>,
18999    ) -> Vec<CreaseId> {
19000        self.display_map
19001            .update(cx, |map, cx| map.insert_creases(creases, cx))
19002    }
19003
19004    pub fn remove_creases(
19005        &mut self,
19006        ids: impl IntoIterator<Item = CreaseId>,
19007        cx: &mut Context<Self>,
19008    ) -> Vec<(CreaseId, Range<Anchor>)> {
19009        self.display_map
19010            .update(cx, |map, cx| map.remove_creases(ids, cx))
19011    }
19012
19013    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19014        self.display_map
19015            .update(cx, |map, cx| map.snapshot(cx))
19016            .longest_row()
19017    }
19018
19019    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19020        self.display_map
19021            .update(cx, |map, cx| map.snapshot(cx))
19022            .max_point()
19023    }
19024
19025    pub fn text(&self, cx: &App) -> String {
19026        self.buffer.read(cx).read(cx).text()
19027    }
19028
19029    pub fn is_empty(&self, cx: &App) -> bool {
19030        self.buffer.read(cx).read(cx).is_empty()
19031    }
19032
19033    pub fn text_option(&self, cx: &App) -> Option<String> {
19034        let text = self.text(cx);
19035        let text = text.trim();
19036
19037        if text.is_empty() {
19038            return None;
19039        }
19040
19041        Some(text.to_string())
19042    }
19043
19044    pub fn set_text(
19045        &mut self,
19046        text: impl Into<Arc<str>>,
19047        window: &mut Window,
19048        cx: &mut Context<Self>,
19049    ) {
19050        self.transact(window, cx, |this, _, cx| {
19051            this.buffer
19052                .read(cx)
19053                .as_singleton()
19054                .expect("you can only call set_text on editors for singleton buffers")
19055                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19056        });
19057    }
19058
19059    pub fn display_text(&self, cx: &mut App) -> String {
19060        self.display_map
19061            .update(cx, |map, cx| map.snapshot(cx))
19062            .text()
19063    }
19064
19065    fn create_minimap(
19066        &self,
19067        minimap_settings: MinimapSettings,
19068        window: &mut Window,
19069        cx: &mut Context<Self>,
19070    ) -> Option<Entity<Self>> {
19071        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19072            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19073    }
19074
19075    fn initialize_new_minimap(
19076        &self,
19077        minimap_settings: MinimapSettings,
19078        window: &mut Window,
19079        cx: &mut Context<Self>,
19080    ) -> Entity<Self> {
19081        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19082
19083        let mut minimap = Editor::new_internal(
19084            EditorMode::Minimap {
19085                parent: cx.weak_entity(),
19086            },
19087            self.buffer.clone(),
19088            None,
19089            Some(self.display_map.clone()),
19090            window,
19091            cx,
19092        );
19093        minimap.scroll_manager.clone_state(&self.scroll_manager);
19094        minimap.set_text_style_refinement(TextStyleRefinement {
19095            font_size: Some(MINIMAP_FONT_SIZE),
19096            font_weight: Some(MINIMAP_FONT_WEIGHT),
19097            ..Default::default()
19098        });
19099        minimap.update_minimap_configuration(minimap_settings, cx);
19100        cx.new(|_| minimap)
19101    }
19102
19103    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19104        let current_line_highlight = minimap_settings
19105            .current_line_highlight
19106            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19107        self.set_current_line_highlight(Some(current_line_highlight));
19108    }
19109
19110    pub fn minimap(&self) -> Option<&Entity<Self>> {
19111        self.minimap
19112            .as_ref()
19113            .filter(|_| self.minimap_visibility.visible())
19114    }
19115
19116    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19117        let mut wrap_guides = smallvec![];
19118
19119        if self.show_wrap_guides == Some(false) {
19120            return wrap_guides;
19121        }
19122
19123        let settings = self.buffer.read(cx).language_settings(cx);
19124        if settings.show_wrap_guides {
19125            match self.soft_wrap_mode(cx) {
19126                SoftWrap::Column(soft_wrap) => {
19127                    wrap_guides.push((soft_wrap as usize, true));
19128                }
19129                SoftWrap::Bounded(soft_wrap) => {
19130                    wrap_guides.push((soft_wrap as usize, true));
19131                }
19132                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19133            }
19134            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19135        }
19136
19137        wrap_guides
19138    }
19139
19140    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19141        let settings = self.buffer.read(cx).language_settings(cx);
19142        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19143        match mode {
19144            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19145                SoftWrap::None
19146            }
19147            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19148            language_settings::SoftWrap::PreferredLineLength => {
19149                SoftWrap::Column(settings.preferred_line_length)
19150            }
19151            language_settings::SoftWrap::Bounded => {
19152                SoftWrap::Bounded(settings.preferred_line_length)
19153            }
19154        }
19155    }
19156
19157    pub fn set_soft_wrap_mode(
19158        &mut self,
19159        mode: language_settings::SoftWrap,
19160
19161        cx: &mut Context<Self>,
19162    ) {
19163        self.soft_wrap_mode_override = Some(mode);
19164        cx.notify();
19165    }
19166
19167    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19168        self.hard_wrap = hard_wrap;
19169        cx.notify();
19170    }
19171
19172    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19173        self.text_style_refinement = Some(style);
19174    }
19175
19176    /// called by the Element so we know what style we were most recently rendered with.
19177    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19178        // We intentionally do not inform the display map about the minimap style
19179        // so that wrapping is not recalculated and stays consistent for the editor
19180        // and its linked minimap.
19181        if !self.mode.is_minimap() {
19182            let font = style.text.font();
19183            let font_size = style.text.font_size.to_pixels(window.rem_size());
19184            let display_map = self
19185                .placeholder_display_map
19186                .as_ref()
19187                .filter(|_| self.is_empty(cx))
19188                .unwrap_or(&self.display_map);
19189
19190            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19191        }
19192        self.style = Some(style);
19193    }
19194
19195    pub fn style(&self) -> Option<&EditorStyle> {
19196        self.style.as_ref()
19197    }
19198
19199    // Called by the element. This method is not designed to be called outside of the editor
19200    // element's layout code because it does not notify when rewrapping is computed synchronously.
19201    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19202        if self.is_empty(cx) {
19203            self.placeholder_display_map
19204                .as_ref()
19205                .map_or(false, |display_map| {
19206                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19207                })
19208        } else {
19209            self.display_map
19210                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19211        }
19212    }
19213
19214    pub fn set_soft_wrap(&mut self) {
19215        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19216    }
19217
19218    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19219        if self.soft_wrap_mode_override.is_some() {
19220            self.soft_wrap_mode_override.take();
19221        } else {
19222            let soft_wrap = match self.soft_wrap_mode(cx) {
19223                SoftWrap::GitDiff => return,
19224                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19225                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19226                    language_settings::SoftWrap::None
19227                }
19228            };
19229            self.soft_wrap_mode_override = Some(soft_wrap);
19230        }
19231        cx.notify();
19232    }
19233
19234    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19235        let Some(workspace) = self.workspace() else {
19236            return;
19237        };
19238        let fs = workspace.read(cx).app_state().fs.clone();
19239        let current_show = TabBarSettings::get_global(cx).show;
19240        update_settings_file(fs, cx, move |setting, _| {
19241            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19242        });
19243    }
19244
19245    pub fn toggle_indent_guides(
19246        &mut self,
19247        _: &ToggleIndentGuides,
19248        _: &mut Window,
19249        cx: &mut Context<Self>,
19250    ) {
19251        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19252            self.buffer
19253                .read(cx)
19254                .language_settings(cx)
19255                .indent_guides
19256                .enabled
19257        });
19258        self.show_indent_guides = Some(!currently_enabled);
19259        cx.notify();
19260    }
19261
19262    fn should_show_indent_guides(&self) -> Option<bool> {
19263        self.show_indent_guides
19264    }
19265
19266    pub fn toggle_line_numbers(
19267        &mut self,
19268        _: &ToggleLineNumbers,
19269        _: &mut Window,
19270        cx: &mut Context<Self>,
19271    ) {
19272        let mut editor_settings = EditorSettings::get_global(cx).clone();
19273        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19274        EditorSettings::override_global(editor_settings, cx);
19275    }
19276
19277    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19278        if let Some(show_line_numbers) = self.show_line_numbers {
19279            return show_line_numbers;
19280        }
19281        EditorSettings::get_global(cx).gutter.line_numbers
19282    }
19283
19284    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19285        self.use_relative_line_numbers
19286            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19287    }
19288
19289    pub fn toggle_relative_line_numbers(
19290        &mut self,
19291        _: &ToggleRelativeLineNumbers,
19292        _: &mut Window,
19293        cx: &mut Context<Self>,
19294    ) {
19295        let is_relative = self.should_use_relative_line_numbers(cx);
19296        self.set_relative_line_number(Some(!is_relative), cx)
19297    }
19298
19299    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19300        self.use_relative_line_numbers = is_relative;
19301        cx.notify();
19302    }
19303
19304    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19305        self.show_gutter = show_gutter;
19306        cx.notify();
19307    }
19308
19309    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19310        self.show_scrollbars = ScrollbarAxes {
19311            horizontal: show,
19312            vertical: show,
19313        };
19314        cx.notify();
19315    }
19316
19317    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19318        self.show_scrollbars.vertical = show;
19319        cx.notify();
19320    }
19321
19322    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19323        self.show_scrollbars.horizontal = show;
19324        cx.notify();
19325    }
19326
19327    pub fn set_minimap_visibility(
19328        &mut self,
19329        minimap_visibility: MinimapVisibility,
19330        window: &mut Window,
19331        cx: &mut Context<Self>,
19332    ) {
19333        if self.minimap_visibility != minimap_visibility {
19334            if minimap_visibility.visible() && self.minimap.is_none() {
19335                let minimap_settings = EditorSettings::get_global(cx).minimap;
19336                self.minimap =
19337                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19338            }
19339            self.minimap_visibility = minimap_visibility;
19340            cx.notify();
19341        }
19342    }
19343
19344    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19345        self.set_show_scrollbars(false, cx);
19346        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19347    }
19348
19349    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19350        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19351    }
19352
19353    /// Normally the text in full mode and auto height editors is padded on the
19354    /// left side by roughly half a character width for improved hit testing.
19355    ///
19356    /// Use this method to disable this for cases where this is not wanted (e.g.
19357    /// if you want to align the editor text with some other text above or below)
19358    /// or if you want to add this padding to single-line editors.
19359    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19360        self.offset_content = offset_content;
19361        cx.notify();
19362    }
19363
19364    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19365        self.show_line_numbers = Some(show_line_numbers);
19366        cx.notify();
19367    }
19368
19369    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19370        self.disable_expand_excerpt_buttons = true;
19371        cx.notify();
19372    }
19373
19374    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19375        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19376        cx.notify();
19377    }
19378
19379    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19380        self.show_code_actions = Some(show_code_actions);
19381        cx.notify();
19382    }
19383
19384    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19385        self.show_runnables = Some(show_runnables);
19386        cx.notify();
19387    }
19388
19389    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19390        self.show_breakpoints = Some(show_breakpoints);
19391        cx.notify();
19392    }
19393
19394    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19395        if self.display_map.read(cx).masked != masked {
19396            self.display_map.update(cx, |map, _| map.masked = masked);
19397        }
19398        cx.notify()
19399    }
19400
19401    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19402        self.show_wrap_guides = Some(show_wrap_guides);
19403        cx.notify();
19404    }
19405
19406    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19407        self.show_indent_guides = Some(show_indent_guides);
19408        cx.notify();
19409    }
19410
19411    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19412        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19413            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19414                && let Some(dir) = file.abs_path(cx).parent()
19415            {
19416                return Some(dir.to_owned());
19417            }
19418        }
19419
19420        None
19421    }
19422
19423    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19424        self.active_excerpt(cx)?
19425            .1
19426            .read(cx)
19427            .file()
19428            .and_then(|f| f.as_local())
19429    }
19430
19431    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19432        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19433            let buffer = buffer.read(cx);
19434            if let Some(project_path) = buffer.project_path(cx) {
19435                let project = self.project()?.read(cx);
19436                project.absolute_path(&project_path, cx)
19437            } else {
19438                buffer
19439                    .file()
19440                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19441            }
19442        })
19443    }
19444
19445    pub fn reveal_in_finder(
19446        &mut self,
19447        _: &RevealInFileManager,
19448        _window: &mut Window,
19449        cx: &mut Context<Self>,
19450    ) {
19451        if let Some(target) = self.target_file(cx) {
19452            cx.reveal_path(&target.abs_path(cx));
19453        }
19454    }
19455
19456    pub fn copy_path(
19457        &mut self,
19458        _: &zed_actions::workspace::CopyPath,
19459        _window: &mut Window,
19460        cx: &mut Context<Self>,
19461    ) {
19462        if let Some(path) = self.target_file_abs_path(cx)
19463            && let Some(path) = path.to_str()
19464        {
19465            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19466        } else {
19467            cx.propagate();
19468        }
19469    }
19470
19471    pub fn copy_relative_path(
19472        &mut self,
19473        _: &zed_actions::workspace::CopyRelativePath,
19474        _window: &mut Window,
19475        cx: &mut Context<Self>,
19476    ) {
19477        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19478            let project = self.project()?.read(cx);
19479            let path = buffer.read(cx).file()?.path();
19480            let path = path.display(project.path_style(cx));
19481            Some(path)
19482        }) {
19483            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19484        } else {
19485            cx.propagate();
19486        }
19487    }
19488
19489    /// Returns the project path for the editor's buffer, if any buffer is
19490    /// opened in the editor.
19491    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19492        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19493            buffer.read(cx).project_path(cx)
19494        } else {
19495            None
19496        }
19497    }
19498
19499    // Returns true if the editor handled a go-to-line request
19500    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19501        maybe!({
19502            let breakpoint_store = self.breakpoint_store.as_ref()?;
19503
19504            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19505            else {
19506                self.clear_row_highlights::<ActiveDebugLine>();
19507                return None;
19508            };
19509
19510            let position = active_stack_frame.position;
19511            let buffer_id = position.buffer_id?;
19512            let snapshot = self
19513                .project
19514                .as_ref()?
19515                .read(cx)
19516                .buffer_for_id(buffer_id, cx)?
19517                .read(cx)
19518                .snapshot();
19519
19520            let mut handled = false;
19521            for (id, ExcerptRange { context, .. }) in
19522                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19523            {
19524                if context.start.cmp(&position, &snapshot).is_ge()
19525                    || context.end.cmp(&position, &snapshot).is_lt()
19526                {
19527                    continue;
19528                }
19529                let snapshot = self.buffer.read(cx).snapshot(cx);
19530                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19531
19532                handled = true;
19533                self.clear_row_highlights::<ActiveDebugLine>();
19534
19535                self.go_to_line::<ActiveDebugLine>(
19536                    multibuffer_anchor,
19537                    Some(cx.theme().colors().editor_debugger_active_line_background),
19538                    window,
19539                    cx,
19540                );
19541
19542                cx.notify();
19543            }
19544
19545            handled.then_some(())
19546        })
19547        .is_some()
19548    }
19549
19550    pub fn copy_file_name_without_extension(
19551        &mut self,
19552        _: &CopyFileNameWithoutExtension,
19553        _: &mut Window,
19554        cx: &mut Context<Self>,
19555    ) {
19556        if let Some(file) = self.target_file(cx)
19557            && let Some(file_stem) = file.path().file_stem()
19558        {
19559            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19560        }
19561    }
19562
19563    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19564        if let Some(file) = self.target_file(cx)
19565            && let Some(name) = file.path().file_name()
19566        {
19567            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19568        }
19569    }
19570
19571    pub fn toggle_git_blame(
19572        &mut self,
19573        _: &::git::Blame,
19574        window: &mut Window,
19575        cx: &mut Context<Self>,
19576    ) {
19577        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19578
19579        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19580            self.start_git_blame(true, window, cx);
19581        }
19582
19583        cx.notify();
19584    }
19585
19586    pub fn toggle_git_blame_inline(
19587        &mut self,
19588        _: &ToggleGitBlameInline,
19589        window: &mut Window,
19590        cx: &mut Context<Self>,
19591    ) {
19592        self.toggle_git_blame_inline_internal(true, window, cx);
19593        cx.notify();
19594    }
19595
19596    pub fn open_git_blame_commit(
19597        &mut self,
19598        _: &OpenGitBlameCommit,
19599        window: &mut Window,
19600        cx: &mut Context<Self>,
19601    ) {
19602        self.open_git_blame_commit_internal(window, cx);
19603    }
19604
19605    fn open_git_blame_commit_internal(
19606        &mut self,
19607        window: &mut Window,
19608        cx: &mut Context<Self>,
19609    ) -> Option<()> {
19610        let blame = self.blame.as_ref()?;
19611        let snapshot = self.snapshot(window, cx);
19612        let cursor = self.selections.newest::<Point>(cx).head();
19613        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19614        let (_, blame_entry) = blame
19615            .update(cx, |blame, cx| {
19616                blame
19617                    .blame_for_rows(
19618                        &[RowInfo {
19619                            buffer_id: Some(buffer.remote_id()),
19620                            buffer_row: Some(point.row),
19621                            ..Default::default()
19622                        }],
19623                        cx,
19624                    )
19625                    .next()
19626            })
19627            .flatten()?;
19628        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19629        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19630        let workspace = self.workspace()?.downgrade();
19631        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19632        None
19633    }
19634
19635    pub fn git_blame_inline_enabled(&self) -> bool {
19636        self.git_blame_inline_enabled
19637    }
19638
19639    pub fn toggle_selection_menu(
19640        &mut self,
19641        _: &ToggleSelectionMenu,
19642        _: &mut Window,
19643        cx: &mut Context<Self>,
19644    ) {
19645        self.show_selection_menu = self
19646            .show_selection_menu
19647            .map(|show_selections_menu| !show_selections_menu)
19648            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19649
19650        cx.notify();
19651    }
19652
19653    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19654        self.show_selection_menu
19655            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19656    }
19657
19658    fn start_git_blame(
19659        &mut self,
19660        user_triggered: bool,
19661        window: &mut Window,
19662        cx: &mut Context<Self>,
19663    ) {
19664        if let Some(project) = self.project() {
19665            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19666                && buffer.read(cx).file().is_none()
19667            {
19668                return;
19669            }
19670
19671            let focused = self.focus_handle(cx).contains_focused(window, cx);
19672
19673            let project = project.clone();
19674            let blame = cx
19675                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19676            self.blame_subscription =
19677                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19678            self.blame = Some(blame);
19679        }
19680    }
19681
19682    fn toggle_git_blame_inline_internal(
19683        &mut self,
19684        user_triggered: bool,
19685        window: &mut Window,
19686        cx: &mut Context<Self>,
19687    ) {
19688        if self.git_blame_inline_enabled {
19689            self.git_blame_inline_enabled = false;
19690            self.show_git_blame_inline = false;
19691            self.show_git_blame_inline_delay_task.take();
19692        } else {
19693            self.git_blame_inline_enabled = true;
19694            self.start_git_blame_inline(user_triggered, window, cx);
19695        }
19696
19697        cx.notify();
19698    }
19699
19700    fn start_git_blame_inline(
19701        &mut self,
19702        user_triggered: bool,
19703        window: &mut Window,
19704        cx: &mut Context<Self>,
19705    ) {
19706        self.start_git_blame(user_triggered, window, cx);
19707
19708        if ProjectSettings::get_global(cx)
19709            .git
19710            .inline_blame_delay()
19711            .is_some()
19712        {
19713            self.start_inline_blame_timer(window, cx);
19714        } else {
19715            self.show_git_blame_inline = true
19716        }
19717    }
19718
19719    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19720        self.blame.as_ref()
19721    }
19722
19723    pub fn show_git_blame_gutter(&self) -> bool {
19724        self.show_git_blame_gutter
19725    }
19726
19727    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19728        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19729    }
19730
19731    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19732        self.show_git_blame_inline
19733            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19734            && !self.newest_selection_head_on_empty_line(cx)
19735            && self.has_blame_entries(cx)
19736    }
19737
19738    fn has_blame_entries(&self, cx: &App) -> bool {
19739        self.blame()
19740            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19741    }
19742
19743    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19744        let cursor_anchor = self.selections.newest_anchor().head();
19745
19746        let snapshot = self.buffer.read(cx).snapshot(cx);
19747        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19748
19749        snapshot.line_len(buffer_row) == 0
19750    }
19751
19752    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19753        let buffer_and_selection = maybe!({
19754            let selection = self.selections.newest::<Point>(cx);
19755            let selection_range = selection.range();
19756
19757            let multi_buffer = self.buffer().read(cx);
19758            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19759            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19760
19761            let (buffer, range, _) = if selection.reversed {
19762                buffer_ranges.first()
19763            } else {
19764                buffer_ranges.last()
19765            }?;
19766
19767            let selection = text::ToPoint::to_point(&range.start, buffer).row
19768                ..text::ToPoint::to_point(&range.end, buffer).row;
19769            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19770        });
19771
19772        let Some((buffer, selection)) = buffer_and_selection else {
19773            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19774        };
19775
19776        let Some(project) = self.project() else {
19777            return Task::ready(Err(anyhow!("editor does not have project")));
19778        };
19779
19780        project.update(cx, |project, cx| {
19781            project.get_permalink_to_line(&buffer, selection, cx)
19782        })
19783    }
19784
19785    pub fn copy_permalink_to_line(
19786        &mut self,
19787        _: &CopyPermalinkToLine,
19788        window: &mut Window,
19789        cx: &mut Context<Self>,
19790    ) {
19791        let permalink_task = self.get_permalink_to_line(cx);
19792        let workspace = self.workspace();
19793
19794        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19795            Ok(permalink) => {
19796                cx.update(|_, cx| {
19797                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19798                })
19799                .ok();
19800            }
19801            Err(err) => {
19802                let message = format!("Failed to copy permalink: {err}");
19803
19804                anyhow::Result::<()>::Err(err).log_err();
19805
19806                if let Some(workspace) = workspace {
19807                    workspace
19808                        .update_in(cx, |workspace, _, cx| {
19809                            struct CopyPermalinkToLine;
19810
19811                            workspace.show_toast(
19812                                Toast::new(
19813                                    NotificationId::unique::<CopyPermalinkToLine>(),
19814                                    message,
19815                                ),
19816                                cx,
19817                            )
19818                        })
19819                        .ok();
19820                }
19821            }
19822        })
19823        .detach();
19824    }
19825
19826    pub fn copy_file_location(
19827        &mut self,
19828        _: &CopyFileLocation,
19829        _: &mut Window,
19830        cx: &mut Context<Self>,
19831    ) {
19832        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19833        if let Some(file) = self.target_file(cx) {
19834            let path = file.path().display(file.path_style(cx));
19835            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19836        }
19837    }
19838
19839    pub fn open_permalink_to_line(
19840        &mut self,
19841        _: &OpenPermalinkToLine,
19842        window: &mut Window,
19843        cx: &mut Context<Self>,
19844    ) {
19845        let permalink_task = self.get_permalink_to_line(cx);
19846        let workspace = self.workspace();
19847
19848        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19849            Ok(permalink) => {
19850                cx.update(|_, cx| {
19851                    cx.open_url(permalink.as_ref());
19852                })
19853                .ok();
19854            }
19855            Err(err) => {
19856                let message = format!("Failed to open permalink: {err}");
19857
19858                anyhow::Result::<()>::Err(err).log_err();
19859
19860                if let Some(workspace) = workspace {
19861                    workspace
19862                        .update(cx, |workspace, cx| {
19863                            struct OpenPermalinkToLine;
19864
19865                            workspace.show_toast(
19866                                Toast::new(
19867                                    NotificationId::unique::<OpenPermalinkToLine>(),
19868                                    message,
19869                                ),
19870                                cx,
19871                            )
19872                        })
19873                        .ok();
19874                }
19875            }
19876        })
19877        .detach();
19878    }
19879
19880    pub fn insert_uuid_v4(
19881        &mut self,
19882        _: &InsertUuidV4,
19883        window: &mut Window,
19884        cx: &mut Context<Self>,
19885    ) {
19886        self.insert_uuid(UuidVersion::V4, window, cx);
19887    }
19888
19889    pub fn insert_uuid_v7(
19890        &mut self,
19891        _: &InsertUuidV7,
19892        window: &mut Window,
19893        cx: &mut Context<Self>,
19894    ) {
19895        self.insert_uuid(UuidVersion::V7, window, cx);
19896    }
19897
19898    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19899        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19900        self.transact(window, cx, |this, window, cx| {
19901            let edits = this
19902                .selections
19903                .all::<Point>(cx)
19904                .into_iter()
19905                .map(|selection| {
19906                    let uuid = match version {
19907                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19908                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19909                    };
19910
19911                    (selection.range(), uuid.to_string())
19912                });
19913            this.edit(edits, cx);
19914            this.refresh_edit_prediction(true, false, window, cx);
19915        });
19916    }
19917
19918    pub fn open_selections_in_multibuffer(
19919        &mut self,
19920        _: &OpenSelectionsInMultibuffer,
19921        window: &mut Window,
19922        cx: &mut Context<Self>,
19923    ) {
19924        let multibuffer = self.buffer.read(cx);
19925
19926        let Some(buffer) = multibuffer.as_singleton() else {
19927            return;
19928        };
19929
19930        let Some(workspace) = self.workspace() else {
19931            return;
19932        };
19933
19934        let title = multibuffer.title(cx).to_string();
19935
19936        let locations = self
19937            .selections
19938            .all_anchors(cx)
19939            .iter()
19940            .map(|selection| {
19941                (
19942                    buffer.clone(),
19943                    (selection.start.text_anchor..selection.end.text_anchor)
19944                        .to_point(buffer.read(cx)),
19945                )
19946            })
19947            .into_group_map();
19948
19949        cx.spawn_in(window, async move |_, cx| {
19950            workspace.update_in(cx, |workspace, window, cx| {
19951                Self::open_locations_in_multibuffer(
19952                    workspace,
19953                    locations,
19954                    format!("Selections for '{title}'"),
19955                    false,
19956                    MultibufferSelectionMode::All,
19957                    window,
19958                    cx,
19959                );
19960            })
19961        })
19962        .detach();
19963    }
19964
19965    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19966    /// last highlight added will be used.
19967    ///
19968    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19969    pub fn highlight_rows<T: 'static>(
19970        &mut self,
19971        range: Range<Anchor>,
19972        color: Hsla,
19973        options: RowHighlightOptions,
19974        cx: &mut Context<Self>,
19975    ) {
19976        let snapshot = self.buffer().read(cx).snapshot(cx);
19977        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19978        let ix = row_highlights.binary_search_by(|highlight| {
19979            Ordering::Equal
19980                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19981                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19982        });
19983
19984        if let Err(mut ix) = ix {
19985            let index = post_inc(&mut self.highlight_order);
19986
19987            // If this range intersects with the preceding highlight, then merge it with
19988            // the preceding highlight. Otherwise insert a new highlight.
19989            let mut merged = false;
19990            if ix > 0 {
19991                let prev_highlight = &mut row_highlights[ix - 1];
19992                if prev_highlight
19993                    .range
19994                    .end
19995                    .cmp(&range.start, &snapshot)
19996                    .is_ge()
19997                {
19998                    ix -= 1;
19999                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20000                        prev_highlight.range.end = range.end;
20001                    }
20002                    merged = true;
20003                    prev_highlight.index = index;
20004                    prev_highlight.color = color;
20005                    prev_highlight.options = options;
20006                }
20007            }
20008
20009            if !merged {
20010                row_highlights.insert(
20011                    ix,
20012                    RowHighlight {
20013                        range,
20014                        index,
20015                        color,
20016                        options,
20017                        type_id: TypeId::of::<T>(),
20018                    },
20019                );
20020            }
20021
20022            // If any of the following highlights intersect with this one, merge them.
20023            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20024                let highlight = &row_highlights[ix];
20025                if next_highlight
20026                    .range
20027                    .start
20028                    .cmp(&highlight.range.end, &snapshot)
20029                    .is_le()
20030                {
20031                    if next_highlight
20032                        .range
20033                        .end
20034                        .cmp(&highlight.range.end, &snapshot)
20035                        .is_gt()
20036                    {
20037                        row_highlights[ix].range.end = next_highlight.range.end;
20038                    }
20039                    row_highlights.remove(ix + 1);
20040                } else {
20041                    break;
20042                }
20043            }
20044        }
20045    }
20046
20047    /// Remove any highlighted row ranges of the given type that intersect the
20048    /// given ranges.
20049    pub fn remove_highlighted_rows<T: 'static>(
20050        &mut self,
20051        ranges_to_remove: Vec<Range<Anchor>>,
20052        cx: &mut Context<Self>,
20053    ) {
20054        let snapshot = self.buffer().read(cx).snapshot(cx);
20055        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20056        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20057        row_highlights.retain(|highlight| {
20058            while let Some(range_to_remove) = ranges_to_remove.peek() {
20059                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20060                    Ordering::Less | Ordering::Equal => {
20061                        ranges_to_remove.next();
20062                    }
20063                    Ordering::Greater => {
20064                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20065                            Ordering::Less | Ordering::Equal => {
20066                                return false;
20067                            }
20068                            Ordering::Greater => break,
20069                        }
20070                    }
20071                }
20072            }
20073
20074            true
20075        })
20076    }
20077
20078    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20079    pub fn clear_row_highlights<T: 'static>(&mut self) {
20080        self.highlighted_rows.remove(&TypeId::of::<T>());
20081    }
20082
20083    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20084    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20085        self.highlighted_rows
20086            .get(&TypeId::of::<T>())
20087            .map_or(&[] as &[_], |vec| vec.as_slice())
20088            .iter()
20089            .map(|highlight| (highlight.range.clone(), highlight.color))
20090    }
20091
20092    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20093    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20094    /// Allows to ignore certain kinds of highlights.
20095    pub fn highlighted_display_rows(
20096        &self,
20097        window: &mut Window,
20098        cx: &mut App,
20099    ) -> BTreeMap<DisplayRow, LineHighlight> {
20100        let snapshot = self.snapshot(window, cx);
20101        let mut used_highlight_orders = HashMap::default();
20102        self.highlighted_rows
20103            .iter()
20104            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20105            .fold(
20106                BTreeMap::<DisplayRow, LineHighlight>::new(),
20107                |mut unique_rows, highlight| {
20108                    let start = highlight.range.start.to_display_point(&snapshot);
20109                    let end = highlight.range.end.to_display_point(&snapshot);
20110                    let start_row = start.row().0;
20111                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20112                        && end.column() == 0
20113                    {
20114                        end.row().0.saturating_sub(1)
20115                    } else {
20116                        end.row().0
20117                    };
20118                    for row in start_row..=end_row {
20119                        let used_index =
20120                            used_highlight_orders.entry(row).or_insert(highlight.index);
20121                        if highlight.index >= *used_index {
20122                            *used_index = highlight.index;
20123                            unique_rows.insert(
20124                                DisplayRow(row),
20125                                LineHighlight {
20126                                    include_gutter: highlight.options.include_gutter,
20127                                    border: None,
20128                                    background: highlight.color.into(),
20129                                    type_id: Some(highlight.type_id),
20130                                },
20131                            );
20132                        }
20133                    }
20134                    unique_rows
20135                },
20136            )
20137    }
20138
20139    pub fn highlighted_display_row_for_autoscroll(
20140        &self,
20141        snapshot: &DisplaySnapshot,
20142    ) -> Option<DisplayRow> {
20143        self.highlighted_rows
20144            .values()
20145            .flat_map(|highlighted_rows| highlighted_rows.iter())
20146            .filter_map(|highlight| {
20147                if highlight.options.autoscroll {
20148                    Some(highlight.range.start.to_display_point(snapshot).row())
20149                } else {
20150                    None
20151                }
20152            })
20153            .min()
20154    }
20155
20156    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20157        self.highlight_background::<SearchWithinRange>(
20158            ranges,
20159            |colors| colors.colors().editor_document_highlight_read_background,
20160            cx,
20161        )
20162    }
20163
20164    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20165        self.breadcrumb_header = Some(new_header);
20166    }
20167
20168    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20169        self.clear_background_highlights::<SearchWithinRange>(cx);
20170    }
20171
20172    pub fn highlight_background<T: 'static>(
20173        &mut self,
20174        ranges: &[Range<Anchor>],
20175        color_fetcher: fn(&Theme) -> Hsla,
20176        cx: &mut Context<Self>,
20177    ) {
20178        self.background_highlights.insert(
20179            HighlightKey::Type(TypeId::of::<T>()),
20180            (color_fetcher, Arc::from(ranges)),
20181        );
20182        self.scrollbar_marker_state.dirty = true;
20183        cx.notify();
20184    }
20185
20186    pub fn highlight_background_key<T: 'static>(
20187        &mut self,
20188        key: usize,
20189        ranges: &[Range<Anchor>],
20190        color_fetcher: fn(&Theme) -> Hsla,
20191        cx: &mut Context<Self>,
20192    ) {
20193        self.background_highlights.insert(
20194            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20195            (color_fetcher, Arc::from(ranges)),
20196        );
20197        self.scrollbar_marker_state.dirty = true;
20198        cx.notify();
20199    }
20200
20201    pub fn clear_background_highlights<T: 'static>(
20202        &mut self,
20203        cx: &mut Context<Self>,
20204    ) -> Option<BackgroundHighlight> {
20205        let text_highlights = self
20206            .background_highlights
20207            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20208        if !text_highlights.1.is_empty() {
20209            self.scrollbar_marker_state.dirty = true;
20210            cx.notify();
20211        }
20212        Some(text_highlights)
20213    }
20214
20215    pub fn highlight_gutter<T: 'static>(
20216        &mut self,
20217        ranges: impl Into<Vec<Range<Anchor>>>,
20218        color_fetcher: fn(&App) -> Hsla,
20219        cx: &mut Context<Self>,
20220    ) {
20221        self.gutter_highlights
20222            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20223        cx.notify();
20224    }
20225
20226    pub fn clear_gutter_highlights<T: 'static>(
20227        &mut self,
20228        cx: &mut Context<Self>,
20229    ) -> Option<GutterHighlight> {
20230        cx.notify();
20231        self.gutter_highlights.remove(&TypeId::of::<T>())
20232    }
20233
20234    pub fn insert_gutter_highlight<T: 'static>(
20235        &mut self,
20236        range: Range<Anchor>,
20237        color_fetcher: fn(&App) -> Hsla,
20238        cx: &mut Context<Self>,
20239    ) {
20240        let snapshot = self.buffer().read(cx).snapshot(cx);
20241        let mut highlights = self
20242            .gutter_highlights
20243            .remove(&TypeId::of::<T>())
20244            .map(|(_, highlights)| highlights)
20245            .unwrap_or_default();
20246        let ix = highlights.binary_search_by(|highlight| {
20247            Ordering::Equal
20248                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20249                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20250        });
20251        if let Err(ix) = ix {
20252            highlights.insert(ix, range);
20253        }
20254        self.gutter_highlights
20255            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20256    }
20257
20258    pub fn remove_gutter_highlights<T: 'static>(
20259        &mut self,
20260        ranges_to_remove: Vec<Range<Anchor>>,
20261        cx: &mut Context<Self>,
20262    ) {
20263        let snapshot = self.buffer().read(cx).snapshot(cx);
20264        let Some((color_fetcher, mut gutter_highlights)) =
20265            self.gutter_highlights.remove(&TypeId::of::<T>())
20266        else {
20267            return;
20268        };
20269        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20270        gutter_highlights.retain(|highlight| {
20271            while let Some(range_to_remove) = ranges_to_remove.peek() {
20272                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20273                    Ordering::Less | Ordering::Equal => {
20274                        ranges_to_remove.next();
20275                    }
20276                    Ordering::Greater => {
20277                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20278                            Ordering::Less | Ordering::Equal => {
20279                                return false;
20280                            }
20281                            Ordering::Greater => break,
20282                        }
20283                    }
20284                }
20285            }
20286
20287            true
20288        });
20289        self.gutter_highlights
20290            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20291    }
20292
20293    #[cfg(feature = "test-support")]
20294    pub fn all_text_highlights(
20295        &self,
20296        window: &mut Window,
20297        cx: &mut Context<Self>,
20298    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20299        let snapshot = self.snapshot(window, cx);
20300        self.display_map.update(cx, |display_map, _| {
20301            display_map
20302                .all_text_highlights()
20303                .map(|highlight| {
20304                    let (style, ranges) = highlight.as_ref();
20305                    (
20306                        *style,
20307                        ranges
20308                            .iter()
20309                            .map(|range| range.clone().to_display_points(&snapshot))
20310                            .collect(),
20311                    )
20312                })
20313                .collect()
20314        })
20315    }
20316
20317    #[cfg(feature = "test-support")]
20318    pub fn all_text_background_highlights(
20319        &self,
20320        window: &mut Window,
20321        cx: &mut Context<Self>,
20322    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20323        let snapshot = self.snapshot(window, cx);
20324        let buffer = &snapshot.buffer_snapshot();
20325        let start = buffer.anchor_before(0);
20326        let end = buffer.anchor_after(buffer.len());
20327        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20328    }
20329
20330    #[cfg(any(test, feature = "test-support"))]
20331    pub fn sorted_background_highlights_in_range(
20332        &self,
20333        search_range: Range<Anchor>,
20334        display_snapshot: &DisplaySnapshot,
20335        theme: &Theme,
20336    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20337        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20338        res.sort_by(|a, b| {
20339            a.0.start
20340                .cmp(&b.0.start)
20341                .then_with(|| a.0.end.cmp(&b.0.end))
20342                .then_with(|| a.1.cmp(&b.1))
20343        });
20344        res
20345    }
20346
20347    #[cfg(feature = "test-support")]
20348    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20349        let snapshot = self.buffer().read(cx).snapshot(cx);
20350
20351        let highlights = self
20352            .background_highlights
20353            .get(&HighlightKey::Type(TypeId::of::<
20354                items::BufferSearchHighlights,
20355            >()));
20356
20357        if let Some((_color, ranges)) = highlights {
20358            ranges
20359                .iter()
20360                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20361                .collect_vec()
20362        } else {
20363            vec![]
20364        }
20365    }
20366
20367    fn document_highlights_for_position<'a>(
20368        &'a self,
20369        position: Anchor,
20370        buffer: &'a MultiBufferSnapshot,
20371    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20372        let read_highlights = self
20373            .background_highlights
20374            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20375            .map(|h| &h.1);
20376        let write_highlights = self
20377            .background_highlights
20378            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20379            .map(|h| &h.1);
20380        let left_position = position.bias_left(buffer);
20381        let right_position = position.bias_right(buffer);
20382        read_highlights
20383            .into_iter()
20384            .chain(write_highlights)
20385            .flat_map(move |ranges| {
20386                let start_ix = match ranges.binary_search_by(|probe| {
20387                    let cmp = probe.end.cmp(&left_position, buffer);
20388                    if cmp.is_ge() {
20389                        Ordering::Greater
20390                    } else {
20391                        Ordering::Less
20392                    }
20393                }) {
20394                    Ok(i) | Err(i) => i,
20395                };
20396
20397                ranges[start_ix..]
20398                    .iter()
20399                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20400            })
20401    }
20402
20403    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20404        self.background_highlights
20405            .get(&HighlightKey::Type(TypeId::of::<T>()))
20406            .is_some_and(|(_, highlights)| !highlights.is_empty())
20407    }
20408
20409    /// Returns all background highlights for a given range.
20410    ///
20411    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20412    pub fn background_highlights_in_range(
20413        &self,
20414        search_range: Range<Anchor>,
20415        display_snapshot: &DisplaySnapshot,
20416        theme: &Theme,
20417    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20418        let mut results = Vec::new();
20419        for (color_fetcher, ranges) in self.background_highlights.values() {
20420            let color = color_fetcher(theme);
20421            let start_ix = match ranges.binary_search_by(|probe| {
20422                let cmp = probe
20423                    .end
20424                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20425                if cmp.is_gt() {
20426                    Ordering::Greater
20427                } else {
20428                    Ordering::Less
20429                }
20430            }) {
20431                Ok(i) | Err(i) => i,
20432            };
20433            for range in &ranges[start_ix..] {
20434                if range
20435                    .start
20436                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20437                    .is_ge()
20438                {
20439                    break;
20440                }
20441
20442                let start = range.start.to_display_point(display_snapshot);
20443                let end = range.end.to_display_point(display_snapshot);
20444                results.push((start..end, color))
20445            }
20446        }
20447        results
20448    }
20449
20450    pub fn gutter_highlights_in_range(
20451        &self,
20452        search_range: Range<Anchor>,
20453        display_snapshot: &DisplaySnapshot,
20454        cx: &App,
20455    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20456        let mut results = Vec::new();
20457        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20458            let color = color_fetcher(cx);
20459            let start_ix = match ranges.binary_search_by(|probe| {
20460                let cmp = probe
20461                    .end
20462                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20463                if cmp.is_gt() {
20464                    Ordering::Greater
20465                } else {
20466                    Ordering::Less
20467                }
20468            }) {
20469                Ok(i) | Err(i) => i,
20470            };
20471            for range in &ranges[start_ix..] {
20472                if range
20473                    .start
20474                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20475                    .is_ge()
20476                {
20477                    break;
20478                }
20479
20480                let start = range.start.to_display_point(display_snapshot);
20481                let end = range.end.to_display_point(display_snapshot);
20482                results.push((start..end, color))
20483            }
20484        }
20485        results
20486    }
20487
20488    /// Get the text ranges corresponding to the redaction query
20489    pub fn redacted_ranges(
20490        &self,
20491        search_range: Range<Anchor>,
20492        display_snapshot: &DisplaySnapshot,
20493        cx: &App,
20494    ) -> Vec<Range<DisplayPoint>> {
20495        display_snapshot
20496            .buffer_snapshot()
20497            .redacted_ranges(search_range, |file| {
20498                if let Some(file) = file {
20499                    file.is_private()
20500                        && EditorSettings::get(
20501                            Some(SettingsLocation {
20502                                worktree_id: file.worktree_id(cx),
20503                                path: file.path().as_ref(),
20504                            }),
20505                            cx,
20506                        )
20507                        .redact_private_values
20508                } else {
20509                    false
20510                }
20511            })
20512            .map(|range| {
20513                range.start.to_display_point(display_snapshot)
20514                    ..range.end.to_display_point(display_snapshot)
20515            })
20516            .collect()
20517    }
20518
20519    pub fn highlight_text_key<T: 'static>(
20520        &mut self,
20521        key: usize,
20522        ranges: Vec<Range<Anchor>>,
20523        style: HighlightStyle,
20524        cx: &mut Context<Self>,
20525    ) {
20526        self.display_map.update(cx, |map, _| {
20527            map.highlight_text(
20528                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20529                ranges,
20530                style,
20531            );
20532        });
20533        cx.notify();
20534    }
20535
20536    pub fn highlight_text<T: 'static>(
20537        &mut self,
20538        ranges: Vec<Range<Anchor>>,
20539        style: HighlightStyle,
20540        cx: &mut Context<Self>,
20541    ) {
20542        self.display_map.update(cx, |map, _| {
20543            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20544        });
20545        cx.notify();
20546    }
20547
20548    pub(crate) fn highlight_inlays<T: 'static>(
20549        &mut self,
20550        highlights: Vec<InlayHighlight>,
20551        style: HighlightStyle,
20552        cx: &mut Context<Self>,
20553    ) {
20554        self.display_map.update(cx, |map, _| {
20555            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20556        });
20557        cx.notify();
20558    }
20559
20560    pub fn text_highlights<'a, T: 'static>(
20561        &'a self,
20562        cx: &'a App,
20563    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20564        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20565    }
20566
20567    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20568        let cleared = self
20569            .display_map
20570            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20571        if cleared {
20572            cx.notify();
20573        }
20574    }
20575
20576    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20577        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20578            && self.focus_handle.is_focused(window)
20579    }
20580
20581    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20582        self.show_cursor_when_unfocused = is_enabled;
20583        cx.notify();
20584    }
20585
20586    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20587        cx.notify();
20588    }
20589
20590    fn on_debug_session_event(
20591        &mut self,
20592        _session: Entity<Session>,
20593        event: &SessionEvent,
20594        cx: &mut Context<Self>,
20595    ) {
20596        if let SessionEvent::InvalidateInlineValue = event {
20597            self.refresh_inline_values(cx);
20598        }
20599    }
20600
20601    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20602        let Some(project) = self.project.clone() else {
20603            return;
20604        };
20605
20606        if !self.inline_value_cache.enabled {
20607            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20608            self.splice_inlays(&inlays, Vec::new(), cx);
20609            return;
20610        }
20611
20612        let current_execution_position = self
20613            .highlighted_rows
20614            .get(&TypeId::of::<ActiveDebugLine>())
20615            .and_then(|lines| lines.last().map(|line| line.range.end));
20616
20617        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20618            let inline_values = editor
20619                .update(cx, |editor, cx| {
20620                    let Some(current_execution_position) = current_execution_position else {
20621                        return Some(Task::ready(Ok(Vec::new())));
20622                    };
20623
20624                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20625                        let snapshot = buffer.snapshot(cx);
20626
20627                        let excerpt = snapshot.excerpt_containing(
20628                            current_execution_position..current_execution_position,
20629                        )?;
20630
20631                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20632                    })?;
20633
20634                    let range =
20635                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20636
20637                    project.inline_values(buffer, range, cx)
20638                })
20639                .ok()
20640                .flatten()?
20641                .await
20642                .context("refreshing debugger inlays")
20643                .log_err()?;
20644
20645            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20646
20647            for (buffer_id, inline_value) in inline_values
20648                .into_iter()
20649                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20650            {
20651                buffer_inline_values
20652                    .entry(buffer_id)
20653                    .or_default()
20654                    .push(inline_value);
20655            }
20656
20657            editor
20658                .update(cx, |editor, cx| {
20659                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20660                    let mut new_inlays = Vec::default();
20661
20662                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20663                        let buffer_id = buffer_snapshot.remote_id();
20664                        buffer_inline_values
20665                            .get(&buffer_id)
20666                            .into_iter()
20667                            .flatten()
20668                            .for_each(|hint| {
20669                                let inlay = Inlay::debugger(
20670                                    post_inc(&mut editor.next_inlay_id),
20671                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20672                                    hint.text(),
20673                                );
20674                                if !inlay.text().chars().contains(&'\n') {
20675                                    new_inlays.push(inlay);
20676                                }
20677                            });
20678                    }
20679
20680                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20681                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20682
20683                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20684                })
20685                .ok()?;
20686            Some(())
20687        });
20688    }
20689
20690    fn on_buffer_event(
20691        &mut self,
20692        multibuffer: &Entity<MultiBuffer>,
20693        event: &multi_buffer::Event,
20694        window: &mut Window,
20695        cx: &mut Context<Self>,
20696    ) {
20697        match event {
20698            multi_buffer::Event::Edited {
20699                singleton_buffer_edited,
20700                edited_buffer,
20701            } => {
20702                self.scrollbar_marker_state.dirty = true;
20703                self.active_indent_guides_state.dirty = true;
20704                self.refresh_active_diagnostics(cx);
20705                self.refresh_code_actions(window, cx);
20706                self.refresh_selected_text_highlights(true, window, cx);
20707                self.refresh_single_line_folds(window, cx);
20708                refresh_matching_bracket_highlights(self, window, cx);
20709                if self.has_active_edit_prediction() {
20710                    self.update_visible_edit_prediction(window, cx);
20711                }
20712                if let Some(project) = self.project.as_ref()
20713                    && let Some(edited_buffer) = edited_buffer
20714                {
20715                    project.update(cx, |project, cx| {
20716                        self.registered_buffers
20717                            .entry(edited_buffer.read(cx).remote_id())
20718                            .or_insert_with(|| {
20719                                project.register_buffer_with_language_servers(edited_buffer, cx)
20720                            });
20721                    });
20722                }
20723                cx.emit(EditorEvent::BufferEdited);
20724                cx.emit(SearchEvent::MatchesInvalidated);
20725
20726                if let Some(buffer) = edited_buffer {
20727                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20728                }
20729
20730                if *singleton_buffer_edited {
20731                    if let Some(buffer) = edited_buffer
20732                        && buffer.read(cx).file().is_none()
20733                    {
20734                        cx.emit(EditorEvent::TitleChanged);
20735                    }
20736                    if let Some(project) = &self.project {
20737                        #[allow(clippy::mutable_key_type)]
20738                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20739                            multibuffer
20740                                .all_buffers()
20741                                .into_iter()
20742                                .filter_map(|buffer| {
20743                                    buffer.update(cx, |buffer, cx| {
20744                                        let language = buffer.language()?;
20745                                        let should_discard = project.update(cx, |project, cx| {
20746                                            project.is_local()
20747                                                && !project.has_language_servers_for(buffer, cx)
20748                                        });
20749                                        should_discard.not().then_some(language.clone())
20750                                    })
20751                                })
20752                                .collect::<HashSet<_>>()
20753                        });
20754                        if !languages_affected.is_empty() {
20755                            self.refresh_inlay_hints(
20756                                InlayHintRefreshReason::BufferEdited(languages_affected),
20757                                cx,
20758                            );
20759                        }
20760                    }
20761                }
20762
20763                let Some(project) = &self.project else { return };
20764                let (telemetry, is_via_ssh) = {
20765                    let project = project.read(cx);
20766                    let telemetry = project.client().telemetry().clone();
20767                    let is_via_ssh = project.is_via_remote_server();
20768                    (telemetry, is_via_ssh)
20769                };
20770                refresh_linked_ranges(self, window, cx);
20771                telemetry.log_edit_event("editor", is_via_ssh);
20772            }
20773            multi_buffer::Event::ExcerptsAdded {
20774                buffer,
20775                predecessor,
20776                excerpts,
20777            } => {
20778                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20779                let buffer_id = buffer.read(cx).remote_id();
20780                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20781                    && let Some(project) = &self.project
20782                {
20783                    update_uncommitted_diff_for_buffer(
20784                        cx.entity(),
20785                        project,
20786                        [buffer.clone()],
20787                        self.buffer.clone(),
20788                        cx,
20789                    )
20790                    .detach();
20791                }
20792                if self.active_diagnostics != ActiveDiagnostic::All {
20793                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20794                }
20795                cx.emit(EditorEvent::ExcerptsAdded {
20796                    buffer: buffer.clone(),
20797                    predecessor: *predecessor,
20798                    excerpts: excerpts.clone(),
20799                });
20800                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20801            }
20802            multi_buffer::Event::ExcerptsRemoved {
20803                ids,
20804                removed_buffer_ids,
20805            } => {
20806                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20807                let buffer = self.buffer.read(cx);
20808                self.registered_buffers
20809                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20810                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20811                cx.emit(EditorEvent::ExcerptsRemoved {
20812                    ids: ids.clone(),
20813                    removed_buffer_ids: removed_buffer_ids.clone(),
20814                });
20815            }
20816            multi_buffer::Event::ExcerptsEdited {
20817                excerpt_ids,
20818                buffer_ids,
20819            } => {
20820                self.display_map.update(cx, |map, cx| {
20821                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20822                });
20823                cx.emit(EditorEvent::ExcerptsEdited {
20824                    ids: excerpt_ids.clone(),
20825                });
20826            }
20827            multi_buffer::Event::ExcerptsExpanded { ids } => {
20828                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20829                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20830            }
20831            multi_buffer::Event::Reparsed(buffer_id) => {
20832                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20833                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20834
20835                cx.emit(EditorEvent::Reparsed(*buffer_id));
20836            }
20837            multi_buffer::Event::DiffHunksToggled => {
20838                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20839            }
20840            multi_buffer::Event::LanguageChanged(buffer_id) => {
20841                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20842                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20843                cx.emit(EditorEvent::Reparsed(*buffer_id));
20844                cx.notify();
20845            }
20846            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20847            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20848            multi_buffer::Event::FileHandleChanged
20849            | multi_buffer::Event::Reloaded
20850            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20851            multi_buffer::Event::DiagnosticsUpdated => {
20852                self.update_diagnostics_state(window, cx);
20853            }
20854            _ => {}
20855        };
20856    }
20857
20858    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20859        if !self.diagnostics_enabled() {
20860            return;
20861        }
20862        self.refresh_active_diagnostics(cx);
20863        self.refresh_inline_diagnostics(true, window, cx);
20864        self.scrollbar_marker_state.dirty = true;
20865        cx.notify();
20866    }
20867
20868    pub fn start_temporary_diff_override(&mut self) {
20869        self.load_diff_task.take();
20870        self.temporary_diff_override = true;
20871    }
20872
20873    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20874        self.temporary_diff_override = false;
20875        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20876        self.buffer.update(cx, |buffer, cx| {
20877            buffer.set_all_diff_hunks_collapsed(cx);
20878        });
20879
20880        if let Some(project) = self.project.clone() {
20881            self.load_diff_task = Some(
20882                update_uncommitted_diff_for_buffer(
20883                    cx.entity(),
20884                    &project,
20885                    self.buffer.read(cx).all_buffers(),
20886                    self.buffer.clone(),
20887                    cx,
20888                )
20889                .shared(),
20890            );
20891        }
20892    }
20893
20894    fn on_display_map_changed(
20895        &mut self,
20896        _: Entity<DisplayMap>,
20897        _: &mut Window,
20898        cx: &mut Context<Self>,
20899    ) {
20900        cx.notify();
20901    }
20902
20903    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20904        if self.diagnostics_enabled() {
20905            let new_severity = EditorSettings::get_global(cx)
20906                .diagnostics_max_severity
20907                .unwrap_or(DiagnosticSeverity::Hint);
20908            self.set_max_diagnostics_severity(new_severity, cx);
20909        }
20910        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20911        self.update_edit_prediction_settings(cx);
20912        self.refresh_edit_prediction(true, false, window, cx);
20913        self.refresh_inline_values(cx);
20914        self.refresh_inlay_hints(
20915            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20916                self.selections.newest_anchor().head(),
20917                &self.buffer.read(cx).snapshot(cx),
20918                cx,
20919            )),
20920            cx,
20921        );
20922
20923        let old_cursor_shape = self.cursor_shape;
20924        let old_show_breadcrumbs = self.show_breadcrumbs;
20925
20926        {
20927            let editor_settings = EditorSettings::get_global(cx);
20928            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20929            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20930            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20931            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20932        }
20933
20934        if old_cursor_shape != self.cursor_shape {
20935            cx.emit(EditorEvent::CursorShapeChanged);
20936        }
20937
20938        if old_show_breadcrumbs != self.show_breadcrumbs {
20939            cx.emit(EditorEvent::BreadcrumbsChanged);
20940        }
20941
20942        let project_settings = ProjectSettings::get_global(cx);
20943        self.serialize_dirty_buffers =
20944            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20945
20946        if self.mode.is_full() {
20947            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20948            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20949            if self.show_inline_diagnostics != show_inline_diagnostics {
20950                self.show_inline_diagnostics = show_inline_diagnostics;
20951                self.refresh_inline_diagnostics(false, window, cx);
20952            }
20953
20954            if self.git_blame_inline_enabled != inline_blame_enabled {
20955                self.toggle_git_blame_inline_internal(false, window, cx);
20956            }
20957
20958            let minimap_settings = EditorSettings::get_global(cx).minimap;
20959            if self.minimap_visibility != MinimapVisibility::Disabled {
20960                if self.minimap_visibility.settings_visibility()
20961                    != minimap_settings.minimap_enabled()
20962                {
20963                    self.set_minimap_visibility(
20964                        MinimapVisibility::for_mode(self.mode(), cx),
20965                        window,
20966                        cx,
20967                    );
20968                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20969                    minimap_entity.update(cx, |minimap_editor, cx| {
20970                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20971                    })
20972                }
20973            }
20974        }
20975
20976        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20977            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20978        }) {
20979            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20980                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20981            }
20982            self.refresh_colors(false, None, window, cx);
20983        }
20984
20985        cx.notify();
20986    }
20987
20988    pub fn set_searchable(&mut self, searchable: bool) {
20989        self.searchable = searchable;
20990    }
20991
20992    pub fn searchable(&self) -> bool {
20993        self.searchable
20994    }
20995
20996    fn open_proposed_changes_editor(
20997        &mut self,
20998        _: &OpenProposedChangesEditor,
20999        window: &mut Window,
21000        cx: &mut Context<Self>,
21001    ) {
21002        let Some(workspace) = self.workspace() else {
21003            cx.propagate();
21004            return;
21005        };
21006
21007        let selections = self.selections.all::<usize>(cx);
21008        let multi_buffer = self.buffer.read(cx);
21009        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21010        let mut new_selections_by_buffer = HashMap::default();
21011        for selection in selections {
21012            for (buffer, range, _) in
21013                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
21014            {
21015                let mut range = range.to_point(buffer);
21016                range.start.column = 0;
21017                range.end.column = buffer.line_len(range.end.row);
21018                new_selections_by_buffer
21019                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
21020                    .or_insert(Vec::new())
21021                    .push(range)
21022            }
21023        }
21024
21025        let proposed_changes_buffers = new_selections_by_buffer
21026            .into_iter()
21027            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
21028            .collect::<Vec<_>>();
21029        let proposed_changes_editor = cx.new(|cx| {
21030            ProposedChangesEditor::new(
21031                "Proposed changes",
21032                proposed_changes_buffers,
21033                self.project.clone(),
21034                window,
21035                cx,
21036            )
21037        });
21038
21039        window.defer(cx, move |window, cx| {
21040            workspace.update(cx, |workspace, cx| {
21041                workspace.active_pane().update(cx, |pane, cx| {
21042                    pane.add_item(
21043                        Box::new(proposed_changes_editor),
21044                        true,
21045                        true,
21046                        None,
21047                        window,
21048                        cx,
21049                    );
21050                });
21051            });
21052        });
21053    }
21054
21055    pub fn open_excerpts_in_split(
21056        &mut self,
21057        _: &OpenExcerptsSplit,
21058        window: &mut Window,
21059        cx: &mut Context<Self>,
21060    ) {
21061        self.open_excerpts_common(None, true, window, cx)
21062    }
21063
21064    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21065        self.open_excerpts_common(None, false, window, cx)
21066    }
21067
21068    fn open_excerpts_common(
21069        &mut self,
21070        jump_data: Option<JumpData>,
21071        split: bool,
21072        window: &mut Window,
21073        cx: &mut Context<Self>,
21074    ) {
21075        let Some(workspace) = self.workspace() else {
21076            cx.propagate();
21077            return;
21078        };
21079
21080        if self.buffer.read(cx).is_singleton() {
21081            cx.propagate();
21082            return;
21083        }
21084
21085        let mut new_selections_by_buffer = HashMap::default();
21086        match &jump_data {
21087            Some(JumpData::MultiBufferPoint {
21088                excerpt_id,
21089                position,
21090                anchor,
21091                line_offset_from_top,
21092            }) => {
21093                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21094                if let Some(buffer) = multi_buffer_snapshot
21095                    .buffer_id_for_excerpt(*excerpt_id)
21096                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21097                {
21098                    let buffer_snapshot = buffer.read(cx).snapshot();
21099                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21100                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21101                    } else {
21102                        buffer_snapshot.clip_point(*position, Bias::Left)
21103                    };
21104                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21105                    new_selections_by_buffer.insert(
21106                        buffer,
21107                        (
21108                            vec![jump_to_offset..jump_to_offset],
21109                            Some(*line_offset_from_top),
21110                        ),
21111                    );
21112                }
21113            }
21114            Some(JumpData::MultiBufferRow {
21115                row,
21116                line_offset_from_top,
21117            }) => {
21118                let point = MultiBufferPoint::new(row.0, 0);
21119                if let Some((buffer, buffer_point, _)) =
21120                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21121                {
21122                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21123                    new_selections_by_buffer
21124                        .entry(buffer)
21125                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21126                        .0
21127                        .push(buffer_offset..buffer_offset)
21128                }
21129            }
21130            None => {
21131                let selections = self.selections.all::<usize>(cx);
21132                let multi_buffer = self.buffer.read(cx);
21133                for selection in selections {
21134                    for (snapshot, range, _, anchor) in multi_buffer
21135                        .snapshot(cx)
21136                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21137                    {
21138                        if let Some(anchor) = anchor {
21139                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21140                            else {
21141                                continue;
21142                            };
21143                            let offset = text::ToOffset::to_offset(
21144                                &anchor.text_anchor,
21145                                &buffer_handle.read(cx).snapshot(),
21146                            );
21147                            let range = offset..offset;
21148                            new_selections_by_buffer
21149                                .entry(buffer_handle)
21150                                .or_insert((Vec::new(), None))
21151                                .0
21152                                .push(range)
21153                        } else {
21154                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21155                            else {
21156                                continue;
21157                            };
21158                            new_selections_by_buffer
21159                                .entry(buffer_handle)
21160                                .or_insert((Vec::new(), None))
21161                                .0
21162                                .push(range)
21163                        }
21164                    }
21165                }
21166            }
21167        }
21168
21169        new_selections_by_buffer
21170            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21171
21172        if new_selections_by_buffer.is_empty() {
21173            return;
21174        }
21175
21176        // We defer the pane interaction because we ourselves are a workspace item
21177        // and activating a new item causes the pane to call a method on us reentrantly,
21178        // which panics if we're on the stack.
21179        window.defer(cx, move |window, cx| {
21180            workspace.update(cx, |workspace, cx| {
21181                let pane = if split {
21182                    workspace.adjacent_pane(window, cx)
21183                } else {
21184                    workspace.active_pane().clone()
21185                };
21186
21187                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21188                    let editor = buffer
21189                        .read(cx)
21190                        .file()
21191                        .is_none()
21192                        .then(|| {
21193                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21194                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21195                            // Instead, we try to activate the existing editor in the pane first.
21196                            let (editor, pane_item_index) =
21197                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21198                                    let editor = item.downcast::<Editor>()?;
21199                                    let singleton_buffer =
21200                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21201                                    if singleton_buffer == buffer {
21202                                        Some((editor, i))
21203                                    } else {
21204                                        None
21205                                    }
21206                                })?;
21207                            pane.update(cx, |pane, cx| {
21208                                pane.activate_item(pane_item_index, true, true, window, cx)
21209                            });
21210                            Some(editor)
21211                        })
21212                        .flatten()
21213                        .unwrap_or_else(|| {
21214                            workspace.open_project_item::<Self>(
21215                                pane.clone(),
21216                                buffer,
21217                                true,
21218                                true,
21219                                window,
21220                                cx,
21221                            )
21222                        });
21223
21224                    editor.update(cx, |editor, cx| {
21225                        let autoscroll = match scroll_offset {
21226                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21227                            None => Autoscroll::newest(),
21228                        };
21229                        let nav_history = editor.nav_history.take();
21230                        editor.change_selections(
21231                            SelectionEffects::scroll(autoscroll),
21232                            window,
21233                            cx,
21234                            |s| {
21235                                s.select_ranges(ranges);
21236                            },
21237                        );
21238                        editor.nav_history = nav_history;
21239                    });
21240                }
21241            })
21242        });
21243    }
21244
21245    // For now, don't allow opening excerpts in buffers that aren't backed by
21246    // regular project files.
21247    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21248        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21249    }
21250
21251    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21252        let snapshot = self.buffer.read(cx).read(cx);
21253        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21254        Some(
21255            ranges
21256                .iter()
21257                .map(move |range| {
21258                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21259                })
21260                .collect(),
21261        )
21262    }
21263
21264    fn selection_replacement_ranges(
21265        &self,
21266        range: Range<OffsetUtf16>,
21267        cx: &mut App,
21268    ) -> Vec<Range<OffsetUtf16>> {
21269        let selections = self.selections.all::<OffsetUtf16>(cx);
21270        let newest_selection = selections
21271            .iter()
21272            .max_by_key(|selection| selection.id)
21273            .unwrap();
21274        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21275        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21276        let snapshot = self.buffer.read(cx).read(cx);
21277        selections
21278            .into_iter()
21279            .map(|mut selection| {
21280                selection.start.0 =
21281                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21282                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21283                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21284                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21285            })
21286            .collect()
21287    }
21288
21289    fn report_editor_event(
21290        &self,
21291        reported_event: ReportEditorEvent,
21292        file_extension: Option<String>,
21293        cx: &App,
21294    ) {
21295        if cfg!(any(test, feature = "test-support")) {
21296            return;
21297        }
21298
21299        let Some(project) = &self.project else { return };
21300
21301        // If None, we are in a file without an extension
21302        let file = self
21303            .buffer
21304            .read(cx)
21305            .as_singleton()
21306            .and_then(|b| b.read(cx).file());
21307        let file_extension = file_extension.or(file
21308            .as_ref()
21309            .and_then(|file| Path::new(file.file_name(cx)).extension())
21310            .and_then(|e| e.to_str())
21311            .map(|a| a.to_string()));
21312
21313        let vim_mode = vim_enabled(cx);
21314
21315        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21316        let copilot_enabled = edit_predictions_provider
21317            == language::language_settings::EditPredictionProvider::Copilot;
21318        let copilot_enabled_for_language = self
21319            .buffer
21320            .read(cx)
21321            .language_settings(cx)
21322            .show_edit_predictions;
21323
21324        let project = project.read(cx);
21325        let event_type = reported_event.event_type();
21326
21327        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21328            telemetry::event!(
21329                event_type,
21330                type = if auto_saved {"autosave"} else {"manual"},
21331                file_extension,
21332                vim_mode,
21333                copilot_enabled,
21334                copilot_enabled_for_language,
21335                edit_predictions_provider,
21336                is_via_ssh = project.is_via_remote_server(),
21337            );
21338        } else {
21339            telemetry::event!(
21340                event_type,
21341                file_extension,
21342                vim_mode,
21343                copilot_enabled,
21344                copilot_enabled_for_language,
21345                edit_predictions_provider,
21346                is_via_ssh = project.is_via_remote_server(),
21347            );
21348        };
21349    }
21350
21351    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21352    /// with each line being an array of {text, highlight} objects.
21353    fn copy_highlight_json(
21354        &mut self,
21355        _: &CopyHighlightJson,
21356        window: &mut Window,
21357        cx: &mut Context<Self>,
21358    ) {
21359        #[derive(Serialize)]
21360        struct Chunk<'a> {
21361            text: String,
21362            highlight: Option<&'a str>,
21363        }
21364
21365        let snapshot = self.buffer.read(cx).snapshot(cx);
21366        let range = self
21367            .selected_text_range(false, window, cx)
21368            .and_then(|selection| {
21369                if selection.range.is_empty() {
21370                    None
21371                } else {
21372                    Some(selection.range)
21373                }
21374            })
21375            .unwrap_or_else(|| 0..snapshot.len());
21376
21377        let chunks = snapshot.chunks(range, true);
21378        let mut lines = Vec::new();
21379        let mut line: VecDeque<Chunk> = VecDeque::new();
21380
21381        let Some(style) = self.style.as_ref() else {
21382            return;
21383        };
21384
21385        for chunk in chunks {
21386            let highlight = chunk
21387                .syntax_highlight_id
21388                .and_then(|id| id.name(&style.syntax));
21389            let mut chunk_lines = chunk.text.split('\n').peekable();
21390            while let Some(text) = chunk_lines.next() {
21391                let mut merged_with_last_token = false;
21392                if let Some(last_token) = line.back_mut()
21393                    && last_token.highlight == highlight
21394                {
21395                    last_token.text.push_str(text);
21396                    merged_with_last_token = true;
21397                }
21398
21399                if !merged_with_last_token {
21400                    line.push_back(Chunk {
21401                        text: text.into(),
21402                        highlight,
21403                    });
21404                }
21405
21406                if chunk_lines.peek().is_some() {
21407                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21408                        line.pop_front();
21409                    }
21410                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21411                        line.pop_back();
21412                    }
21413
21414                    lines.push(mem::take(&mut line));
21415                }
21416            }
21417        }
21418
21419        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21420            return;
21421        };
21422        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21423    }
21424
21425    pub fn open_context_menu(
21426        &mut self,
21427        _: &OpenContextMenu,
21428        window: &mut Window,
21429        cx: &mut Context<Self>,
21430    ) {
21431        self.request_autoscroll(Autoscroll::newest(), cx);
21432        let position = self.selections.newest_display(cx).start;
21433        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21434    }
21435
21436    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21437        &self.inlay_hint_cache
21438    }
21439
21440    pub fn replay_insert_event(
21441        &mut self,
21442        text: &str,
21443        relative_utf16_range: Option<Range<isize>>,
21444        window: &mut Window,
21445        cx: &mut Context<Self>,
21446    ) {
21447        if !self.input_enabled {
21448            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21449            return;
21450        }
21451        if let Some(relative_utf16_range) = relative_utf16_range {
21452            let selections = self.selections.all::<OffsetUtf16>(cx);
21453            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21454                let new_ranges = selections.into_iter().map(|range| {
21455                    let start = OffsetUtf16(
21456                        range
21457                            .head()
21458                            .0
21459                            .saturating_add_signed(relative_utf16_range.start),
21460                    );
21461                    let end = OffsetUtf16(
21462                        range
21463                            .head()
21464                            .0
21465                            .saturating_add_signed(relative_utf16_range.end),
21466                    );
21467                    start..end
21468                });
21469                s.select_ranges(new_ranges);
21470            });
21471        }
21472
21473        self.handle_input(text, window, cx);
21474    }
21475
21476    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21477        let Some(provider) = self.semantics_provider.as_ref() else {
21478            return false;
21479        };
21480
21481        let mut supports = false;
21482        self.buffer().update(cx, |this, cx| {
21483            this.for_each_buffer(|buffer| {
21484                supports |= provider.supports_inlay_hints(buffer, cx);
21485            });
21486        });
21487
21488        supports
21489    }
21490
21491    pub fn is_focused(&self, window: &Window) -> bool {
21492        self.focus_handle.is_focused(window)
21493    }
21494
21495    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21496        cx.emit(EditorEvent::Focused);
21497
21498        if let Some(descendant) = self
21499            .last_focused_descendant
21500            .take()
21501            .and_then(|descendant| descendant.upgrade())
21502        {
21503            window.focus(&descendant);
21504        } else {
21505            if let Some(blame) = self.blame.as_ref() {
21506                blame.update(cx, GitBlame::focus)
21507            }
21508
21509            self.blink_manager.update(cx, BlinkManager::enable);
21510            self.show_cursor_names(window, cx);
21511            self.buffer.update(cx, |buffer, cx| {
21512                buffer.finalize_last_transaction(cx);
21513                if self.leader_id.is_none() {
21514                    buffer.set_active_selections(
21515                        &self.selections.disjoint_anchors_arc(),
21516                        self.selections.line_mode(),
21517                        self.cursor_shape,
21518                        cx,
21519                    );
21520                }
21521            });
21522        }
21523    }
21524
21525    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21526        cx.emit(EditorEvent::FocusedIn)
21527    }
21528
21529    fn handle_focus_out(
21530        &mut self,
21531        event: FocusOutEvent,
21532        _window: &mut Window,
21533        cx: &mut Context<Self>,
21534    ) {
21535        if event.blurred != self.focus_handle {
21536            self.last_focused_descendant = Some(event.blurred);
21537        }
21538        self.selection_drag_state = SelectionDragState::None;
21539        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21540    }
21541
21542    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21543        self.blink_manager.update(cx, BlinkManager::disable);
21544        self.buffer
21545            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21546
21547        if let Some(blame) = self.blame.as_ref() {
21548            blame.update(cx, GitBlame::blur)
21549        }
21550        if !self.hover_state.focused(window, cx) {
21551            hide_hover(self, cx);
21552        }
21553        if !self
21554            .context_menu
21555            .borrow()
21556            .as_ref()
21557            .is_some_and(|context_menu| context_menu.focused(window, cx))
21558        {
21559            self.hide_context_menu(window, cx);
21560        }
21561        self.take_active_edit_prediction(cx);
21562        cx.emit(EditorEvent::Blurred);
21563        cx.notify();
21564    }
21565
21566    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21567        let mut pending: String = window
21568            .pending_input_keystrokes()
21569            .into_iter()
21570            .flatten()
21571            .filter_map(|keystroke| {
21572                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21573                    keystroke.key_char.clone()
21574                } else {
21575                    None
21576                }
21577            })
21578            .collect();
21579
21580        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21581            pending = "".to_string();
21582        }
21583
21584        let existing_pending = self
21585            .text_highlights::<PendingInput>(cx)
21586            .map(|(_, ranges)| ranges.to_vec());
21587        if existing_pending.is_none() && pending.is_empty() {
21588            return;
21589        }
21590        let transaction =
21591            self.transact(window, cx, |this, window, cx| {
21592                let selections = this.selections.all::<usize>(cx);
21593                let edits = selections
21594                    .iter()
21595                    .map(|selection| (selection.end..selection.end, pending.clone()));
21596                this.edit(edits, cx);
21597                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21598                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21599                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21600                    }));
21601                });
21602                if let Some(existing_ranges) = existing_pending {
21603                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21604                    this.edit(edits, cx);
21605                }
21606            });
21607
21608        let snapshot = self.snapshot(window, cx);
21609        let ranges = self
21610            .selections
21611            .all::<usize>(cx)
21612            .into_iter()
21613            .map(|selection| {
21614                snapshot.buffer_snapshot().anchor_after(selection.end)
21615                    ..snapshot
21616                        .buffer_snapshot()
21617                        .anchor_before(selection.end + pending.len())
21618            })
21619            .collect();
21620
21621        if pending.is_empty() {
21622            self.clear_highlights::<PendingInput>(cx);
21623        } else {
21624            self.highlight_text::<PendingInput>(
21625                ranges,
21626                HighlightStyle {
21627                    underline: Some(UnderlineStyle {
21628                        thickness: px(1.),
21629                        color: None,
21630                        wavy: false,
21631                    }),
21632                    ..Default::default()
21633                },
21634                cx,
21635            );
21636        }
21637
21638        self.ime_transaction = self.ime_transaction.or(transaction);
21639        if let Some(transaction) = self.ime_transaction {
21640            self.buffer.update(cx, |buffer, cx| {
21641                buffer.group_until_transaction(transaction, cx);
21642            });
21643        }
21644
21645        if self.text_highlights::<PendingInput>(cx).is_none() {
21646            self.ime_transaction.take();
21647        }
21648    }
21649
21650    pub fn register_action_renderer(
21651        &mut self,
21652        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21653    ) -> Subscription {
21654        let id = self.next_editor_action_id.post_inc();
21655        self.editor_actions
21656            .borrow_mut()
21657            .insert(id, Box::new(listener));
21658
21659        let editor_actions = self.editor_actions.clone();
21660        Subscription::new(move || {
21661            editor_actions.borrow_mut().remove(&id);
21662        })
21663    }
21664
21665    pub fn register_action<A: Action>(
21666        &mut self,
21667        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21668    ) -> Subscription {
21669        let id = self.next_editor_action_id.post_inc();
21670        let listener = Arc::new(listener);
21671        self.editor_actions.borrow_mut().insert(
21672            id,
21673            Box::new(move |_, window, _| {
21674                let listener = listener.clone();
21675                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21676                    let action = action.downcast_ref().unwrap();
21677                    if phase == DispatchPhase::Bubble {
21678                        listener(action, window, cx)
21679                    }
21680                })
21681            }),
21682        );
21683
21684        let editor_actions = self.editor_actions.clone();
21685        Subscription::new(move || {
21686            editor_actions.borrow_mut().remove(&id);
21687        })
21688    }
21689
21690    pub fn file_header_size(&self) -> u32 {
21691        FILE_HEADER_HEIGHT
21692    }
21693
21694    pub fn restore(
21695        &mut self,
21696        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21697        window: &mut Window,
21698        cx: &mut Context<Self>,
21699    ) {
21700        let workspace = self.workspace();
21701        let project = self.project();
21702        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21703            let mut tasks = Vec::new();
21704            for (buffer_id, changes) in revert_changes {
21705                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21706                    buffer.update(cx, |buffer, cx| {
21707                        buffer.edit(
21708                            changes
21709                                .into_iter()
21710                                .map(|(range, text)| (range, text.to_string())),
21711                            None,
21712                            cx,
21713                        );
21714                    });
21715
21716                    if let Some(project) =
21717                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21718                    {
21719                        project.update(cx, |project, cx| {
21720                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21721                        })
21722                    }
21723                }
21724            }
21725            tasks
21726        });
21727        cx.spawn_in(window, async move |_, cx| {
21728            for (buffer, task) in save_tasks {
21729                let result = task.await;
21730                if result.is_err() {
21731                    let Some(path) = buffer
21732                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21733                        .ok()
21734                    else {
21735                        continue;
21736                    };
21737                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21738                        let Some(task) = cx
21739                            .update_window_entity(workspace, |workspace, window, cx| {
21740                                workspace
21741                                    .open_path_preview(path, None, false, false, false, window, cx)
21742                            })
21743                            .ok()
21744                        else {
21745                            continue;
21746                        };
21747                        task.await.log_err();
21748                    }
21749                }
21750            }
21751        })
21752        .detach();
21753        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21754            selections.refresh()
21755        });
21756    }
21757
21758    pub fn to_pixel_point(
21759        &self,
21760        source: multi_buffer::Anchor,
21761        editor_snapshot: &EditorSnapshot,
21762        window: &mut Window,
21763    ) -> Option<gpui::Point<Pixels>> {
21764        let source_point = source.to_display_point(editor_snapshot);
21765        self.display_to_pixel_point(source_point, editor_snapshot, window)
21766    }
21767
21768    pub fn display_to_pixel_point(
21769        &self,
21770        source: DisplayPoint,
21771        editor_snapshot: &EditorSnapshot,
21772        window: &mut Window,
21773    ) -> Option<gpui::Point<Pixels>> {
21774        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21775        let text_layout_details = self.text_layout_details(window);
21776        let scroll_top = text_layout_details
21777            .scroll_anchor
21778            .scroll_position(editor_snapshot)
21779            .y;
21780
21781        if source.row().as_f64() < scroll_top.floor() {
21782            return None;
21783        }
21784        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21785        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21786        Some(gpui::Point::new(source_x, source_y))
21787    }
21788
21789    pub fn has_visible_completions_menu(&self) -> bool {
21790        !self.edit_prediction_preview_is_active()
21791            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21792                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21793            })
21794    }
21795
21796    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21797        if self.mode.is_minimap() {
21798            return;
21799        }
21800        self.addons
21801            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21802    }
21803
21804    pub fn unregister_addon<T: Addon>(&mut self) {
21805        self.addons.remove(&std::any::TypeId::of::<T>());
21806    }
21807
21808    pub fn addon<T: Addon>(&self) -> Option<&T> {
21809        let type_id = std::any::TypeId::of::<T>();
21810        self.addons
21811            .get(&type_id)
21812            .and_then(|item| item.to_any().downcast_ref::<T>())
21813    }
21814
21815    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21816        let type_id = std::any::TypeId::of::<T>();
21817        self.addons
21818            .get_mut(&type_id)
21819            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21820    }
21821
21822    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21823        let text_layout_details = self.text_layout_details(window);
21824        let style = &text_layout_details.editor_style;
21825        let font_id = window.text_system().resolve_font(&style.text.font());
21826        let font_size = style.text.font_size.to_pixels(window.rem_size());
21827        let line_height = style.text.line_height_in_pixels(window.rem_size());
21828        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21829        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21830
21831        CharacterDimensions {
21832            em_width,
21833            em_advance,
21834            line_height,
21835        }
21836    }
21837
21838    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21839        self.load_diff_task.clone()
21840    }
21841
21842    fn read_metadata_from_db(
21843        &mut self,
21844        item_id: u64,
21845        workspace_id: WorkspaceId,
21846        window: &mut Window,
21847        cx: &mut Context<Editor>,
21848    ) {
21849        if self.buffer_kind(cx) == ItemBufferKind::Singleton
21850            && !self.mode.is_minimap()
21851            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21852        {
21853            let buffer_snapshot = OnceCell::new();
21854
21855            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21856                && !folds.is_empty()
21857            {
21858                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21859                self.fold_ranges(
21860                    folds
21861                        .into_iter()
21862                        .map(|(start, end)| {
21863                            snapshot.clip_offset(start, Bias::Left)
21864                                ..snapshot.clip_offset(end, Bias::Right)
21865                        })
21866                        .collect(),
21867                    false,
21868                    window,
21869                    cx,
21870                );
21871            }
21872
21873            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21874                && !selections.is_empty()
21875            {
21876                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21877                // skip adding the initial selection to selection history
21878                self.selection_history.mode = SelectionHistoryMode::Skipping;
21879                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21880                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21881                        snapshot.clip_offset(start, Bias::Left)
21882                            ..snapshot.clip_offset(end, Bias::Right)
21883                    }));
21884                });
21885                self.selection_history.mode = SelectionHistoryMode::Normal;
21886            };
21887        }
21888
21889        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21890    }
21891
21892    fn update_lsp_data(
21893        &mut self,
21894        ignore_cache: bool,
21895        for_buffer: Option<BufferId>,
21896        window: &mut Window,
21897        cx: &mut Context<'_, Self>,
21898    ) {
21899        self.pull_diagnostics(for_buffer, window, cx);
21900        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21901    }
21902}
21903
21904fn edit_for_markdown_paste<'a>(
21905    buffer: &MultiBufferSnapshot,
21906    range: Range<usize>,
21907    to_insert: &'a str,
21908    url: Option<url::Url>,
21909) -> (Range<usize>, Cow<'a, str>) {
21910    if url.is_none() {
21911        return (range, Cow::Borrowed(to_insert));
21912    };
21913
21914    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
21915
21916    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
21917        Cow::Borrowed(to_insert)
21918    } else {
21919        Cow::Owned(format!("[{old_text}]({to_insert})"))
21920    };
21921    (range, new_text)
21922}
21923
21924fn vim_enabled(cx: &App) -> bool {
21925    vim_mode_setting::VimModeSetting::try_get(cx)
21926        .map(|vim_mode| vim_mode.0)
21927        .unwrap_or(false)
21928}
21929
21930fn process_completion_for_edit(
21931    completion: &Completion,
21932    intent: CompletionIntent,
21933    buffer: &Entity<Buffer>,
21934    cursor_position: &text::Anchor,
21935    cx: &mut Context<Editor>,
21936) -> CompletionEdit {
21937    let buffer = buffer.read(cx);
21938    let buffer_snapshot = buffer.snapshot();
21939    let (snippet, new_text) = if completion.is_snippet() {
21940        let mut snippet_source = completion.new_text.clone();
21941        // Workaround for typescript language server issues so that methods don't expand within
21942        // strings and functions with type expressions. The previous point is used because the query
21943        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21944        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
21945        let previous_point = if previous_point.column > 0 {
21946            cursor_position.to_previous_offset(&buffer_snapshot)
21947        } else {
21948            cursor_position.to_offset(&buffer_snapshot)
21949        };
21950        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21951            && scope.prefers_label_for_snippet_in_completion()
21952            && let Some(label) = completion.label()
21953            && matches!(
21954                completion.kind(),
21955                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21956            )
21957        {
21958            snippet_source = label;
21959        }
21960        match Snippet::parse(&snippet_source).log_err() {
21961            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21962            None => (None, completion.new_text.clone()),
21963        }
21964    } else {
21965        (None, completion.new_text.clone())
21966    };
21967
21968    let mut range_to_replace = {
21969        let replace_range = &completion.replace_range;
21970        if let CompletionSource::Lsp {
21971            insert_range: Some(insert_range),
21972            ..
21973        } = &completion.source
21974        {
21975            debug_assert_eq!(
21976                insert_range.start, replace_range.start,
21977                "insert_range and replace_range should start at the same position"
21978            );
21979            debug_assert!(
21980                insert_range
21981                    .start
21982                    .cmp(cursor_position, &buffer_snapshot)
21983                    .is_le(),
21984                "insert_range should start before or at cursor position"
21985            );
21986            debug_assert!(
21987                replace_range
21988                    .start
21989                    .cmp(cursor_position, &buffer_snapshot)
21990                    .is_le(),
21991                "replace_range should start before or at cursor position"
21992            );
21993
21994            let should_replace = match intent {
21995                CompletionIntent::CompleteWithInsert => false,
21996                CompletionIntent::CompleteWithReplace => true,
21997                CompletionIntent::Complete | CompletionIntent::Compose => {
21998                    let insert_mode =
21999                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22000                            .completions
22001                            .lsp_insert_mode;
22002                    match insert_mode {
22003                        LspInsertMode::Insert => false,
22004                        LspInsertMode::Replace => true,
22005                        LspInsertMode::ReplaceSubsequence => {
22006                            let mut text_to_replace = buffer.chars_for_range(
22007                                buffer.anchor_before(replace_range.start)
22008                                    ..buffer.anchor_after(replace_range.end),
22009                            );
22010                            let mut current_needle = text_to_replace.next();
22011                            for haystack_ch in completion.label.text.chars() {
22012                                if let Some(needle_ch) = current_needle
22013                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22014                                {
22015                                    current_needle = text_to_replace.next();
22016                                }
22017                            }
22018                            current_needle.is_none()
22019                        }
22020                        LspInsertMode::ReplaceSuffix => {
22021                            if replace_range
22022                                .end
22023                                .cmp(cursor_position, &buffer_snapshot)
22024                                .is_gt()
22025                            {
22026                                let range_after_cursor = *cursor_position..replace_range.end;
22027                                let text_after_cursor = buffer
22028                                    .text_for_range(
22029                                        buffer.anchor_before(range_after_cursor.start)
22030                                            ..buffer.anchor_after(range_after_cursor.end),
22031                                    )
22032                                    .collect::<String>()
22033                                    .to_ascii_lowercase();
22034                                completion
22035                                    .label
22036                                    .text
22037                                    .to_ascii_lowercase()
22038                                    .ends_with(&text_after_cursor)
22039                            } else {
22040                                true
22041                            }
22042                        }
22043                    }
22044                }
22045            };
22046
22047            if should_replace {
22048                replace_range.clone()
22049            } else {
22050                insert_range.clone()
22051            }
22052        } else {
22053            replace_range.clone()
22054        }
22055    };
22056
22057    if range_to_replace
22058        .end
22059        .cmp(cursor_position, &buffer_snapshot)
22060        .is_lt()
22061    {
22062        range_to_replace.end = *cursor_position;
22063    }
22064
22065    CompletionEdit {
22066        new_text,
22067        replace_range: range_to_replace.to_offset(buffer),
22068        snippet,
22069    }
22070}
22071
22072struct CompletionEdit {
22073    new_text: String,
22074    replace_range: Range<usize>,
22075    snippet: Option<Snippet>,
22076}
22077
22078fn insert_extra_newline_brackets(
22079    buffer: &MultiBufferSnapshot,
22080    range: Range<usize>,
22081    language: &language::LanguageScope,
22082) -> bool {
22083    let leading_whitespace_len = buffer
22084        .reversed_chars_at(range.start)
22085        .take_while(|c| c.is_whitespace() && *c != '\n')
22086        .map(|c| c.len_utf8())
22087        .sum::<usize>();
22088    let trailing_whitespace_len = buffer
22089        .chars_at(range.end)
22090        .take_while(|c| c.is_whitespace() && *c != '\n')
22091        .map(|c| c.len_utf8())
22092        .sum::<usize>();
22093    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22094
22095    language.brackets().any(|(pair, enabled)| {
22096        let pair_start = pair.start.trim_end();
22097        let pair_end = pair.end.trim_start();
22098
22099        enabled
22100            && pair.newline
22101            && buffer.contains_str_at(range.end, pair_end)
22102            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22103    })
22104}
22105
22106fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22107    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22108        [(buffer, range, _)] => (*buffer, range.clone()),
22109        _ => return false,
22110    };
22111    let pair = {
22112        let mut result: Option<BracketMatch> = None;
22113
22114        for pair in buffer
22115            .all_bracket_ranges(range.clone())
22116            .filter(move |pair| {
22117                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22118            })
22119        {
22120            let len = pair.close_range.end - pair.open_range.start;
22121
22122            if let Some(existing) = &result {
22123                let existing_len = existing.close_range.end - existing.open_range.start;
22124                if len > existing_len {
22125                    continue;
22126                }
22127            }
22128
22129            result = Some(pair);
22130        }
22131
22132        result
22133    };
22134    let Some(pair) = pair else {
22135        return false;
22136    };
22137    pair.newline_only
22138        && buffer
22139            .chars_for_range(pair.open_range.end..range.start)
22140            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22141            .all(|c| c.is_whitespace() && c != '\n')
22142}
22143
22144fn update_uncommitted_diff_for_buffer(
22145    editor: Entity<Editor>,
22146    project: &Entity<Project>,
22147    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22148    buffer: Entity<MultiBuffer>,
22149    cx: &mut App,
22150) -> Task<()> {
22151    let mut tasks = Vec::new();
22152    project.update(cx, |project, cx| {
22153        for buffer in buffers {
22154            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22155                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22156            }
22157        }
22158    });
22159    cx.spawn(async move |cx| {
22160        let diffs = future::join_all(tasks).await;
22161        if editor
22162            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22163            .unwrap_or(false)
22164        {
22165            return;
22166        }
22167
22168        buffer
22169            .update(cx, |buffer, cx| {
22170                for diff in diffs.into_iter().flatten() {
22171                    buffer.add_diff(diff, cx);
22172                }
22173            })
22174            .ok();
22175    })
22176}
22177
22178fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22179    let tab_size = tab_size.get() as usize;
22180    let mut width = offset;
22181
22182    for ch in text.chars() {
22183        width += if ch == '\t' {
22184            tab_size - (width % tab_size)
22185        } else {
22186            1
22187        };
22188    }
22189
22190    width - offset
22191}
22192
22193#[cfg(test)]
22194mod tests {
22195    use super::*;
22196
22197    #[test]
22198    fn test_string_size_with_expanded_tabs() {
22199        let nz = |val| NonZeroU32::new(val).unwrap();
22200        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22201        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22202        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22203        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22204        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22205        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22206        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22207        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22208    }
22209}
22210
22211/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22212struct WordBreakingTokenizer<'a> {
22213    input: &'a str,
22214}
22215
22216impl<'a> WordBreakingTokenizer<'a> {
22217    fn new(input: &'a str) -> Self {
22218        Self { input }
22219    }
22220}
22221
22222fn is_char_ideographic(ch: char) -> bool {
22223    use unicode_script::Script::*;
22224    use unicode_script::UnicodeScript;
22225    matches!(ch.script(), Han | Tangut | Yi)
22226}
22227
22228fn is_grapheme_ideographic(text: &str) -> bool {
22229    text.chars().any(is_char_ideographic)
22230}
22231
22232fn is_grapheme_whitespace(text: &str) -> bool {
22233    text.chars().any(|x| x.is_whitespace())
22234}
22235
22236fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22237    text.chars()
22238        .next()
22239        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22240}
22241
22242#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22243enum WordBreakToken<'a> {
22244    Word { token: &'a str, grapheme_len: usize },
22245    InlineWhitespace { token: &'a str, grapheme_len: usize },
22246    Newline,
22247}
22248
22249impl<'a> Iterator for WordBreakingTokenizer<'a> {
22250    /// Yields a span, the count of graphemes in the token, and whether it was
22251    /// whitespace. Note that it also breaks at word boundaries.
22252    type Item = WordBreakToken<'a>;
22253
22254    fn next(&mut self) -> Option<Self::Item> {
22255        use unicode_segmentation::UnicodeSegmentation;
22256        if self.input.is_empty() {
22257            return None;
22258        }
22259
22260        let mut iter = self.input.graphemes(true).peekable();
22261        let mut offset = 0;
22262        let mut grapheme_len = 0;
22263        if let Some(first_grapheme) = iter.next() {
22264            let is_newline = first_grapheme == "\n";
22265            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22266            offset += first_grapheme.len();
22267            grapheme_len += 1;
22268            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22269                if let Some(grapheme) = iter.peek().copied()
22270                    && should_stay_with_preceding_ideograph(grapheme)
22271                {
22272                    offset += grapheme.len();
22273                    grapheme_len += 1;
22274                }
22275            } else {
22276                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22277                let mut next_word_bound = words.peek().copied();
22278                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22279                    next_word_bound = words.next();
22280                }
22281                while let Some(grapheme) = iter.peek().copied() {
22282                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22283                        break;
22284                    };
22285                    if is_grapheme_whitespace(grapheme) != is_whitespace
22286                        || (grapheme == "\n") != is_newline
22287                    {
22288                        break;
22289                    };
22290                    offset += grapheme.len();
22291                    grapheme_len += 1;
22292                    iter.next();
22293                }
22294            }
22295            let token = &self.input[..offset];
22296            self.input = &self.input[offset..];
22297            if token == "\n" {
22298                Some(WordBreakToken::Newline)
22299            } else if is_whitespace {
22300                Some(WordBreakToken::InlineWhitespace {
22301                    token,
22302                    grapheme_len,
22303                })
22304            } else {
22305                Some(WordBreakToken::Word {
22306                    token,
22307                    grapheme_len,
22308                })
22309            }
22310        } else {
22311            None
22312        }
22313    }
22314}
22315
22316#[test]
22317fn test_word_breaking_tokenizer() {
22318    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22319        ("", &[]),
22320        ("  ", &[whitespace("  ", 2)]),
22321        ("Ʒ", &[word("Ʒ", 1)]),
22322        ("Ǽ", &[word("Ǽ", 1)]),
22323        ("", &[word("", 1)]),
22324        ("⋑⋑", &[word("⋑⋑", 2)]),
22325        (
22326            "原理,进而",
22327            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22328        ),
22329        (
22330            "hello world",
22331            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22332        ),
22333        (
22334            "hello, world",
22335            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22336        ),
22337        (
22338            "  hello world",
22339            &[
22340                whitespace("  ", 2),
22341                word("hello", 5),
22342                whitespace(" ", 1),
22343                word("world", 5),
22344            ],
22345        ),
22346        (
22347            "这是什么 \n 钢笔",
22348            &[
22349                word("", 1),
22350                word("", 1),
22351                word("", 1),
22352                word("", 1),
22353                whitespace(" ", 1),
22354                newline(),
22355                whitespace(" ", 1),
22356                word("", 1),
22357                word("", 1),
22358            ],
22359        ),
22360        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22361    ];
22362
22363    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22364        WordBreakToken::Word {
22365            token,
22366            grapheme_len,
22367        }
22368    }
22369
22370    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22371        WordBreakToken::InlineWhitespace {
22372            token,
22373            grapheme_len,
22374        }
22375    }
22376
22377    fn newline() -> WordBreakToken<'static> {
22378        WordBreakToken::Newline
22379    }
22380
22381    for (input, result) in tests {
22382        assert_eq!(
22383            WordBreakingTokenizer::new(input)
22384                .collect::<Vec<_>>()
22385                .as_slice(),
22386            *result,
22387        );
22388    }
22389}
22390
22391fn wrap_with_prefix(
22392    first_line_prefix: String,
22393    subsequent_lines_prefix: String,
22394    unwrapped_text: String,
22395    wrap_column: usize,
22396    tab_size: NonZeroU32,
22397    preserve_existing_whitespace: bool,
22398) -> String {
22399    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22400    let subsequent_lines_prefix_len =
22401        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22402    let mut wrapped_text = String::new();
22403    let mut current_line = first_line_prefix;
22404    let mut is_first_line = true;
22405
22406    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22407    let mut current_line_len = first_line_prefix_len;
22408    let mut in_whitespace = false;
22409    for token in tokenizer {
22410        let have_preceding_whitespace = in_whitespace;
22411        match token {
22412            WordBreakToken::Word {
22413                token,
22414                grapheme_len,
22415            } => {
22416                in_whitespace = false;
22417                let current_prefix_len = if is_first_line {
22418                    first_line_prefix_len
22419                } else {
22420                    subsequent_lines_prefix_len
22421                };
22422                if current_line_len + grapheme_len > wrap_column
22423                    && current_line_len != current_prefix_len
22424                {
22425                    wrapped_text.push_str(current_line.trim_end());
22426                    wrapped_text.push('\n');
22427                    is_first_line = false;
22428                    current_line = subsequent_lines_prefix.clone();
22429                    current_line_len = subsequent_lines_prefix_len;
22430                }
22431                current_line.push_str(token);
22432                current_line_len += grapheme_len;
22433            }
22434            WordBreakToken::InlineWhitespace {
22435                mut token,
22436                mut grapheme_len,
22437            } => {
22438                in_whitespace = true;
22439                if have_preceding_whitespace && !preserve_existing_whitespace {
22440                    continue;
22441                }
22442                if !preserve_existing_whitespace {
22443                    // Keep a single whitespace grapheme as-is
22444                    if let Some(first) =
22445                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22446                    {
22447                        token = first;
22448                    } else {
22449                        token = " ";
22450                    }
22451                    grapheme_len = 1;
22452                }
22453                let current_prefix_len = if is_first_line {
22454                    first_line_prefix_len
22455                } else {
22456                    subsequent_lines_prefix_len
22457                };
22458                if current_line_len + grapheme_len > wrap_column {
22459                    wrapped_text.push_str(current_line.trim_end());
22460                    wrapped_text.push('\n');
22461                    is_first_line = false;
22462                    current_line = subsequent_lines_prefix.clone();
22463                    current_line_len = subsequent_lines_prefix_len;
22464                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22465                    current_line.push_str(token);
22466                    current_line_len += grapheme_len;
22467                }
22468            }
22469            WordBreakToken::Newline => {
22470                in_whitespace = true;
22471                let current_prefix_len = if is_first_line {
22472                    first_line_prefix_len
22473                } else {
22474                    subsequent_lines_prefix_len
22475                };
22476                if preserve_existing_whitespace {
22477                    wrapped_text.push_str(current_line.trim_end());
22478                    wrapped_text.push('\n');
22479                    is_first_line = false;
22480                    current_line = subsequent_lines_prefix.clone();
22481                    current_line_len = subsequent_lines_prefix_len;
22482                } else if have_preceding_whitespace {
22483                    continue;
22484                } else if current_line_len + 1 > wrap_column
22485                    && current_line_len != current_prefix_len
22486                {
22487                    wrapped_text.push_str(current_line.trim_end());
22488                    wrapped_text.push('\n');
22489                    is_first_line = false;
22490                    current_line = subsequent_lines_prefix.clone();
22491                    current_line_len = subsequent_lines_prefix_len;
22492                } else if current_line_len != current_prefix_len {
22493                    current_line.push(' ');
22494                    current_line_len += 1;
22495                }
22496            }
22497        }
22498    }
22499
22500    if !current_line.is_empty() {
22501        wrapped_text.push_str(&current_line);
22502    }
22503    wrapped_text
22504}
22505
22506#[test]
22507fn test_wrap_with_prefix() {
22508    assert_eq!(
22509        wrap_with_prefix(
22510            "# ".to_string(),
22511            "# ".to_string(),
22512            "abcdefg".to_string(),
22513            4,
22514            NonZeroU32::new(4).unwrap(),
22515            false,
22516        ),
22517        "# abcdefg"
22518    );
22519    assert_eq!(
22520        wrap_with_prefix(
22521            "".to_string(),
22522            "".to_string(),
22523            "\thello world".to_string(),
22524            8,
22525            NonZeroU32::new(4).unwrap(),
22526            false,
22527        ),
22528        "hello\nworld"
22529    );
22530    assert_eq!(
22531        wrap_with_prefix(
22532            "// ".to_string(),
22533            "// ".to_string(),
22534            "xx \nyy zz aa bb cc".to_string(),
22535            12,
22536            NonZeroU32::new(4).unwrap(),
22537            false,
22538        ),
22539        "// xx yy zz\n// aa bb cc"
22540    );
22541    assert_eq!(
22542        wrap_with_prefix(
22543            String::new(),
22544            String::new(),
22545            "这是什么 \n 钢笔".to_string(),
22546            3,
22547            NonZeroU32::new(4).unwrap(),
22548            false,
22549        ),
22550        "这是什\n么 钢\n"
22551    );
22552    assert_eq!(
22553        wrap_with_prefix(
22554            String::new(),
22555            String::new(),
22556            format!("foo{}bar", '\u{2009}'), // thin space
22557            80,
22558            NonZeroU32::new(4).unwrap(),
22559            false,
22560        ),
22561        format!("foo{}bar", '\u{2009}')
22562    );
22563}
22564
22565pub trait CollaborationHub {
22566    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22567    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22568    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22569}
22570
22571impl CollaborationHub for Entity<Project> {
22572    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22573        self.read(cx).collaborators()
22574    }
22575
22576    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22577        self.read(cx).user_store().read(cx).participant_indices()
22578    }
22579
22580    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22581        let this = self.read(cx);
22582        let user_ids = this.collaborators().values().map(|c| c.user_id);
22583        this.user_store().read(cx).participant_names(user_ids, cx)
22584    }
22585}
22586
22587pub trait SemanticsProvider {
22588    fn hover(
22589        &self,
22590        buffer: &Entity<Buffer>,
22591        position: text::Anchor,
22592        cx: &mut App,
22593    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22594
22595    fn inline_values(
22596        &self,
22597        buffer_handle: Entity<Buffer>,
22598        range: Range<text::Anchor>,
22599        cx: &mut App,
22600    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22601
22602    fn inlay_hints(
22603        &self,
22604        buffer_handle: Entity<Buffer>,
22605        range: Range<text::Anchor>,
22606        cx: &mut App,
22607    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22608
22609    fn resolve_inlay_hint(
22610        &self,
22611        hint: InlayHint,
22612        buffer_handle: Entity<Buffer>,
22613        server_id: LanguageServerId,
22614        cx: &mut App,
22615    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22616
22617    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22618
22619    fn document_highlights(
22620        &self,
22621        buffer: &Entity<Buffer>,
22622        position: text::Anchor,
22623        cx: &mut App,
22624    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22625
22626    fn definitions(
22627        &self,
22628        buffer: &Entity<Buffer>,
22629        position: text::Anchor,
22630        kind: GotoDefinitionKind,
22631        cx: &mut App,
22632    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22633
22634    fn range_for_rename(
22635        &self,
22636        buffer: &Entity<Buffer>,
22637        position: text::Anchor,
22638        cx: &mut App,
22639    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22640
22641    fn perform_rename(
22642        &self,
22643        buffer: &Entity<Buffer>,
22644        position: text::Anchor,
22645        new_name: String,
22646        cx: &mut App,
22647    ) -> Option<Task<Result<ProjectTransaction>>>;
22648}
22649
22650pub trait CompletionProvider {
22651    fn completions(
22652        &self,
22653        excerpt_id: ExcerptId,
22654        buffer: &Entity<Buffer>,
22655        buffer_position: text::Anchor,
22656        trigger: CompletionContext,
22657        window: &mut Window,
22658        cx: &mut Context<Editor>,
22659    ) -> Task<Result<Vec<CompletionResponse>>>;
22660
22661    fn resolve_completions(
22662        &self,
22663        _buffer: Entity<Buffer>,
22664        _completion_indices: Vec<usize>,
22665        _completions: Rc<RefCell<Box<[Completion]>>>,
22666        _cx: &mut Context<Editor>,
22667    ) -> Task<Result<bool>> {
22668        Task::ready(Ok(false))
22669    }
22670
22671    fn apply_additional_edits_for_completion(
22672        &self,
22673        _buffer: Entity<Buffer>,
22674        _completions: Rc<RefCell<Box<[Completion]>>>,
22675        _completion_index: usize,
22676        _push_to_history: bool,
22677        _cx: &mut Context<Editor>,
22678    ) -> Task<Result<Option<language::Transaction>>> {
22679        Task::ready(Ok(None))
22680    }
22681
22682    fn is_completion_trigger(
22683        &self,
22684        buffer: &Entity<Buffer>,
22685        position: language::Anchor,
22686        text: &str,
22687        trigger_in_words: bool,
22688        menu_is_open: bool,
22689        cx: &mut Context<Editor>,
22690    ) -> bool;
22691
22692    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22693
22694    fn sort_completions(&self) -> bool {
22695        true
22696    }
22697
22698    fn filter_completions(&self) -> bool {
22699        true
22700    }
22701}
22702
22703pub trait CodeActionProvider {
22704    fn id(&self) -> Arc<str>;
22705
22706    fn code_actions(
22707        &self,
22708        buffer: &Entity<Buffer>,
22709        range: Range<text::Anchor>,
22710        window: &mut Window,
22711        cx: &mut App,
22712    ) -> Task<Result<Vec<CodeAction>>>;
22713
22714    fn apply_code_action(
22715        &self,
22716        buffer_handle: Entity<Buffer>,
22717        action: CodeAction,
22718        excerpt_id: ExcerptId,
22719        push_to_history: bool,
22720        window: &mut Window,
22721        cx: &mut App,
22722    ) -> Task<Result<ProjectTransaction>>;
22723}
22724
22725impl CodeActionProvider for Entity<Project> {
22726    fn id(&self) -> Arc<str> {
22727        "project".into()
22728    }
22729
22730    fn code_actions(
22731        &self,
22732        buffer: &Entity<Buffer>,
22733        range: Range<text::Anchor>,
22734        _window: &mut Window,
22735        cx: &mut App,
22736    ) -> Task<Result<Vec<CodeAction>>> {
22737        self.update(cx, |project, cx| {
22738            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22739            let code_actions = project.code_actions(buffer, range, None, cx);
22740            cx.background_spawn(async move {
22741                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22742                Ok(code_lens_actions
22743                    .context("code lens fetch")?
22744                    .into_iter()
22745                    .flatten()
22746                    .chain(
22747                        code_actions
22748                            .context("code action fetch")?
22749                            .into_iter()
22750                            .flatten(),
22751                    )
22752                    .collect())
22753            })
22754        })
22755    }
22756
22757    fn apply_code_action(
22758        &self,
22759        buffer_handle: Entity<Buffer>,
22760        action: CodeAction,
22761        _excerpt_id: ExcerptId,
22762        push_to_history: bool,
22763        _window: &mut Window,
22764        cx: &mut App,
22765    ) -> Task<Result<ProjectTransaction>> {
22766        self.update(cx, |project, cx| {
22767            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22768        })
22769    }
22770}
22771
22772fn snippet_completions(
22773    project: &Project,
22774    buffer: &Entity<Buffer>,
22775    buffer_position: text::Anchor,
22776    cx: &mut App,
22777) -> Task<Result<CompletionResponse>> {
22778    let languages = buffer.read(cx).languages_at(buffer_position);
22779    let snippet_store = project.snippets().read(cx);
22780
22781    let scopes: Vec<_> = languages
22782        .iter()
22783        .filter_map(|language| {
22784            let language_name = language.lsp_id();
22785            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22786
22787            if snippets.is_empty() {
22788                None
22789            } else {
22790                Some((language.default_scope(), snippets))
22791            }
22792        })
22793        .collect();
22794
22795    if scopes.is_empty() {
22796        return Task::ready(Ok(CompletionResponse {
22797            completions: vec![],
22798            display_options: CompletionDisplayOptions::default(),
22799            is_incomplete: false,
22800        }));
22801    }
22802
22803    let snapshot = buffer.read(cx).text_snapshot();
22804    let executor = cx.background_executor().clone();
22805
22806    cx.background_spawn(async move {
22807        let mut is_incomplete = false;
22808        let mut completions: Vec<Completion> = Vec::new();
22809        for (scope, snippets) in scopes.into_iter() {
22810            let classifier =
22811                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22812
22813            const MAX_WORD_PREFIX_LEN: usize = 128;
22814            let last_word: String = snapshot
22815                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22816                .take(MAX_WORD_PREFIX_LEN)
22817                .take_while(|c| classifier.is_word(*c))
22818                .collect::<String>()
22819                .chars()
22820                .rev()
22821                .collect();
22822
22823            if last_word.is_empty() {
22824                return Ok(CompletionResponse {
22825                    completions: vec![],
22826                    display_options: CompletionDisplayOptions::default(),
22827                    is_incomplete: true,
22828                });
22829            }
22830
22831            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22832            let to_lsp = |point: &text::Anchor| {
22833                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22834                point_to_lsp(end)
22835            };
22836            let lsp_end = to_lsp(&buffer_position);
22837
22838            let candidates = snippets
22839                .iter()
22840                .enumerate()
22841                .flat_map(|(ix, snippet)| {
22842                    snippet
22843                        .prefix
22844                        .iter()
22845                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22846                })
22847                .collect::<Vec<StringMatchCandidate>>();
22848
22849            const MAX_RESULTS: usize = 100;
22850            let mut matches = fuzzy::match_strings(
22851                &candidates,
22852                &last_word,
22853                last_word.chars().any(|c| c.is_uppercase()),
22854                true,
22855                MAX_RESULTS,
22856                &Default::default(),
22857                executor.clone(),
22858            )
22859            .await;
22860
22861            if matches.len() >= MAX_RESULTS {
22862                is_incomplete = true;
22863            }
22864
22865            // Remove all candidates where the query's start does not match the start of any word in the candidate
22866            if let Some(query_start) = last_word.chars().next() {
22867                matches.retain(|string_match| {
22868                    split_words(&string_match.string).any(|word| {
22869                        // Check that the first codepoint of the word as lowercase matches the first
22870                        // codepoint of the query as lowercase
22871                        word.chars()
22872                            .flat_map(|codepoint| codepoint.to_lowercase())
22873                            .zip(query_start.to_lowercase())
22874                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22875                    })
22876                });
22877            }
22878
22879            let matched_strings = matches
22880                .into_iter()
22881                .map(|m| m.string)
22882                .collect::<HashSet<_>>();
22883
22884            completions.extend(snippets.iter().filter_map(|snippet| {
22885                let matching_prefix = snippet
22886                    .prefix
22887                    .iter()
22888                    .find(|prefix| matched_strings.contains(*prefix))?;
22889                let start = as_offset - last_word.len();
22890                let start = snapshot.anchor_before(start);
22891                let range = start..buffer_position;
22892                let lsp_start = to_lsp(&start);
22893                let lsp_range = lsp::Range {
22894                    start: lsp_start,
22895                    end: lsp_end,
22896                };
22897                Some(Completion {
22898                    replace_range: range,
22899                    new_text: snippet.body.clone(),
22900                    source: CompletionSource::Lsp {
22901                        insert_range: None,
22902                        server_id: LanguageServerId(usize::MAX),
22903                        resolved: true,
22904                        lsp_completion: Box::new(lsp::CompletionItem {
22905                            label: snippet.prefix.first().unwrap().clone(),
22906                            kind: Some(CompletionItemKind::SNIPPET),
22907                            label_details: snippet.description.as_ref().map(|description| {
22908                                lsp::CompletionItemLabelDetails {
22909                                    detail: Some(description.clone()),
22910                                    description: None,
22911                                }
22912                            }),
22913                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22914                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22915                                lsp::InsertReplaceEdit {
22916                                    new_text: snippet.body.clone(),
22917                                    insert: lsp_range,
22918                                    replace: lsp_range,
22919                                },
22920                            )),
22921                            filter_text: Some(snippet.body.clone()),
22922                            sort_text: Some(char::MAX.to_string()),
22923                            ..lsp::CompletionItem::default()
22924                        }),
22925                        lsp_defaults: None,
22926                    },
22927                    label: CodeLabel {
22928                        text: matching_prefix.clone(),
22929                        runs: Vec::new(),
22930                        filter_range: 0..matching_prefix.len(),
22931                    },
22932                    icon_path: None,
22933                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22934                        single_line: snippet.name.clone().into(),
22935                        plain_text: snippet
22936                            .description
22937                            .clone()
22938                            .map(|description| description.into()),
22939                    }),
22940                    insert_text_mode: None,
22941                    confirm: None,
22942                })
22943            }))
22944        }
22945
22946        Ok(CompletionResponse {
22947            completions,
22948            display_options: CompletionDisplayOptions::default(),
22949            is_incomplete,
22950        })
22951    })
22952}
22953
22954impl CompletionProvider for Entity<Project> {
22955    fn completions(
22956        &self,
22957        _excerpt_id: ExcerptId,
22958        buffer: &Entity<Buffer>,
22959        buffer_position: text::Anchor,
22960        options: CompletionContext,
22961        _window: &mut Window,
22962        cx: &mut Context<Editor>,
22963    ) -> Task<Result<Vec<CompletionResponse>>> {
22964        self.update(cx, |project, cx| {
22965            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22966            let project_completions = project.completions(buffer, buffer_position, options, cx);
22967            cx.background_spawn(async move {
22968                let mut responses = project_completions.await?;
22969                let snippets = snippets.await?;
22970                if !snippets.completions.is_empty() {
22971                    responses.push(snippets);
22972                }
22973                Ok(responses)
22974            })
22975        })
22976    }
22977
22978    fn resolve_completions(
22979        &self,
22980        buffer: Entity<Buffer>,
22981        completion_indices: Vec<usize>,
22982        completions: Rc<RefCell<Box<[Completion]>>>,
22983        cx: &mut Context<Editor>,
22984    ) -> Task<Result<bool>> {
22985        self.update(cx, |project, cx| {
22986            project.lsp_store().update(cx, |lsp_store, cx| {
22987                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22988            })
22989        })
22990    }
22991
22992    fn apply_additional_edits_for_completion(
22993        &self,
22994        buffer: Entity<Buffer>,
22995        completions: Rc<RefCell<Box<[Completion]>>>,
22996        completion_index: usize,
22997        push_to_history: bool,
22998        cx: &mut Context<Editor>,
22999    ) -> Task<Result<Option<language::Transaction>>> {
23000        self.update(cx, |project, cx| {
23001            project.lsp_store().update(cx, |lsp_store, cx| {
23002                lsp_store.apply_additional_edits_for_completion(
23003                    buffer,
23004                    completions,
23005                    completion_index,
23006                    push_to_history,
23007                    cx,
23008                )
23009            })
23010        })
23011    }
23012
23013    fn is_completion_trigger(
23014        &self,
23015        buffer: &Entity<Buffer>,
23016        position: language::Anchor,
23017        text: &str,
23018        trigger_in_words: bool,
23019        menu_is_open: bool,
23020        cx: &mut Context<Editor>,
23021    ) -> bool {
23022        let mut chars = text.chars();
23023        let char = if let Some(char) = chars.next() {
23024            char
23025        } else {
23026            return false;
23027        };
23028        if chars.next().is_some() {
23029            return false;
23030        }
23031
23032        let buffer = buffer.read(cx);
23033        let snapshot = buffer.snapshot();
23034        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23035            return false;
23036        }
23037        let classifier = snapshot
23038            .char_classifier_at(position)
23039            .scope_context(Some(CharScopeContext::Completion));
23040        if trigger_in_words && classifier.is_word(char) {
23041            return true;
23042        }
23043
23044        buffer.completion_triggers().contains(text)
23045    }
23046}
23047
23048impl SemanticsProvider for Entity<Project> {
23049    fn hover(
23050        &self,
23051        buffer: &Entity<Buffer>,
23052        position: text::Anchor,
23053        cx: &mut App,
23054    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23055        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23056    }
23057
23058    fn document_highlights(
23059        &self,
23060        buffer: &Entity<Buffer>,
23061        position: text::Anchor,
23062        cx: &mut App,
23063    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23064        Some(self.update(cx, |project, cx| {
23065            project.document_highlights(buffer, position, cx)
23066        }))
23067    }
23068
23069    fn definitions(
23070        &self,
23071        buffer: &Entity<Buffer>,
23072        position: text::Anchor,
23073        kind: GotoDefinitionKind,
23074        cx: &mut App,
23075    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23076        Some(self.update(cx, |project, cx| match kind {
23077            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23078            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23079            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23080            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23081        }))
23082    }
23083
23084    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23085        self.update(cx, |project, cx| {
23086            if project
23087                .active_debug_session(cx)
23088                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23089            {
23090                return true;
23091            }
23092
23093            buffer.update(cx, |buffer, cx| {
23094                project.any_language_server_supports_inlay_hints(buffer, cx)
23095            })
23096        })
23097    }
23098
23099    fn inline_values(
23100        &self,
23101        buffer_handle: Entity<Buffer>,
23102        range: Range<text::Anchor>,
23103        cx: &mut App,
23104    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23105        self.update(cx, |project, cx| {
23106            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23107
23108            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23109        })
23110    }
23111
23112    fn inlay_hints(
23113        &self,
23114        buffer_handle: Entity<Buffer>,
23115        range: Range<text::Anchor>,
23116        cx: &mut App,
23117    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23118        Some(self.update(cx, |project, cx| {
23119            project.inlay_hints(buffer_handle, range, cx)
23120        }))
23121    }
23122
23123    fn resolve_inlay_hint(
23124        &self,
23125        hint: InlayHint,
23126        buffer_handle: Entity<Buffer>,
23127        server_id: LanguageServerId,
23128        cx: &mut App,
23129    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23130        Some(self.update(cx, |project, cx| {
23131            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23132        }))
23133    }
23134
23135    fn range_for_rename(
23136        &self,
23137        buffer: &Entity<Buffer>,
23138        position: text::Anchor,
23139        cx: &mut App,
23140    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23141        Some(self.update(cx, |project, cx| {
23142            let buffer = buffer.clone();
23143            let task = project.prepare_rename(buffer.clone(), position, cx);
23144            cx.spawn(async move |_, cx| {
23145                Ok(match task.await? {
23146                    PrepareRenameResponse::Success(range) => Some(range),
23147                    PrepareRenameResponse::InvalidPosition => None,
23148                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23149                        // Fallback on using TreeSitter info to determine identifier range
23150                        buffer.read_with(cx, |buffer, _| {
23151                            let snapshot = buffer.snapshot();
23152                            let (range, kind) = snapshot.surrounding_word(position, None);
23153                            if kind != Some(CharKind::Word) {
23154                                return None;
23155                            }
23156                            Some(
23157                                snapshot.anchor_before(range.start)
23158                                    ..snapshot.anchor_after(range.end),
23159                            )
23160                        })?
23161                    }
23162                })
23163            })
23164        }))
23165    }
23166
23167    fn perform_rename(
23168        &self,
23169        buffer: &Entity<Buffer>,
23170        position: text::Anchor,
23171        new_name: String,
23172        cx: &mut App,
23173    ) -> Option<Task<Result<ProjectTransaction>>> {
23174        Some(self.update(cx, |project, cx| {
23175            project.perform_rename(buffer.clone(), position, new_name, cx)
23176        }))
23177    }
23178}
23179
23180fn inlay_hint_settings(
23181    location: Anchor,
23182    snapshot: &MultiBufferSnapshot,
23183    cx: &mut Context<Editor>,
23184) -> InlayHintSettings {
23185    let file = snapshot.file_at(location);
23186    let language = snapshot.language_at(location).map(|l| l.name());
23187    language_settings(language, file, cx).inlay_hints
23188}
23189
23190fn consume_contiguous_rows(
23191    contiguous_row_selections: &mut Vec<Selection<Point>>,
23192    selection: &Selection<Point>,
23193    display_map: &DisplaySnapshot,
23194    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23195) -> (MultiBufferRow, MultiBufferRow) {
23196    contiguous_row_selections.push(selection.clone());
23197    let start_row = starting_row(selection, display_map);
23198    let mut end_row = ending_row(selection, display_map);
23199
23200    while let Some(next_selection) = selections.peek() {
23201        if next_selection.start.row <= end_row.0 {
23202            end_row = ending_row(next_selection, display_map);
23203            contiguous_row_selections.push(selections.next().unwrap().clone());
23204        } else {
23205            break;
23206        }
23207    }
23208    (start_row, end_row)
23209}
23210
23211fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23212    if selection.start.column > 0 {
23213        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23214    } else {
23215        MultiBufferRow(selection.start.row)
23216    }
23217}
23218
23219fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23220    if next_selection.end.column > 0 || next_selection.is_empty() {
23221        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23222    } else {
23223        MultiBufferRow(next_selection.end.row)
23224    }
23225}
23226
23227impl EditorSnapshot {
23228    pub fn remote_selections_in_range<'a>(
23229        &'a self,
23230        range: &'a Range<Anchor>,
23231        collaboration_hub: &dyn CollaborationHub,
23232        cx: &'a App,
23233    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23234        let participant_names = collaboration_hub.user_names(cx);
23235        let participant_indices = collaboration_hub.user_participant_indices(cx);
23236        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23237        let collaborators_by_replica_id = collaborators_by_peer_id
23238            .values()
23239            .map(|collaborator| (collaborator.replica_id, collaborator))
23240            .collect::<HashMap<_, _>>();
23241        self.buffer_snapshot()
23242            .selections_in_range(range, false)
23243            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23244                if replica_id == AGENT_REPLICA_ID {
23245                    Some(RemoteSelection {
23246                        replica_id,
23247                        selection,
23248                        cursor_shape,
23249                        line_mode,
23250                        collaborator_id: CollaboratorId::Agent,
23251                        user_name: Some("Agent".into()),
23252                        color: cx.theme().players().agent(),
23253                    })
23254                } else {
23255                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23256                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23257                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23258                    Some(RemoteSelection {
23259                        replica_id,
23260                        selection,
23261                        cursor_shape,
23262                        line_mode,
23263                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23264                        user_name,
23265                        color: if let Some(index) = participant_index {
23266                            cx.theme().players().color_for_participant(index.0)
23267                        } else {
23268                            cx.theme().players().absent()
23269                        },
23270                    })
23271                }
23272            })
23273    }
23274
23275    pub fn hunks_for_ranges(
23276        &self,
23277        ranges: impl IntoIterator<Item = Range<Point>>,
23278    ) -> Vec<MultiBufferDiffHunk> {
23279        let mut hunks = Vec::new();
23280        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23281            HashMap::default();
23282        for query_range in ranges {
23283            let query_rows =
23284                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23285            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23286                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23287            ) {
23288                // Include deleted hunks that are adjacent to the query range, because
23289                // otherwise they would be missed.
23290                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23291                if hunk.status().is_deleted() {
23292                    intersects_range |= hunk.row_range.start == query_rows.end;
23293                    intersects_range |= hunk.row_range.end == query_rows.start;
23294                }
23295                if intersects_range {
23296                    if !processed_buffer_rows
23297                        .entry(hunk.buffer_id)
23298                        .or_default()
23299                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23300                    {
23301                        continue;
23302                    }
23303                    hunks.push(hunk);
23304                }
23305            }
23306        }
23307
23308        hunks
23309    }
23310
23311    fn display_diff_hunks_for_rows<'a>(
23312        &'a self,
23313        display_rows: Range<DisplayRow>,
23314        folded_buffers: &'a HashSet<BufferId>,
23315    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23316        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23317        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23318
23319        self.buffer_snapshot()
23320            .diff_hunks_in_range(buffer_start..buffer_end)
23321            .filter_map(|hunk| {
23322                if folded_buffers.contains(&hunk.buffer_id) {
23323                    return None;
23324                }
23325
23326                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23327                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23328
23329                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23330                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23331
23332                let display_hunk = if hunk_display_start.column() != 0 {
23333                    DisplayDiffHunk::Folded {
23334                        display_row: hunk_display_start.row(),
23335                    }
23336                } else {
23337                    let mut end_row = hunk_display_end.row();
23338                    if hunk_display_end.column() > 0 {
23339                        end_row.0 += 1;
23340                    }
23341                    let is_created_file = hunk.is_created_file();
23342                    DisplayDiffHunk::Unfolded {
23343                        status: hunk.status(),
23344                        diff_base_byte_range: hunk.diff_base_byte_range,
23345                        display_row_range: hunk_display_start.row()..end_row,
23346                        multi_buffer_range: Anchor::range_in_buffer(
23347                            hunk.excerpt_id,
23348                            hunk.buffer_id,
23349                            hunk.buffer_range,
23350                        ),
23351                        is_created_file,
23352                    }
23353                };
23354
23355                Some(display_hunk)
23356            })
23357    }
23358
23359    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23360        self.display_snapshot
23361            .buffer_snapshot()
23362            .language_at(position)
23363    }
23364
23365    pub fn is_focused(&self) -> bool {
23366        self.is_focused
23367    }
23368
23369    pub fn placeholder_text(&self) -> Option<String> {
23370        self.placeholder_display_snapshot
23371            .as_ref()
23372            .map(|display_map| display_map.text())
23373    }
23374
23375    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23376        self.scroll_anchor.scroll_position(&self.display_snapshot)
23377    }
23378
23379    fn gutter_dimensions(
23380        &self,
23381        font_id: FontId,
23382        font_size: Pixels,
23383        max_line_number_width: Pixels,
23384        cx: &App,
23385    ) -> Option<GutterDimensions> {
23386        if !self.show_gutter {
23387            return None;
23388        }
23389
23390        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23391        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23392
23393        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23394            matches!(
23395                ProjectSettings::get_global(cx).git.git_gutter,
23396                GitGutterSetting::TrackedFiles
23397            )
23398        });
23399        let gutter_settings = EditorSettings::get_global(cx).gutter;
23400        let show_line_numbers = self
23401            .show_line_numbers
23402            .unwrap_or(gutter_settings.line_numbers);
23403        let line_gutter_width = if show_line_numbers {
23404            // Avoid flicker-like gutter resizes when the line number gains another digit by
23405            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23406            let min_width_for_number_on_gutter =
23407                ch_advance * gutter_settings.min_line_number_digits as f32;
23408            max_line_number_width.max(min_width_for_number_on_gutter)
23409        } else {
23410            0.0.into()
23411        };
23412
23413        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23414        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23415
23416        let git_blame_entries_width =
23417            self.git_blame_gutter_max_author_length
23418                .map(|max_author_length| {
23419                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23420                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23421
23422                    /// The number of characters to dedicate to gaps and margins.
23423                    const SPACING_WIDTH: usize = 4;
23424
23425                    let max_char_count = max_author_length.min(renderer.max_author_length())
23426                        + ::git::SHORT_SHA_LENGTH
23427                        + MAX_RELATIVE_TIMESTAMP.len()
23428                        + SPACING_WIDTH;
23429
23430                    ch_advance * max_char_count
23431                });
23432
23433        let is_singleton = self.buffer_snapshot().is_singleton();
23434
23435        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23436        left_padding += if !is_singleton {
23437            ch_width * 4.0
23438        } else if show_runnables || show_breakpoints {
23439            ch_width * 3.0
23440        } else if show_git_gutter && show_line_numbers {
23441            ch_width * 2.0
23442        } else if show_git_gutter || show_line_numbers {
23443            ch_width
23444        } else {
23445            px(0.)
23446        };
23447
23448        let shows_folds = is_singleton && gutter_settings.folds;
23449
23450        let right_padding = if shows_folds && show_line_numbers {
23451            ch_width * 4.0
23452        } else if shows_folds || (!is_singleton && show_line_numbers) {
23453            ch_width * 3.0
23454        } else if show_line_numbers {
23455            ch_width
23456        } else {
23457            px(0.)
23458        };
23459
23460        Some(GutterDimensions {
23461            left_padding,
23462            right_padding,
23463            width: line_gutter_width + left_padding + right_padding,
23464            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23465            git_blame_entries_width,
23466        })
23467    }
23468
23469    pub fn render_crease_toggle(
23470        &self,
23471        buffer_row: MultiBufferRow,
23472        row_contains_cursor: bool,
23473        editor: Entity<Editor>,
23474        window: &mut Window,
23475        cx: &mut App,
23476    ) -> Option<AnyElement> {
23477        let folded = self.is_line_folded(buffer_row);
23478        let mut is_foldable = false;
23479
23480        if let Some(crease) = self
23481            .crease_snapshot
23482            .query_row(buffer_row, self.buffer_snapshot())
23483        {
23484            is_foldable = true;
23485            match crease {
23486                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23487                    if let Some(render_toggle) = render_toggle {
23488                        let toggle_callback =
23489                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23490                                if folded {
23491                                    editor.update(cx, |editor, cx| {
23492                                        editor.fold_at(buffer_row, window, cx)
23493                                    });
23494                                } else {
23495                                    editor.update(cx, |editor, cx| {
23496                                        editor.unfold_at(buffer_row, window, cx)
23497                                    });
23498                                }
23499                            });
23500                        return Some((render_toggle)(
23501                            buffer_row,
23502                            folded,
23503                            toggle_callback,
23504                            window,
23505                            cx,
23506                        ));
23507                    }
23508                }
23509            }
23510        }
23511
23512        is_foldable |= self.starts_indent(buffer_row);
23513
23514        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23515            Some(
23516                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23517                    .toggle_state(folded)
23518                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23519                        if folded {
23520                            this.unfold_at(buffer_row, window, cx);
23521                        } else {
23522                            this.fold_at(buffer_row, window, cx);
23523                        }
23524                    }))
23525                    .into_any_element(),
23526            )
23527        } else {
23528            None
23529        }
23530    }
23531
23532    pub fn render_crease_trailer(
23533        &self,
23534        buffer_row: MultiBufferRow,
23535        window: &mut Window,
23536        cx: &mut App,
23537    ) -> Option<AnyElement> {
23538        let folded = self.is_line_folded(buffer_row);
23539        if let Crease::Inline { render_trailer, .. } = self
23540            .crease_snapshot
23541            .query_row(buffer_row, self.buffer_snapshot())?
23542        {
23543            let render_trailer = render_trailer.as_ref()?;
23544            Some(render_trailer(buffer_row, folded, window, cx))
23545        } else {
23546            None
23547        }
23548    }
23549}
23550
23551impl Deref for EditorSnapshot {
23552    type Target = DisplaySnapshot;
23553
23554    fn deref(&self) -> &Self::Target {
23555        &self.display_snapshot
23556    }
23557}
23558
23559#[derive(Clone, Debug, PartialEq, Eq)]
23560pub enum EditorEvent {
23561    InputIgnored {
23562        text: Arc<str>,
23563    },
23564    InputHandled {
23565        utf16_range_to_replace: Option<Range<isize>>,
23566        text: Arc<str>,
23567    },
23568    ExcerptsAdded {
23569        buffer: Entity<Buffer>,
23570        predecessor: ExcerptId,
23571        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23572    },
23573    ExcerptsRemoved {
23574        ids: Vec<ExcerptId>,
23575        removed_buffer_ids: Vec<BufferId>,
23576    },
23577    BufferFoldToggled {
23578        ids: Vec<ExcerptId>,
23579        folded: bool,
23580    },
23581    ExcerptsEdited {
23582        ids: Vec<ExcerptId>,
23583    },
23584    ExcerptsExpanded {
23585        ids: Vec<ExcerptId>,
23586    },
23587    BufferEdited,
23588    Edited {
23589        transaction_id: clock::Lamport,
23590    },
23591    Reparsed(BufferId),
23592    Focused,
23593    FocusedIn,
23594    Blurred,
23595    DirtyChanged,
23596    Saved,
23597    TitleChanged,
23598    SelectionsChanged {
23599        local: bool,
23600    },
23601    ScrollPositionChanged {
23602        local: bool,
23603        autoscroll: bool,
23604    },
23605    TransactionUndone {
23606        transaction_id: clock::Lamport,
23607    },
23608    TransactionBegun {
23609        transaction_id: clock::Lamport,
23610    },
23611    CursorShapeChanged,
23612    BreadcrumbsChanged,
23613    PushedToNavHistory {
23614        anchor: Anchor,
23615        is_deactivate: bool,
23616    },
23617}
23618
23619impl EventEmitter<EditorEvent> for Editor {}
23620
23621impl Focusable for Editor {
23622    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23623        self.focus_handle.clone()
23624    }
23625}
23626
23627impl Render for Editor {
23628    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23629        let settings = ThemeSettings::get_global(cx);
23630
23631        let mut text_style = match self.mode {
23632            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23633                color: cx.theme().colors().editor_foreground,
23634                font_family: settings.ui_font.family.clone(),
23635                font_features: settings.ui_font.features.clone(),
23636                font_fallbacks: settings.ui_font.fallbacks.clone(),
23637                font_size: rems(0.875).into(),
23638                font_weight: settings.ui_font.weight,
23639                line_height: relative(settings.buffer_line_height.value()),
23640                ..Default::default()
23641            },
23642            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23643                color: cx.theme().colors().editor_foreground,
23644                font_family: settings.buffer_font.family.clone(),
23645                font_features: settings.buffer_font.features.clone(),
23646                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23647                font_size: settings.buffer_font_size(cx).into(),
23648                font_weight: settings.buffer_font.weight,
23649                line_height: relative(settings.buffer_line_height.value()),
23650                ..Default::default()
23651            },
23652        };
23653        if let Some(text_style_refinement) = &self.text_style_refinement {
23654            text_style.refine(text_style_refinement)
23655        }
23656
23657        let background = match self.mode {
23658            EditorMode::SingleLine => cx.theme().system().transparent,
23659            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23660            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23661            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23662        };
23663
23664        EditorElement::new(
23665            &cx.entity(),
23666            EditorStyle {
23667                background,
23668                border: cx.theme().colors().border,
23669                local_player: cx.theme().players().local(),
23670                text: text_style,
23671                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23672                syntax: cx.theme().syntax().clone(),
23673                status: cx.theme().status().clone(),
23674                inlay_hints_style: make_inlay_hints_style(cx),
23675                edit_prediction_styles: make_suggestion_styles(cx),
23676                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23677                show_underlines: self.diagnostics_enabled(),
23678            },
23679        )
23680    }
23681}
23682
23683impl EntityInputHandler for Editor {
23684    fn text_for_range(
23685        &mut self,
23686        range_utf16: Range<usize>,
23687        adjusted_range: &mut Option<Range<usize>>,
23688        _: &mut Window,
23689        cx: &mut Context<Self>,
23690    ) -> Option<String> {
23691        let snapshot = self.buffer.read(cx).read(cx);
23692        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23693        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23694        if (start.0..end.0) != range_utf16 {
23695            adjusted_range.replace(start.0..end.0);
23696        }
23697        Some(snapshot.text_for_range(start..end).collect())
23698    }
23699
23700    fn selected_text_range(
23701        &mut self,
23702        ignore_disabled_input: bool,
23703        _: &mut Window,
23704        cx: &mut Context<Self>,
23705    ) -> Option<UTF16Selection> {
23706        // Prevent the IME menu from appearing when holding down an alphabetic key
23707        // while input is disabled.
23708        if !ignore_disabled_input && !self.input_enabled {
23709            return None;
23710        }
23711
23712        let selection = self.selections.newest::<OffsetUtf16>(cx);
23713        let range = selection.range();
23714
23715        Some(UTF16Selection {
23716            range: range.start.0..range.end.0,
23717            reversed: selection.reversed,
23718        })
23719    }
23720
23721    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23722        let snapshot = self.buffer.read(cx).read(cx);
23723        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23724        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23725    }
23726
23727    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23728        self.clear_highlights::<InputComposition>(cx);
23729        self.ime_transaction.take();
23730    }
23731
23732    fn replace_text_in_range(
23733        &mut self,
23734        range_utf16: Option<Range<usize>>,
23735        text: &str,
23736        window: &mut Window,
23737        cx: &mut Context<Self>,
23738    ) {
23739        if !self.input_enabled {
23740            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23741            return;
23742        }
23743
23744        self.transact(window, cx, |this, window, cx| {
23745            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23746                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23747                Some(this.selection_replacement_ranges(range_utf16, cx))
23748            } else {
23749                this.marked_text_ranges(cx)
23750            };
23751
23752            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23753                let newest_selection_id = this.selections.newest_anchor().id;
23754                this.selections
23755                    .all::<OffsetUtf16>(cx)
23756                    .iter()
23757                    .zip(ranges_to_replace.iter())
23758                    .find_map(|(selection, range)| {
23759                        if selection.id == newest_selection_id {
23760                            Some(
23761                                (range.start.0 as isize - selection.head().0 as isize)
23762                                    ..(range.end.0 as isize - selection.head().0 as isize),
23763                            )
23764                        } else {
23765                            None
23766                        }
23767                    })
23768            });
23769
23770            cx.emit(EditorEvent::InputHandled {
23771                utf16_range_to_replace: range_to_replace,
23772                text: text.into(),
23773            });
23774
23775            if let Some(new_selected_ranges) = new_selected_ranges {
23776                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23777                    selections.select_ranges(new_selected_ranges)
23778                });
23779                this.backspace(&Default::default(), window, cx);
23780            }
23781
23782            this.handle_input(text, window, cx);
23783        });
23784
23785        if let Some(transaction) = self.ime_transaction {
23786            self.buffer.update(cx, |buffer, cx| {
23787                buffer.group_until_transaction(transaction, cx);
23788            });
23789        }
23790
23791        self.unmark_text(window, cx);
23792    }
23793
23794    fn replace_and_mark_text_in_range(
23795        &mut self,
23796        range_utf16: Option<Range<usize>>,
23797        text: &str,
23798        new_selected_range_utf16: Option<Range<usize>>,
23799        window: &mut Window,
23800        cx: &mut Context<Self>,
23801    ) {
23802        if !self.input_enabled {
23803            return;
23804        }
23805
23806        let transaction = self.transact(window, cx, |this, window, cx| {
23807            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23808                let snapshot = this.buffer.read(cx).read(cx);
23809                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23810                    for marked_range in &mut marked_ranges {
23811                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23812                        marked_range.start.0 += relative_range_utf16.start;
23813                        marked_range.start =
23814                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23815                        marked_range.end =
23816                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23817                    }
23818                }
23819                Some(marked_ranges)
23820            } else if let Some(range_utf16) = range_utf16 {
23821                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23822                Some(this.selection_replacement_ranges(range_utf16, cx))
23823            } else {
23824                None
23825            };
23826
23827            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23828                let newest_selection_id = this.selections.newest_anchor().id;
23829                this.selections
23830                    .all::<OffsetUtf16>(cx)
23831                    .iter()
23832                    .zip(ranges_to_replace.iter())
23833                    .find_map(|(selection, range)| {
23834                        if selection.id == newest_selection_id {
23835                            Some(
23836                                (range.start.0 as isize - selection.head().0 as isize)
23837                                    ..(range.end.0 as isize - selection.head().0 as isize),
23838                            )
23839                        } else {
23840                            None
23841                        }
23842                    })
23843            });
23844
23845            cx.emit(EditorEvent::InputHandled {
23846                utf16_range_to_replace: range_to_replace,
23847                text: text.into(),
23848            });
23849
23850            if let Some(ranges) = ranges_to_replace {
23851                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23852                    s.select_ranges(ranges)
23853                });
23854            }
23855
23856            let marked_ranges = {
23857                let snapshot = this.buffer.read(cx).read(cx);
23858                this.selections
23859                    .disjoint_anchors_arc()
23860                    .iter()
23861                    .map(|selection| {
23862                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23863                    })
23864                    .collect::<Vec<_>>()
23865            };
23866
23867            if text.is_empty() {
23868                this.unmark_text(window, cx);
23869            } else {
23870                this.highlight_text::<InputComposition>(
23871                    marked_ranges.clone(),
23872                    HighlightStyle {
23873                        underline: Some(UnderlineStyle {
23874                            thickness: px(1.),
23875                            color: None,
23876                            wavy: false,
23877                        }),
23878                        ..Default::default()
23879                    },
23880                    cx,
23881                );
23882            }
23883
23884            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23885            let use_autoclose = this.use_autoclose;
23886            let use_auto_surround = this.use_auto_surround;
23887            this.set_use_autoclose(false);
23888            this.set_use_auto_surround(false);
23889            this.handle_input(text, window, cx);
23890            this.set_use_autoclose(use_autoclose);
23891            this.set_use_auto_surround(use_auto_surround);
23892
23893            if let Some(new_selected_range) = new_selected_range_utf16 {
23894                let snapshot = this.buffer.read(cx).read(cx);
23895                let new_selected_ranges = marked_ranges
23896                    .into_iter()
23897                    .map(|marked_range| {
23898                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23899                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23900                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23901                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23902                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23903                    })
23904                    .collect::<Vec<_>>();
23905
23906                drop(snapshot);
23907                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23908                    selections.select_ranges(new_selected_ranges)
23909                });
23910            }
23911        });
23912
23913        self.ime_transaction = self.ime_transaction.or(transaction);
23914        if let Some(transaction) = self.ime_transaction {
23915            self.buffer.update(cx, |buffer, cx| {
23916                buffer.group_until_transaction(transaction, cx);
23917            });
23918        }
23919
23920        if self.text_highlights::<InputComposition>(cx).is_none() {
23921            self.ime_transaction.take();
23922        }
23923    }
23924
23925    fn bounds_for_range(
23926        &mut self,
23927        range_utf16: Range<usize>,
23928        element_bounds: gpui::Bounds<Pixels>,
23929        window: &mut Window,
23930        cx: &mut Context<Self>,
23931    ) -> Option<gpui::Bounds<Pixels>> {
23932        let text_layout_details = self.text_layout_details(window);
23933        let CharacterDimensions {
23934            em_width,
23935            em_advance,
23936            line_height,
23937        } = self.character_dimensions(window);
23938
23939        let snapshot = self.snapshot(window, cx);
23940        let scroll_position = snapshot.scroll_position();
23941        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
23942
23943        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23944        let x = Pixels::from(
23945            ScrollOffset::from(
23946                snapshot.x_for_display_point(start, &text_layout_details)
23947                    + self.gutter_dimensions.full_width(),
23948            ) - scroll_left,
23949        );
23950        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
23951
23952        Some(Bounds {
23953            origin: element_bounds.origin + point(x, y),
23954            size: size(em_width, line_height),
23955        })
23956    }
23957
23958    fn character_index_for_point(
23959        &mut self,
23960        point: gpui::Point<Pixels>,
23961        _window: &mut Window,
23962        _cx: &mut Context<Self>,
23963    ) -> Option<usize> {
23964        let position_map = self.last_position_map.as_ref()?;
23965        if !position_map.text_hitbox.contains(&point) {
23966            return None;
23967        }
23968        let display_point = position_map.point_for_position(point).previous_valid;
23969        let anchor = position_map
23970            .snapshot
23971            .display_point_to_anchor(display_point, Bias::Left);
23972        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
23973        Some(utf16_offset.0)
23974    }
23975}
23976
23977trait SelectionExt {
23978    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23979    fn spanned_rows(
23980        &self,
23981        include_end_if_at_line_start: bool,
23982        map: &DisplaySnapshot,
23983    ) -> Range<MultiBufferRow>;
23984}
23985
23986impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23987    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23988        let start = self
23989            .start
23990            .to_point(map.buffer_snapshot())
23991            .to_display_point(map);
23992        let end = self
23993            .end
23994            .to_point(map.buffer_snapshot())
23995            .to_display_point(map);
23996        if self.reversed {
23997            end..start
23998        } else {
23999            start..end
24000        }
24001    }
24002
24003    fn spanned_rows(
24004        &self,
24005        include_end_if_at_line_start: bool,
24006        map: &DisplaySnapshot,
24007    ) -> Range<MultiBufferRow> {
24008        let start = self.start.to_point(map.buffer_snapshot());
24009        let mut end = self.end.to_point(map.buffer_snapshot());
24010        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24011            end.row -= 1;
24012        }
24013
24014        let buffer_start = map.prev_line_boundary(start).0;
24015        let buffer_end = map.next_line_boundary(end).0;
24016        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24017    }
24018}
24019
24020impl<T: InvalidationRegion> InvalidationStack<T> {
24021    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24022    where
24023        S: Clone + ToOffset,
24024    {
24025        while let Some(region) = self.last() {
24026            let all_selections_inside_invalidation_ranges =
24027                if selections.len() == region.ranges().len() {
24028                    selections
24029                        .iter()
24030                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24031                        .all(|(selection, invalidation_range)| {
24032                            let head = selection.head().to_offset(buffer);
24033                            invalidation_range.start <= head && invalidation_range.end >= head
24034                        })
24035                } else {
24036                    false
24037                };
24038
24039            if all_selections_inside_invalidation_ranges {
24040                break;
24041            } else {
24042                self.pop();
24043            }
24044        }
24045    }
24046}
24047
24048impl<T> Default for InvalidationStack<T> {
24049    fn default() -> Self {
24050        Self(Default::default())
24051    }
24052}
24053
24054impl<T> Deref for InvalidationStack<T> {
24055    type Target = Vec<T>;
24056
24057    fn deref(&self) -> &Self::Target {
24058        &self.0
24059    }
24060}
24061
24062impl<T> DerefMut for InvalidationStack<T> {
24063    fn deref_mut(&mut self) -> &mut Self::Target {
24064        &mut self.0
24065    }
24066}
24067
24068impl InvalidationRegion for SnippetState {
24069    fn ranges(&self) -> &[Range<Anchor>] {
24070        &self.ranges[self.active_index]
24071    }
24072}
24073
24074fn edit_prediction_edit_text(
24075    current_snapshot: &BufferSnapshot,
24076    edits: &[(Range<Anchor>, String)],
24077    edit_preview: &EditPreview,
24078    include_deletions: bool,
24079    cx: &App,
24080) -> HighlightedText {
24081    let edits = edits
24082        .iter()
24083        .map(|(anchor, text)| {
24084            (
24085                anchor.start.text_anchor..anchor.end.text_anchor,
24086                text.clone(),
24087            )
24088        })
24089        .collect::<Vec<_>>();
24090
24091    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24092}
24093
24094fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24095    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24096    // Just show the raw edit text with basic styling
24097    let mut text = String::new();
24098    let mut highlights = Vec::new();
24099
24100    let insertion_highlight_style = HighlightStyle {
24101        color: Some(cx.theme().colors().text),
24102        ..Default::default()
24103    };
24104
24105    for (_, edit_text) in edits {
24106        let start_offset = text.len();
24107        text.push_str(edit_text);
24108        let end_offset = text.len();
24109
24110        if start_offset < end_offset {
24111            highlights.push((start_offset..end_offset, insertion_highlight_style));
24112        }
24113    }
24114
24115    HighlightedText {
24116        text: text.into(),
24117        highlights,
24118    }
24119}
24120
24121pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24122    match severity {
24123        lsp::DiagnosticSeverity::ERROR => colors.error,
24124        lsp::DiagnosticSeverity::WARNING => colors.warning,
24125        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24126        lsp::DiagnosticSeverity::HINT => colors.info,
24127        _ => colors.ignored,
24128    }
24129}
24130
24131pub fn styled_runs_for_code_label<'a>(
24132    label: &'a CodeLabel,
24133    syntax_theme: &'a theme::SyntaxTheme,
24134) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24135    let fade_out = HighlightStyle {
24136        fade_out: Some(0.35),
24137        ..Default::default()
24138    };
24139
24140    let mut prev_end = label.filter_range.end;
24141    label
24142        .runs
24143        .iter()
24144        .enumerate()
24145        .flat_map(move |(ix, (range, highlight_id))| {
24146            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24147                style
24148            } else {
24149                return Default::default();
24150            };
24151            let muted_style = style.highlight(fade_out);
24152
24153            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24154            if range.start >= label.filter_range.end {
24155                if range.start > prev_end {
24156                    runs.push((prev_end..range.start, fade_out));
24157                }
24158                runs.push((range.clone(), muted_style));
24159            } else if range.end <= label.filter_range.end {
24160                runs.push((range.clone(), style));
24161            } else {
24162                runs.push((range.start..label.filter_range.end, style));
24163                runs.push((label.filter_range.end..range.end, muted_style));
24164            }
24165            prev_end = cmp::max(prev_end, range.end);
24166
24167            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24168                runs.push((prev_end..label.text.len(), fade_out));
24169            }
24170
24171            runs
24172        })
24173}
24174
24175pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24176    let mut prev_index = 0;
24177    let mut prev_codepoint: Option<char> = None;
24178    text.char_indices()
24179        .chain([(text.len(), '\0')])
24180        .filter_map(move |(index, codepoint)| {
24181            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24182            let is_boundary = index == text.len()
24183                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24184                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24185            if is_boundary {
24186                let chunk = &text[prev_index..index];
24187                prev_index = index;
24188                Some(chunk)
24189            } else {
24190                None
24191            }
24192        })
24193}
24194
24195pub trait RangeToAnchorExt: Sized {
24196    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24197
24198    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24199        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24200        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24201    }
24202}
24203
24204impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24205    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24206        let start_offset = self.start.to_offset(snapshot);
24207        let end_offset = self.end.to_offset(snapshot);
24208        if start_offset == end_offset {
24209            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24210        } else {
24211            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24212        }
24213    }
24214}
24215
24216pub trait RowExt {
24217    fn as_f64(&self) -> f64;
24218
24219    fn next_row(&self) -> Self;
24220
24221    fn previous_row(&self) -> Self;
24222
24223    fn minus(&self, other: Self) -> u32;
24224}
24225
24226impl RowExt for DisplayRow {
24227    fn as_f64(&self) -> f64 {
24228        self.0 as _
24229    }
24230
24231    fn next_row(&self) -> Self {
24232        Self(self.0 + 1)
24233    }
24234
24235    fn previous_row(&self) -> Self {
24236        Self(self.0.saturating_sub(1))
24237    }
24238
24239    fn minus(&self, other: Self) -> u32 {
24240        self.0 - other.0
24241    }
24242}
24243
24244impl RowExt for MultiBufferRow {
24245    fn as_f64(&self) -> f64 {
24246        self.0 as _
24247    }
24248
24249    fn next_row(&self) -> Self {
24250        Self(self.0 + 1)
24251    }
24252
24253    fn previous_row(&self) -> Self {
24254        Self(self.0.saturating_sub(1))
24255    }
24256
24257    fn minus(&self, other: Self) -> u32 {
24258        self.0 - other.0
24259    }
24260}
24261
24262trait RowRangeExt {
24263    type Row;
24264
24265    fn len(&self) -> usize;
24266
24267    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24268}
24269
24270impl RowRangeExt for Range<MultiBufferRow> {
24271    type Row = MultiBufferRow;
24272
24273    fn len(&self) -> usize {
24274        (self.end.0 - self.start.0) as usize
24275    }
24276
24277    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24278        (self.start.0..self.end.0).map(MultiBufferRow)
24279    }
24280}
24281
24282impl RowRangeExt for Range<DisplayRow> {
24283    type Row = DisplayRow;
24284
24285    fn len(&self) -> usize {
24286        (self.end.0 - self.start.0) as usize
24287    }
24288
24289    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24290        (self.start.0..self.end.0).map(DisplayRow)
24291    }
24292}
24293
24294/// If select range has more than one line, we
24295/// just point the cursor to range.start.
24296fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24297    if range.start.row == range.end.row {
24298        range
24299    } else {
24300        range.start..range.start
24301    }
24302}
24303pub struct KillRing(ClipboardItem);
24304impl Global for KillRing {}
24305
24306const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24307
24308enum BreakpointPromptEditAction {
24309    Log,
24310    Condition,
24311    HitCondition,
24312}
24313
24314struct BreakpointPromptEditor {
24315    pub(crate) prompt: Entity<Editor>,
24316    editor: WeakEntity<Editor>,
24317    breakpoint_anchor: Anchor,
24318    breakpoint: Breakpoint,
24319    edit_action: BreakpointPromptEditAction,
24320    block_ids: HashSet<CustomBlockId>,
24321    editor_margins: Arc<Mutex<EditorMargins>>,
24322    _subscriptions: Vec<Subscription>,
24323}
24324
24325impl BreakpointPromptEditor {
24326    const MAX_LINES: u8 = 4;
24327
24328    fn new(
24329        editor: WeakEntity<Editor>,
24330        breakpoint_anchor: Anchor,
24331        breakpoint: Breakpoint,
24332        edit_action: BreakpointPromptEditAction,
24333        window: &mut Window,
24334        cx: &mut Context<Self>,
24335    ) -> Self {
24336        let base_text = match edit_action {
24337            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24338            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24339            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24340        }
24341        .map(|msg| msg.to_string())
24342        .unwrap_or_default();
24343
24344        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24345        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24346
24347        let prompt = cx.new(|cx| {
24348            let mut prompt = Editor::new(
24349                EditorMode::AutoHeight {
24350                    min_lines: 1,
24351                    max_lines: Some(Self::MAX_LINES as usize),
24352                },
24353                buffer,
24354                None,
24355                window,
24356                cx,
24357            );
24358            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24359            prompt.set_show_cursor_when_unfocused(false, cx);
24360            prompt.set_placeholder_text(
24361                match edit_action {
24362                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24363                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24364                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24365                },
24366                window,
24367                cx,
24368            );
24369
24370            prompt
24371        });
24372
24373        Self {
24374            prompt,
24375            editor,
24376            breakpoint_anchor,
24377            breakpoint,
24378            edit_action,
24379            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24380            block_ids: Default::default(),
24381            _subscriptions: vec![],
24382        }
24383    }
24384
24385    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24386        self.block_ids.extend(block_ids)
24387    }
24388
24389    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24390        if let Some(editor) = self.editor.upgrade() {
24391            let message = self
24392                .prompt
24393                .read(cx)
24394                .buffer
24395                .read(cx)
24396                .as_singleton()
24397                .expect("A multi buffer in breakpoint prompt isn't possible")
24398                .read(cx)
24399                .as_rope()
24400                .to_string();
24401
24402            editor.update(cx, |editor, cx| {
24403                editor.edit_breakpoint_at_anchor(
24404                    self.breakpoint_anchor,
24405                    self.breakpoint.clone(),
24406                    match self.edit_action {
24407                        BreakpointPromptEditAction::Log => {
24408                            BreakpointEditAction::EditLogMessage(message.into())
24409                        }
24410                        BreakpointPromptEditAction::Condition => {
24411                            BreakpointEditAction::EditCondition(message.into())
24412                        }
24413                        BreakpointPromptEditAction::HitCondition => {
24414                            BreakpointEditAction::EditHitCondition(message.into())
24415                        }
24416                    },
24417                    cx,
24418                );
24419
24420                editor.remove_blocks(self.block_ids.clone(), None, cx);
24421                cx.focus_self(window);
24422            });
24423        }
24424    }
24425
24426    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24427        self.editor
24428            .update(cx, |editor, cx| {
24429                editor.remove_blocks(self.block_ids.clone(), None, cx);
24430                window.focus(&editor.focus_handle);
24431            })
24432            .log_err();
24433    }
24434
24435    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24436        let settings = ThemeSettings::get_global(cx);
24437        let text_style = TextStyle {
24438            color: if self.prompt.read(cx).read_only(cx) {
24439                cx.theme().colors().text_disabled
24440            } else {
24441                cx.theme().colors().text
24442            },
24443            font_family: settings.buffer_font.family.clone(),
24444            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24445            font_size: settings.buffer_font_size(cx).into(),
24446            font_weight: settings.buffer_font.weight,
24447            line_height: relative(settings.buffer_line_height.value()),
24448            ..Default::default()
24449        };
24450        EditorElement::new(
24451            &self.prompt,
24452            EditorStyle {
24453                background: cx.theme().colors().editor_background,
24454                local_player: cx.theme().players().local(),
24455                text: text_style,
24456                ..Default::default()
24457            },
24458        )
24459    }
24460}
24461
24462impl Render for BreakpointPromptEditor {
24463    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24464        let editor_margins = *self.editor_margins.lock();
24465        let gutter_dimensions = editor_margins.gutter;
24466        h_flex()
24467            .key_context("Editor")
24468            .bg(cx.theme().colors().editor_background)
24469            .border_y_1()
24470            .border_color(cx.theme().status().info_border)
24471            .size_full()
24472            .py(window.line_height() / 2.5)
24473            .on_action(cx.listener(Self::confirm))
24474            .on_action(cx.listener(Self::cancel))
24475            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24476            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24477    }
24478}
24479
24480impl Focusable for BreakpointPromptEditor {
24481    fn focus_handle(&self, cx: &App) -> FocusHandle {
24482        self.prompt.focus_handle(cx)
24483    }
24484}
24485
24486fn all_edits_insertions_or_deletions(
24487    edits: &Vec<(Range<Anchor>, String)>,
24488    snapshot: &MultiBufferSnapshot,
24489) -> bool {
24490    let mut all_insertions = true;
24491    let mut all_deletions = true;
24492
24493    for (range, new_text) in edits.iter() {
24494        let range_is_empty = range.to_offset(snapshot).is_empty();
24495        let text_is_empty = new_text.is_empty();
24496
24497        if range_is_empty != text_is_empty {
24498            if range_is_empty {
24499                all_deletions = false;
24500            } else {
24501                all_insertions = false;
24502            }
24503        } else {
24504            return false;
24505        }
24506
24507        if !all_insertions && !all_deletions {
24508            return false;
24509        }
24510    }
24511    all_insertions || all_deletions
24512}
24513
24514struct MissingEditPredictionKeybindingTooltip;
24515
24516impl Render for MissingEditPredictionKeybindingTooltip {
24517    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24518        ui::tooltip_container(cx, |container, cx| {
24519            container
24520                .flex_shrink_0()
24521                .max_w_80()
24522                .min_h(rems_from_px(124.))
24523                .justify_between()
24524                .child(
24525                    v_flex()
24526                        .flex_1()
24527                        .text_ui_sm(cx)
24528                        .child(Label::new("Conflict with Accept Keybinding"))
24529                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24530                )
24531                .child(
24532                    h_flex()
24533                        .pb_1()
24534                        .gap_1()
24535                        .items_end()
24536                        .w_full()
24537                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24538                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24539                        }))
24540                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24541                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24542                        })),
24543                )
24544        })
24545    }
24546}
24547
24548#[derive(Debug, Clone, Copy, PartialEq)]
24549pub struct LineHighlight {
24550    pub background: Background,
24551    pub border: Option<gpui::Hsla>,
24552    pub include_gutter: bool,
24553    pub type_id: Option<TypeId>,
24554}
24555
24556struct LineManipulationResult {
24557    pub new_text: String,
24558    pub line_count_before: usize,
24559    pub line_count_after: usize,
24560}
24561
24562fn render_diff_hunk_controls(
24563    row: u32,
24564    status: &DiffHunkStatus,
24565    hunk_range: Range<Anchor>,
24566    is_created_file: bool,
24567    line_height: Pixels,
24568    editor: &Entity<Editor>,
24569    _window: &mut Window,
24570    cx: &mut App,
24571) -> AnyElement {
24572    h_flex()
24573        .h(line_height)
24574        .mr_1()
24575        .gap_1()
24576        .px_0p5()
24577        .pb_1()
24578        .border_x_1()
24579        .border_b_1()
24580        .border_color(cx.theme().colors().border_variant)
24581        .rounded_b_lg()
24582        .bg(cx.theme().colors().editor_background)
24583        .gap_1()
24584        .block_mouse_except_scroll()
24585        .shadow_md()
24586        .child(if status.has_secondary_hunk() {
24587            Button::new(("stage", row as u64), "Stage")
24588                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24589                .tooltip({
24590                    let focus_handle = editor.focus_handle(cx);
24591                    move |window, cx| {
24592                        Tooltip::for_action_in(
24593                            "Stage Hunk",
24594                            &::git::ToggleStaged,
24595                            &focus_handle,
24596                            window,
24597                            cx,
24598                        )
24599                    }
24600                })
24601                .on_click({
24602                    let editor = editor.clone();
24603                    move |_event, _window, cx| {
24604                        editor.update(cx, |editor, cx| {
24605                            editor.stage_or_unstage_diff_hunks(
24606                                true,
24607                                vec![hunk_range.start..hunk_range.start],
24608                                cx,
24609                            );
24610                        });
24611                    }
24612                })
24613        } else {
24614            Button::new(("unstage", row as u64), "Unstage")
24615                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24616                .tooltip({
24617                    let focus_handle = editor.focus_handle(cx);
24618                    move |window, cx| {
24619                        Tooltip::for_action_in(
24620                            "Unstage Hunk",
24621                            &::git::ToggleStaged,
24622                            &focus_handle,
24623                            window,
24624                            cx,
24625                        )
24626                    }
24627                })
24628                .on_click({
24629                    let editor = editor.clone();
24630                    move |_event, _window, cx| {
24631                        editor.update(cx, |editor, cx| {
24632                            editor.stage_or_unstage_diff_hunks(
24633                                false,
24634                                vec![hunk_range.start..hunk_range.start],
24635                                cx,
24636                            );
24637                        });
24638                    }
24639                })
24640        })
24641        .child(
24642            Button::new(("restore", row as u64), "Restore")
24643                .tooltip({
24644                    let focus_handle = editor.focus_handle(cx);
24645                    move |window, cx| {
24646                        Tooltip::for_action_in(
24647                            "Restore Hunk",
24648                            &::git::Restore,
24649                            &focus_handle,
24650                            window,
24651                            cx,
24652                        )
24653                    }
24654                })
24655                .on_click({
24656                    let editor = editor.clone();
24657                    move |_event, window, cx| {
24658                        editor.update(cx, |editor, cx| {
24659                            let snapshot = editor.snapshot(window, cx);
24660                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24661                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24662                        });
24663                    }
24664                })
24665                .disabled(is_created_file),
24666        )
24667        .when(
24668            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24669            |el| {
24670                el.child(
24671                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24672                        .shape(IconButtonShape::Square)
24673                        .icon_size(IconSize::Small)
24674                        // .disabled(!has_multiple_hunks)
24675                        .tooltip({
24676                            let focus_handle = editor.focus_handle(cx);
24677                            move |window, cx| {
24678                                Tooltip::for_action_in(
24679                                    "Next Hunk",
24680                                    &GoToHunk,
24681                                    &focus_handle,
24682                                    window,
24683                                    cx,
24684                                )
24685                            }
24686                        })
24687                        .on_click({
24688                            let editor = editor.clone();
24689                            move |_event, window, cx| {
24690                                editor.update(cx, |editor, cx| {
24691                                    let snapshot = editor.snapshot(window, cx);
24692                                    let position =
24693                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24694                                    editor.go_to_hunk_before_or_after_position(
24695                                        &snapshot,
24696                                        position,
24697                                        Direction::Next,
24698                                        window,
24699                                        cx,
24700                                    );
24701                                    editor.expand_selected_diff_hunks(cx);
24702                                });
24703                            }
24704                        }),
24705                )
24706                .child(
24707                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24708                        .shape(IconButtonShape::Square)
24709                        .icon_size(IconSize::Small)
24710                        // .disabled(!has_multiple_hunks)
24711                        .tooltip({
24712                            let focus_handle = editor.focus_handle(cx);
24713                            move |window, cx| {
24714                                Tooltip::for_action_in(
24715                                    "Previous Hunk",
24716                                    &GoToPreviousHunk,
24717                                    &focus_handle,
24718                                    window,
24719                                    cx,
24720                                )
24721                            }
24722                        })
24723                        .on_click({
24724                            let editor = editor.clone();
24725                            move |_event, window, cx| {
24726                                editor.update(cx, |editor, cx| {
24727                                    let snapshot = editor.snapshot(window, cx);
24728                                    let point =
24729                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24730                                    editor.go_to_hunk_before_or_after_position(
24731                                        &snapshot,
24732                                        point,
24733                                        Direction::Prev,
24734                                        window,
24735                                        cx,
24736                                    );
24737                                    editor.expand_selected_diff_hunks(cx);
24738                                });
24739                            }
24740                        }),
24741                )
24742            },
24743        )
24744        .into_any_element()
24745}
24746
24747pub fn multibuffer_context_lines(cx: &App) -> u32 {
24748    EditorSettings::try_get(cx)
24749        .map(|settings| settings.excerpt_context_lines)
24750        .unwrap_or(2)
24751        .min(32)
24752}