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.clear_inlay_hints(cx);
 5221                            return;
 5222                        }
 5223                    }
 5224                    None => return,
 5225                }
 5226            }
 5227            InlayHintRefreshReason::Toggle(enabled) => {
 5228                if self.inlay_hint_cache.toggle(enabled) {
 5229                    if enabled {
 5230                        (InvalidationStrategy::RefreshRequested, None)
 5231                    } else {
 5232                        self.clear_inlay_hints(cx);
 5233                        return;
 5234                    }
 5235                } else {
 5236                    return;
 5237                }
 5238            }
 5239            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5240                match self.inlay_hint_cache.update_settings(
 5241                    &self.buffer,
 5242                    new_settings,
 5243                    self.visible_inlay_hints(cx).cloned().collect::<Vec<_>>(),
 5244                    cx,
 5245                ) {
 5246                    ControlFlow::Break(Some(InlaySplice {
 5247                        to_remove,
 5248                        to_insert,
 5249                    })) => {
 5250                        self.splice_inlays(&to_remove, to_insert, cx);
 5251                        return;
 5252                    }
 5253                    ControlFlow::Break(None) => return,
 5254                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5255                }
 5256            }
 5257            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5258                if let Some(InlaySplice {
 5259                    to_remove,
 5260                    to_insert,
 5261                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5262                {
 5263                    self.splice_inlays(&to_remove, to_insert, cx);
 5264                }
 5265                self.display_map.update(cx, |display_map, _| {
 5266                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5267                });
 5268                return;
 5269            }
 5270            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5271            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5272                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5273            }
 5274            InlayHintRefreshReason::RefreshRequested => {
 5275                (InvalidationStrategy::RefreshRequested, None)
 5276            }
 5277        };
 5278
 5279        if let Some(InlaySplice {
 5280            to_remove,
 5281            to_insert,
 5282        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5283            reason_description,
 5284            self.visible_excerpts(required_languages.as_ref(), cx),
 5285            invalidate_cache,
 5286            ignore_debounce,
 5287            cx,
 5288        ) {
 5289            self.splice_inlays(&to_remove, to_insert, cx);
 5290        }
 5291    }
 5292
 5293    pub fn clear_inlay_hints(&self, cx: &mut Context<Editor>) {
 5294        self.splice_inlays(
 5295            &self
 5296                .visible_inlay_hints(cx)
 5297                .map(|inlay| inlay.id)
 5298                .collect::<Vec<_>>(),
 5299            Vec::new(),
 5300            cx,
 5301        );
 5302    }
 5303
 5304    fn visible_inlay_hints<'a>(
 5305        &'a self,
 5306        cx: &'a Context<Editor>,
 5307    ) -> impl Iterator<Item = &'a Inlay> {
 5308        self.display_map
 5309            .read(cx)
 5310            .current_inlays()
 5311            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5312    }
 5313
 5314    pub fn visible_excerpts(
 5315        &self,
 5316        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5317        cx: &mut Context<Editor>,
 5318    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5319        let Some(project) = self.project() else {
 5320            return HashMap::default();
 5321        };
 5322        let project = project.read(cx);
 5323        let multi_buffer = self.buffer().read(cx);
 5324        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5325        let multi_buffer_visible_start = self
 5326            .scroll_manager
 5327            .anchor()
 5328            .anchor
 5329            .to_point(&multi_buffer_snapshot);
 5330        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5331            multi_buffer_visible_start
 5332                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5333            Bias::Left,
 5334        );
 5335        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5336        multi_buffer_snapshot
 5337            .range_to_buffer_ranges(multi_buffer_visible_range)
 5338            .into_iter()
 5339            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5340            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5341                let buffer_file = project::File::from_dyn(buffer.file())?;
 5342                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5343                let worktree_entry = buffer_worktree
 5344                    .read(cx)
 5345                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5346                if worktree_entry.is_ignored {
 5347                    return None;
 5348                }
 5349
 5350                let language = buffer.language()?;
 5351                if let Some(restrict_to_languages) = restrict_to_languages
 5352                    && !restrict_to_languages.contains(language)
 5353                {
 5354                    return None;
 5355                }
 5356                Some((
 5357                    excerpt_id,
 5358                    (
 5359                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5360                        buffer.version().clone(),
 5361                        excerpt_visible_range,
 5362                    ),
 5363                ))
 5364            })
 5365            .collect()
 5366    }
 5367
 5368    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5369        TextLayoutDetails {
 5370            text_system: window.text_system().clone(),
 5371            editor_style: self.style.clone().unwrap(),
 5372            rem_size: window.rem_size(),
 5373            scroll_anchor: self.scroll_manager.anchor(),
 5374            visible_rows: self.visible_line_count(),
 5375            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5376        }
 5377    }
 5378
 5379    pub fn splice_inlays(
 5380        &self,
 5381        to_remove: &[InlayId],
 5382        to_insert: Vec<Inlay>,
 5383        cx: &mut Context<Self>,
 5384    ) {
 5385        self.display_map.update(cx, |display_map, cx| {
 5386            display_map.splice_inlays(to_remove, to_insert, cx)
 5387        });
 5388        cx.notify();
 5389    }
 5390
 5391    fn trigger_on_type_formatting(
 5392        &self,
 5393        input: String,
 5394        window: &mut Window,
 5395        cx: &mut Context<Self>,
 5396    ) -> Option<Task<Result<()>>> {
 5397        if input.len() != 1 {
 5398            return None;
 5399        }
 5400
 5401        let project = self.project()?;
 5402        let position = self.selections.newest_anchor().head();
 5403        let (buffer, buffer_position) = self
 5404            .buffer
 5405            .read(cx)
 5406            .text_anchor_for_position(position, cx)?;
 5407
 5408        let settings = language_settings::language_settings(
 5409            buffer
 5410                .read(cx)
 5411                .language_at(buffer_position)
 5412                .map(|l| l.name()),
 5413            buffer.read(cx).file(),
 5414            cx,
 5415        );
 5416        if !settings.use_on_type_format {
 5417            return None;
 5418        }
 5419
 5420        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5421        // hence we do LSP request & edit on host side only — add formats to host's history.
 5422        let push_to_lsp_host_history = true;
 5423        // If this is not the host, append its history with new edits.
 5424        let push_to_client_history = project.read(cx).is_via_collab();
 5425
 5426        let on_type_formatting = project.update(cx, |project, cx| {
 5427            project.on_type_format(
 5428                buffer.clone(),
 5429                buffer_position,
 5430                input,
 5431                push_to_lsp_host_history,
 5432                cx,
 5433            )
 5434        });
 5435        Some(cx.spawn_in(window, async move |editor, cx| {
 5436            if let Some(transaction) = on_type_formatting.await? {
 5437                if push_to_client_history {
 5438                    buffer
 5439                        .update(cx, |buffer, _| {
 5440                            buffer.push_transaction(transaction, Instant::now());
 5441                            buffer.finalize_last_transaction();
 5442                        })
 5443                        .ok();
 5444                }
 5445                editor.update(cx, |editor, cx| {
 5446                    editor.refresh_document_highlights(cx);
 5447                })?;
 5448            }
 5449            Ok(())
 5450        }))
 5451    }
 5452
 5453    pub fn show_word_completions(
 5454        &mut self,
 5455        _: &ShowWordCompletions,
 5456        window: &mut Window,
 5457        cx: &mut Context<Self>,
 5458    ) {
 5459        self.open_or_update_completions_menu(
 5460            Some(CompletionsMenuSource::Words {
 5461                ignore_threshold: true,
 5462            }),
 5463            None,
 5464            window,
 5465            cx,
 5466        );
 5467    }
 5468
 5469    pub fn show_completions(
 5470        &mut self,
 5471        options: &ShowCompletions,
 5472        window: &mut Window,
 5473        cx: &mut Context<Self>,
 5474    ) {
 5475        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5476    }
 5477
 5478    fn open_or_update_completions_menu(
 5479        &mut self,
 5480        requested_source: Option<CompletionsMenuSource>,
 5481        trigger: Option<&str>,
 5482        window: &mut Window,
 5483        cx: &mut Context<Self>,
 5484    ) {
 5485        if self.pending_rename.is_some() {
 5486            return;
 5487        }
 5488
 5489        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5490
 5491        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5492        // inserted and selected. To handle that case, the start of the selection is used so that
 5493        // the menu starts with all choices.
 5494        let position = self
 5495            .selections
 5496            .newest_anchor()
 5497            .start
 5498            .bias_right(&multibuffer_snapshot);
 5499        if position.diff_base_anchor.is_some() {
 5500            return;
 5501        }
 5502        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5503        let Some(buffer) = buffer_position
 5504            .buffer_id
 5505            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5506        else {
 5507            return;
 5508        };
 5509        let buffer_snapshot = buffer.read(cx).snapshot();
 5510
 5511        let query: Option<Arc<String>> =
 5512            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5513                .map(|query| query.into());
 5514
 5515        drop(multibuffer_snapshot);
 5516
 5517        // Hide the current completions menu when query is empty. Without this, cached
 5518        // completions from before the trigger char may be reused (#32774).
 5519        if query.is_none() {
 5520            let menu_is_open = matches!(
 5521                self.context_menu.borrow().as_ref(),
 5522                Some(CodeContextMenu::Completions(_))
 5523            );
 5524            if menu_is_open {
 5525                self.hide_context_menu(window, cx);
 5526            }
 5527        }
 5528
 5529        let mut ignore_word_threshold = false;
 5530        let provider = match requested_source {
 5531            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5532            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5533                ignore_word_threshold = ignore_threshold;
 5534                None
 5535            }
 5536            Some(CompletionsMenuSource::SnippetChoices) => {
 5537                log::error!("bug: SnippetChoices requested_source is not handled");
 5538                None
 5539            }
 5540        };
 5541
 5542        let sort_completions = provider
 5543            .as_ref()
 5544            .is_some_and(|provider| provider.sort_completions());
 5545
 5546        let filter_completions = provider
 5547            .as_ref()
 5548            .is_none_or(|provider| provider.filter_completions());
 5549
 5550        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5551            if filter_completions {
 5552                menu.filter(query.clone(), provider.clone(), window, cx);
 5553            }
 5554            // When `is_incomplete` is false, no need to re-query completions when the current query
 5555            // is a suffix of the initial query.
 5556            if !menu.is_incomplete {
 5557                // If the new query is a suffix of the old query (typing more characters) and
 5558                // the previous result was complete, the existing completions can be filtered.
 5559                //
 5560                // Note that this is always true for snippet completions.
 5561                let query_matches = match (&menu.initial_query, &query) {
 5562                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5563                    (None, _) => true,
 5564                    _ => false,
 5565                };
 5566                if query_matches {
 5567                    let position_matches = if menu.initial_position == position {
 5568                        true
 5569                    } else {
 5570                        let snapshot = self.buffer.read(cx).read(cx);
 5571                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5572                    };
 5573                    if position_matches {
 5574                        return;
 5575                    }
 5576                }
 5577            }
 5578        };
 5579
 5580        let trigger_kind = match trigger {
 5581            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5582                CompletionTriggerKind::TRIGGER_CHARACTER
 5583            }
 5584            _ => CompletionTriggerKind::INVOKED,
 5585        };
 5586        let completion_context = CompletionContext {
 5587            trigger_character: trigger.and_then(|trigger| {
 5588                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5589                    Some(String::from(trigger))
 5590                } else {
 5591                    None
 5592                }
 5593            }),
 5594            trigger_kind,
 5595        };
 5596
 5597        let Anchor {
 5598            excerpt_id: buffer_excerpt_id,
 5599            text_anchor: buffer_position,
 5600            ..
 5601        } = buffer_position;
 5602
 5603        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5604            buffer_snapshot.surrounding_word(buffer_position, None)
 5605        {
 5606            let word_to_exclude = buffer_snapshot
 5607                .text_for_range(word_range.clone())
 5608                .collect::<String>();
 5609            (
 5610                buffer_snapshot.anchor_before(word_range.start)
 5611                    ..buffer_snapshot.anchor_after(buffer_position),
 5612                Some(word_to_exclude),
 5613            )
 5614        } else {
 5615            (buffer_position..buffer_position, None)
 5616        };
 5617
 5618        let language = buffer_snapshot
 5619            .language_at(buffer_position)
 5620            .map(|language| language.name());
 5621
 5622        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5623            .completions
 5624            .clone();
 5625
 5626        let show_completion_documentation = buffer_snapshot
 5627            .settings_at(buffer_position, cx)
 5628            .show_completion_documentation;
 5629
 5630        // The document can be large, so stay in reasonable bounds when searching for words,
 5631        // otherwise completion pop-up might be slow to appear.
 5632        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5633        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5634        let min_word_search = buffer_snapshot.clip_point(
 5635            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5636            Bias::Left,
 5637        );
 5638        let max_word_search = buffer_snapshot.clip_point(
 5639            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5640            Bias::Right,
 5641        );
 5642        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5643            ..buffer_snapshot.point_to_offset(max_word_search);
 5644
 5645        let skip_digits = query
 5646            .as_ref()
 5647            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5648
 5649        let omit_word_completions = !self.word_completions_enabled
 5650            || (!ignore_word_threshold
 5651                && match &query {
 5652                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5653                    None => completion_settings.words_min_length != 0,
 5654                });
 5655
 5656        let (mut words, provider_responses) = match &provider {
 5657            Some(provider) => {
 5658                let provider_responses = provider.completions(
 5659                    buffer_excerpt_id,
 5660                    &buffer,
 5661                    buffer_position,
 5662                    completion_context,
 5663                    window,
 5664                    cx,
 5665                );
 5666
 5667                let words = match (omit_word_completions, completion_settings.words) {
 5668                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5669                        Task::ready(BTreeMap::default())
 5670                    }
 5671                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5672                        .background_spawn(async move {
 5673                            buffer_snapshot.words_in_range(WordsQuery {
 5674                                fuzzy_contents: None,
 5675                                range: word_search_range,
 5676                                skip_digits,
 5677                            })
 5678                        }),
 5679                };
 5680
 5681                (words, provider_responses)
 5682            }
 5683            None => {
 5684                let words = if omit_word_completions {
 5685                    Task::ready(BTreeMap::default())
 5686                } else {
 5687                    cx.background_spawn(async move {
 5688                        buffer_snapshot.words_in_range(WordsQuery {
 5689                            fuzzy_contents: None,
 5690                            range: word_search_range,
 5691                            skip_digits,
 5692                        })
 5693                    })
 5694                };
 5695                (words, Task::ready(Ok(Vec::new())))
 5696            }
 5697        };
 5698
 5699        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5700
 5701        let id = post_inc(&mut self.next_completion_id);
 5702        let task = cx.spawn_in(window, async move |editor, cx| {
 5703            let Ok(()) = editor.update(cx, |this, _| {
 5704                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5705            }) else {
 5706                return;
 5707            };
 5708
 5709            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5710            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5711            let mut completions = Vec::new();
 5712            let mut is_incomplete = false;
 5713            let mut display_options: Option<CompletionDisplayOptions> = None;
 5714            if let Some(provider_responses) = provider_responses.await.log_err()
 5715                && !provider_responses.is_empty()
 5716            {
 5717                for response in provider_responses {
 5718                    completions.extend(response.completions);
 5719                    is_incomplete = is_incomplete || response.is_incomplete;
 5720                    match display_options.as_mut() {
 5721                        None => {
 5722                            display_options = Some(response.display_options);
 5723                        }
 5724                        Some(options) => options.merge(&response.display_options),
 5725                    }
 5726                }
 5727                if completion_settings.words == WordsCompletionMode::Fallback {
 5728                    words = Task::ready(BTreeMap::default());
 5729                }
 5730            }
 5731            let display_options = display_options.unwrap_or_default();
 5732
 5733            let mut words = words.await;
 5734            if let Some(word_to_exclude) = &word_to_exclude {
 5735                words.remove(word_to_exclude);
 5736            }
 5737            for lsp_completion in &completions {
 5738                words.remove(&lsp_completion.new_text);
 5739            }
 5740            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5741                replace_range: word_replace_range.clone(),
 5742                new_text: word.clone(),
 5743                label: CodeLabel::plain(word, None),
 5744                icon_path: None,
 5745                documentation: None,
 5746                source: CompletionSource::BufferWord {
 5747                    word_range,
 5748                    resolved: false,
 5749                },
 5750                insert_text_mode: Some(InsertTextMode::AS_IS),
 5751                confirm: None,
 5752            }));
 5753
 5754            let menu = if completions.is_empty() {
 5755                None
 5756            } else {
 5757                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5758                    let languages = editor
 5759                        .workspace
 5760                        .as_ref()
 5761                        .and_then(|(workspace, _)| workspace.upgrade())
 5762                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5763                    let menu = CompletionsMenu::new(
 5764                        id,
 5765                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5766                        sort_completions,
 5767                        show_completion_documentation,
 5768                        position,
 5769                        query.clone(),
 5770                        is_incomplete,
 5771                        buffer.clone(),
 5772                        completions.into(),
 5773                        display_options,
 5774                        snippet_sort_order,
 5775                        languages,
 5776                        language,
 5777                        cx,
 5778                    );
 5779
 5780                    let query = if filter_completions { query } else { None };
 5781                    let matches_task = if let Some(query) = query {
 5782                        menu.do_async_filtering(query, cx)
 5783                    } else {
 5784                        Task::ready(menu.unfiltered_matches())
 5785                    };
 5786                    (menu, matches_task)
 5787                }) else {
 5788                    return;
 5789                };
 5790
 5791                let matches = matches_task.await;
 5792
 5793                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5794                    // Newer menu already set, so exit.
 5795                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5796                        editor.context_menu.borrow().as_ref()
 5797                        && prev_menu.id > id
 5798                    {
 5799                        return;
 5800                    };
 5801
 5802                    // Only valid to take prev_menu because it the new menu is immediately set
 5803                    // below, or the menu is hidden.
 5804                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5805                        editor.context_menu.borrow_mut().take()
 5806                    {
 5807                        let position_matches =
 5808                            if prev_menu.initial_position == menu.initial_position {
 5809                                true
 5810                            } else {
 5811                                let snapshot = editor.buffer.read(cx).read(cx);
 5812                                prev_menu.initial_position.to_offset(&snapshot)
 5813                                    == menu.initial_position.to_offset(&snapshot)
 5814                            };
 5815                        if position_matches {
 5816                            // Preserve markdown cache before `set_filter_results` because it will
 5817                            // try to populate the documentation cache.
 5818                            menu.preserve_markdown_cache(prev_menu);
 5819                        }
 5820                    };
 5821
 5822                    menu.set_filter_results(matches, provider, window, cx);
 5823                }) else {
 5824                    return;
 5825                };
 5826
 5827                menu.visible().then_some(menu)
 5828            };
 5829
 5830            editor
 5831                .update_in(cx, |editor, window, cx| {
 5832                    if editor.focus_handle.is_focused(window)
 5833                        && let Some(menu) = menu
 5834                    {
 5835                        *editor.context_menu.borrow_mut() =
 5836                            Some(CodeContextMenu::Completions(menu));
 5837
 5838                        crate::hover_popover::hide_hover(editor, cx);
 5839                        if editor.show_edit_predictions_in_menu() {
 5840                            editor.update_visible_edit_prediction(window, cx);
 5841                        } else {
 5842                            editor.discard_edit_prediction(false, cx);
 5843                        }
 5844
 5845                        cx.notify();
 5846                        return;
 5847                    }
 5848
 5849                    if editor.completion_tasks.len() <= 1 {
 5850                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5851                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5852                        // If it was already hidden and we don't show edit predictions in the menu,
 5853                        // we should also show the edit prediction when available.
 5854                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5855                            editor.update_visible_edit_prediction(window, cx);
 5856                        }
 5857                    }
 5858                })
 5859                .ok();
 5860        });
 5861
 5862        self.completion_tasks.push((id, task));
 5863    }
 5864
 5865    #[cfg(feature = "test-support")]
 5866    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5867        let menu = self.context_menu.borrow();
 5868        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5869            let completions = menu.completions.borrow();
 5870            Some(completions.to_vec())
 5871        } else {
 5872            None
 5873        }
 5874    }
 5875
 5876    pub fn with_completions_menu_matching_id<R>(
 5877        &self,
 5878        id: CompletionId,
 5879        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5880    ) -> R {
 5881        let mut context_menu = self.context_menu.borrow_mut();
 5882        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5883            return f(None);
 5884        };
 5885        if completions_menu.id != id {
 5886            return f(None);
 5887        }
 5888        f(Some(completions_menu))
 5889    }
 5890
 5891    pub fn confirm_completion(
 5892        &mut self,
 5893        action: &ConfirmCompletion,
 5894        window: &mut Window,
 5895        cx: &mut Context<Self>,
 5896    ) -> Option<Task<Result<()>>> {
 5897        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5898        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5899    }
 5900
 5901    pub fn confirm_completion_insert(
 5902        &mut self,
 5903        _: &ConfirmCompletionInsert,
 5904        window: &mut Window,
 5905        cx: &mut Context<Self>,
 5906    ) -> Option<Task<Result<()>>> {
 5907        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5908        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5909    }
 5910
 5911    pub fn confirm_completion_replace(
 5912        &mut self,
 5913        _: &ConfirmCompletionReplace,
 5914        window: &mut Window,
 5915        cx: &mut Context<Self>,
 5916    ) -> Option<Task<Result<()>>> {
 5917        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5918        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5919    }
 5920
 5921    pub fn compose_completion(
 5922        &mut self,
 5923        action: &ComposeCompletion,
 5924        window: &mut Window,
 5925        cx: &mut Context<Self>,
 5926    ) -> Option<Task<Result<()>>> {
 5927        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5928        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5929    }
 5930
 5931    fn do_completion(
 5932        &mut self,
 5933        item_ix: Option<usize>,
 5934        intent: CompletionIntent,
 5935        window: &mut Window,
 5936        cx: &mut Context<Editor>,
 5937    ) -> Option<Task<Result<()>>> {
 5938        use language::ToOffset as _;
 5939
 5940        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5941        else {
 5942            return None;
 5943        };
 5944
 5945        let candidate_id = {
 5946            let entries = completions_menu.entries.borrow();
 5947            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5948            if self.show_edit_predictions_in_menu() {
 5949                self.discard_edit_prediction(true, cx);
 5950            }
 5951            mat.candidate_id
 5952        };
 5953
 5954        let completion = completions_menu
 5955            .completions
 5956            .borrow()
 5957            .get(candidate_id)?
 5958            .clone();
 5959        cx.stop_propagation();
 5960
 5961        let buffer_handle = completions_menu.buffer.clone();
 5962
 5963        let CompletionEdit {
 5964            new_text,
 5965            snippet,
 5966            replace_range,
 5967        } = process_completion_for_edit(
 5968            &completion,
 5969            intent,
 5970            &buffer_handle,
 5971            &completions_menu.initial_position.text_anchor,
 5972            cx,
 5973        );
 5974
 5975        let buffer = buffer_handle.read(cx);
 5976        let snapshot = self.buffer.read(cx).snapshot(cx);
 5977        let newest_anchor = self.selections.newest_anchor();
 5978        let replace_range_multibuffer = {
 5979            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5980            let multibuffer_anchor = snapshot
 5981                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5982                .unwrap()
 5983                ..snapshot
 5984                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5985                    .unwrap();
 5986            multibuffer_anchor.start.to_offset(&snapshot)
 5987                ..multibuffer_anchor.end.to_offset(&snapshot)
 5988        };
 5989        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5990            return None;
 5991        }
 5992
 5993        let old_text = buffer
 5994            .text_for_range(replace_range.clone())
 5995            .collect::<String>();
 5996        let lookbehind = newest_anchor
 5997            .start
 5998            .text_anchor
 5999            .to_offset(buffer)
 6000            .saturating_sub(replace_range.start);
 6001        let lookahead = replace_range
 6002            .end
 6003            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6004        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6005        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6006
 6007        let selections = self.selections.all::<usize>(cx);
 6008        let mut ranges = Vec::new();
 6009        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6010
 6011        for selection in &selections {
 6012            let range = if selection.id == newest_anchor.id {
 6013                replace_range_multibuffer.clone()
 6014            } else {
 6015                let mut range = selection.range();
 6016
 6017                // if prefix is present, don't duplicate it
 6018                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6019                    range.start = range.start.saturating_sub(lookbehind);
 6020
 6021                    // if suffix is also present, mimic the newest cursor and replace it
 6022                    if selection.id != newest_anchor.id
 6023                        && snapshot.contains_str_at(range.end, suffix)
 6024                    {
 6025                        range.end += lookahead;
 6026                    }
 6027                }
 6028                range
 6029            };
 6030
 6031            ranges.push(range.clone());
 6032
 6033            if !self.linked_edit_ranges.is_empty() {
 6034                let start_anchor = snapshot.anchor_before(range.start);
 6035                let end_anchor = snapshot.anchor_after(range.end);
 6036                if let Some(ranges) = self
 6037                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6038                {
 6039                    for (buffer, edits) in ranges {
 6040                        linked_edits
 6041                            .entry(buffer.clone())
 6042                            .or_default()
 6043                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6044                    }
 6045                }
 6046            }
 6047        }
 6048
 6049        let common_prefix_len = old_text
 6050            .chars()
 6051            .zip(new_text.chars())
 6052            .take_while(|(a, b)| a == b)
 6053            .map(|(a, _)| a.len_utf8())
 6054            .sum::<usize>();
 6055
 6056        cx.emit(EditorEvent::InputHandled {
 6057            utf16_range_to_replace: None,
 6058            text: new_text[common_prefix_len..].into(),
 6059        });
 6060
 6061        self.transact(window, cx, |editor, window, cx| {
 6062            if let Some(mut snippet) = snippet {
 6063                snippet.text = new_text.to_string();
 6064                editor
 6065                    .insert_snippet(&ranges, snippet, window, cx)
 6066                    .log_err();
 6067            } else {
 6068                editor.buffer.update(cx, |multi_buffer, cx| {
 6069                    let auto_indent = match completion.insert_text_mode {
 6070                        Some(InsertTextMode::AS_IS) => None,
 6071                        _ => editor.autoindent_mode.clone(),
 6072                    };
 6073                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6074                    multi_buffer.edit(edits, auto_indent, cx);
 6075                });
 6076            }
 6077            for (buffer, edits) in linked_edits {
 6078                buffer.update(cx, |buffer, cx| {
 6079                    let snapshot = buffer.snapshot();
 6080                    let edits = edits
 6081                        .into_iter()
 6082                        .map(|(range, text)| {
 6083                            use text::ToPoint as TP;
 6084                            let end_point = TP::to_point(&range.end, &snapshot);
 6085                            let start_point = TP::to_point(&range.start, &snapshot);
 6086                            (start_point..end_point, text)
 6087                        })
 6088                        .sorted_by_key(|(range, _)| range.start);
 6089                    buffer.edit(edits, None, cx);
 6090                })
 6091            }
 6092
 6093            editor.refresh_edit_prediction(true, false, window, cx);
 6094        });
 6095        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6096
 6097        let show_new_completions_on_confirm = completion
 6098            .confirm
 6099            .as_ref()
 6100            .is_some_and(|confirm| confirm(intent, window, cx));
 6101        if show_new_completions_on_confirm {
 6102            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6103        }
 6104
 6105        let provider = self.completion_provider.as_ref()?;
 6106        drop(completion);
 6107        let apply_edits = provider.apply_additional_edits_for_completion(
 6108            buffer_handle,
 6109            completions_menu.completions.clone(),
 6110            candidate_id,
 6111            true,
 6112            cx,
 6113        );
 6114
 6115        let editor_settings = EditorSettings::get_global(cx);
 6116        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6117            // After the code completion is finished, users often want to know what signatures are needed.
 6118            // so we should automatically call signature_help
 6119            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6120        }
 6121
 6122        Some(cx.foreground_executor().spawn(async move {
 6123            apply_edits.await?;
 6124            Ok(())
 6125        }))
 6126    }
 6127
 6128    pub fn toggle_code_actions(
 6129        &mut self,
 6130        action: &ToggleCodeActions,
 6131        window: &mut Window,
 6132        cx: &mut Context<Self>,
 6133    ) {
 6134        let quick_launch = action.quick_launch;
 6135        let mut context_menu = self.context_menu.borrow_mut();
 6136        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6137            if code_actions.deployed_from == action.deployed_from {
 6138                // Toggle if we're selecting the same one
 6139                *context_menu = None;
 6140                cx.notify();
 6141                return;
 6142            } else {
 6143                // Otherwise, clear it and start a new one
 6144                *context_menu = None;
 6145                cx.notify();
 6146            }
 6147        }
 6148        drop(context_menu);
 6149        let snapshot = self.snapshot(window, cx);
 6150        let deployed_from = action.deployed_from.clone();
 6151        let action = action.clone();
 6152        self.completion_tasks.clear();
 6153        self.discard_edit_prediction(false, cx);
 6154
 6155        let multibuffer_point = match &action.deployed_from {
 6156            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6157                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6158            }
 6159            _ => self.selections.newest::<Point>(cx).head(),
 6160        };
 6161        let Some((buffer, buffer_row)) = snapshot
 6162            .buffer_snapshot()
 6163            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6164            .and_then(|(buffer_snapshot, range)| {
 6165                self.buffer()
 6166                    .read(cx)
 6167                    .buffer(buffer_snapshot.remote_id())
 6168                    .map(|buffer| (buffer, range.start.row))
 6169            })
 6170        else {
 6171            return;
 6172        };
 6173        let buffer_id = buffer.read(cx).remote_id();
 6174        let tasks = self
 6175            .tasks
 6176            .get(&(buffer_id, buffer_row))
 6177            .map(|t| Arc::new(t.to_owned()));
 6178
 6179        if !self.focus_handle.is_focused(window) {
 6180            return;
 6181        }
 6182        let project = self.project.clone();
 6183
 6184        let code_actions_task = match deployed_from {
 6185            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6186            _ => self.code_actions(buffer_row, window, cx),
 6187        };
 6188
 6189        let runnable_task = match deployed_from {
 6190            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6191            _ => {
 6192                let mut task_context_task = Task::ready(None);
 6193                if let Some(tasks) = &tasks
 6194                    && let Some(project) = project
 6195                {
 6196                    task_context_task =
 6197                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6198                }
 6199
 6200                cx.spawn_in(window, {
 6201                    let buffer = buffer.clone();
 6202                    async move |editor, cx| {
 6203                        let task_context = task_context_task.await;
 6204
 6205                        let resolved_tasks =
 6206                            tasks
 6207                                .zip(task_context.clone())
 6208                                .map(|(tasks, task_context)| ResolvedTasks {
 6209                                    templates: tasks.resolve(&task_context).collect(),
 6210                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6211                                        multibuffer_point.row,
 6212                                        tasks.column,
 6213                                    )),
 6214                                });
 6215                        let debug_scenarios = editor
 6216                            .update(cx, |editor, cx| {
 6217                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6218                            })?
 6219                            .await;
 6220                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6221                    }
 6222                })
 6223            }
 6224        };
 6225
 6226        cx.spawn_in(window, async move |editor, cx| {
 6227            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6228            let code_actions = code_actions_task.await;
 6229            let spawn_straight_away = quick_launch
 6230                && resolved_tasks
 6231                    .as_ref()
 6232                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6233                && code_actions
 6234                    .as_ref()
 6235                    .is_none_or(|actions| actions.is_empty())
 6236                && debug_scenarios.is_empty();
 6237
 6238            editor.update_in(cx, |editor, window, cx| {
 6239                crate::hover_popover::hide_hover(editor, cx);
 6240                let actions = CodeActionContents::new(
 6241                    resolved_tasks,
 6242                    code_actions,
 6243                    debug_scenarios,
 6244                    task_context.unwrap_or_default(),
 6245                );
 6246
 6247                // Don't show the menu if there are no actions available
 6248                if actions.is_empty() {
 6249                    cx.notify();
 6250                    return Task::ready(Ok(()));
 6251                }
 6252
 6253                *editor.context_menu.borrow_mut() =
 6254                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6255                        buffer,
 6256                        actions,
 6257                        selected_item: Default::default(),
 6258                        scroll_handle: UniformListScrollHandle::default(),
 6259                        deployed_from,
 6260                    }));
 6261                cx.notify();
 6262                if spawn_straight_away
 6263                    && let Some(task) = editor.confirm_code_action(
 6264                        &ConfirmCodeAction { item_ix: Some(0) },
 6265                        window,
 6266                        cx,
 6267                    )
 6268                {
 6269                    return task;
 6270                }
 6271
 6272                Task::ready(Ok(()))
 6273            })
 6274        })
 6275        .detach_and_log_err(cx);
 6276    }
 6277
 6278    fn debug_scenarios(
 6279        &mut self,
 6280        resolved_tasks: &Option<ResolvedTasks>,
 6281        buffer: &Entity<Buffer>,
 6282        cx: &mut App,
 6283    ) -> Task<Vec<task::DebugScenario>> {
 6284        maybe!({
 6285            let project = self.project()?;
 6286            let dap_store = project.read(cx).dap_store();
 6287            let mut scenarios = vec![];
 6288            let resolved_tasks = resolved_tasks.as_ref()?;
 6289            let buffer = buffer.read(cx);
 6290            let language = buffer.language()?;
 6291            let file = buffer.file();
 6292            let debug_adapter = language_settings(language.name().into(), file, cx)
 6293                .debuggers
 6294                .first()
 6295                .map(SharedString::from)
 6296                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6297
 6298            dap_store.update(cx, |dap_store, cx| {
 6299                for (_, task) in &resolved_tasks.templates {
 6300                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6301                        task.original_task().clone(),
 6302                        debug_adapter.clone().into(),
 6303                        task.display_label().to_owned().into(),
 6304                        cx,
 6305                    );
 6306                    scenarios.push(maybe_scenario);
 6307                }
 6308            });
 6309            Some(cx.background_spawn(async move {
 6310                futures::future::join_all(scenarios)
 6311                    .await
 6312                    .into_iter()
 6313                    .flatten()
 6314                    .collect::<Vec<_>>()
 6315            }))
 6316        })
 6317        .unwrap_or_else(|| Task::ready(vec![]))
 6318    }
 6319
 6320    fn code_actions(
 6321        &mut self,
 6322        buffer_row: u32,
 6323        window: &mut Window,
 6324        cx: &mut Context<Self>,
 6325    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6326        let mut task = self.code_actions_task.take();
 6327        cx.spawn_in(window, async move |editor, cx| {
 6328            while let Some(prev_task) = task {
 6329                prev_task.await.log_err();
 6330                task = editor
 6331                    .update(cx, |this, _| this.code_actions_task.take())
 6332                    .ok()?;
 6333            }
 6334
 6335            editor
 6336                .update(cx, |editor, cx| {
 6337                    editor
 6338                        .available_code_actions
 6339                        .clone()
 6340                        .and_then(|(location, code_actions)| {
 6341                            let snapshot = location.buffer.read(cx).snapshot();
 6342                            let point_range = location.range.to_point(&snapshot);
 6343                            let point_range = point_range.start.row..=point_range.end.row;
 6344                            if point_range.contains(&buffer_row) {
 6345                                Some(code_actions)
 6346                            } else {
 6347                                None
 6348                            }
 6349                        })
 6350                })
 6351                .ok()
 6352                .flatten()
 6353        })
 6354    }
 6355
 6356    pub fn confirm_code_action(
 6357        &mut self,
 6358        action: &ConfirmCodeAction,
 6359        window: &mut Window,
 6360        cx: &mut Context<Self>,
 6361    ) -> Option<Task<Result<()>>> {
 6362        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6363
 6364        let actions_menu =
 6365            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6366                menu
 6367            } else {
 6368                return None;
 6369            };
 6370
 6371        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6372        let action = actions_menu.actions.get(action_ix)?;
 6373        let title = action.label();
 6374        let buffer = actions_menu.buffer;
 6375        let workspace = self.workspace()?;
 6376
 6377        match action {
 6378            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6379                workspace.update(cx, |workspace, cx| {
 6380                    workspace.schedule_resolved_task(
 6381                        task_source_kind,
 6382                        resolved_task,
 6383                        false,
 6384                        window,
 6385                        cx,
 6386                    );
 6387
 6388                    Some(Task::ready(Ok(())))
 6389                })
 6390            }
 6391            CodeActionsItem::CodeAction {
 6392                excerpt_id,
 6393                action,
 6394                provider,
 6395            } => {
 6396                let apply_code_action =
 6397                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6398                let workspace = workspace.downgrade();
 6399                Some(cx.spawn_in(window, async move |editor, cx| {
 6400                    let project_transaction = apply_code_action.await?;
 6401                    Self::open_project_transaction(
 6402                        &editor,
 6403                        workspace,
 6404                        project_transaction,
 6405                        title,
 6406                        cx,
 6407                    )
 6408                    .await
 6409                }))
 6410            }
 6411            CodeActionsItem::DebugScenario(scenario) => {
 6412                let context = actions_menu.actions.context;
 6413
 6414                workspace.update(cx, |workspace, cx| {
 6415                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6416                    workspace.start_debug_session(
 6417                        scenario,
 6418                        context,
 6419                        Some(buffer),
 6420                        None,
 6421                        window,
 6422                        cx,
 6423                    );
 6424                });
 6425                Some(Task::ready(Ok(())))
 6426            }
 6427        }
 6428    }
 6429
 6430    pub async fn open_project_transaction(
 6431        editor: &WeakEntity<Editor>,
 6432        workspace: WeakEntity<Workspace>,
 6433        transaction: ProjectTransaction,
 6434        title: String,
 6435        cx: &mut AsyncWindowContext,
 6436    ) -> Result<()> {
 6437        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6438        cx.update(|_, cx| {
 6439            entries.sort_unstable_by_key(|(buffer, _)| {
 6440                buffer.read(cx).file().map(|f| f.path().clone())
 6441            });
 6442        })?;
 6443        if entries.is_empty() {
 6444            return Ok(());
 6445        }
 6446
 6447        // If the project transaction's edits are all contained within this editor, then
 6448        // avoid opening a new editor to display them.
 6449
 6450        if let [(buffer, transaction)] = &*entries {
 6451            let excerpt = editor.update(cx, |editor, cx| {
 6452                editor
 6453                    .buffer()
 6454                    .read(cx)
 6455                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6456            })?;
 6457            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6458                && excerpted_buffer == *buffer
 6459            {
 6460                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6461                    let excerpt_range = excerpt_range.to_offset(buffer);
 6462                    buffer
 6463                        .edited_ranges_for_transaction::<usize>(transaction)
 6464                        .all(|range| {
 6465                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6466                        })
 6467                })?;
 6468
 6469                if all_edits_within_excerpt {
 6470                    return Ok(());
 6471                }
 6472            }
 6473        }
 6474
 6475        let mut ranges_to_highlight = Vec::new();
 6476        let excerpt_buffer = cx.new(|cx| {
 6477            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6478            for (buffer_handle, transaction) in &entries {
 6479                let edited_ranges = buffer_handle
 6480                    .read(cx)
 6481                    .edited_ranges_for_transaction::<Point>(transaction)
 6482                    .collect::<Vec<_>>();
 6483                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6484                    PathKey::for_buffer(buffer_handle, cx),
 6485                    buffer_handle.clone(),
 6486                    edited_ranges,
 6487                    multibuffer_context_lines(cx),
 6488                    cx,
 6489                );
 6490
 6491                ranges_to_highlight.extend(ranges);
 6492            }
 6493            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6494            multibuffer
 6495        })?;
 6496
 6497        workspace.update_in(cx, |workspace, window, cx| {
 6498            let project = workspace.project().clone();
 6499            let editor =
 6500                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6501            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6502            editor.update(cx, |editor, cx| {
 6503                editor.highlight_background::<Self>(
 6504                    &ranges_to_highlight,
 6505                    |theme| theme.colors().editor_highlighted_line_background,
 6506                    cx,
 6507                );
 6508            });
 6509        })?;
 6510
 6511        Ok(())
 6512    }
 6513
 6514    pub fn clear_code_action_providers(&mut self) {
 6515        self.code_action_providers.clear();
 6516        self.available_code_actions.take();
 6517    }
 6518
 6519    pub fn add_code_action_provider(
 6520        &mut self,
 6521        provider: Rc<dyn CodeActionProvider>,
 6522        window: &mut Window,
 6523        cx: &mut Context<Self>,
 6524    ) {
 6525        if self
 6526            .code_action_providers
 6527            .iter()
 6528            .any(|existing_provider| existing_provider.id() == provider.id())
 6529        {
 6530            return;
 6531        }
 6532
 6533        self.code_action_providers.push(provider);
 6534        self.refresh_code_actions(window, cx);
 6535    }
 6536
 6537    pub fn remove_code_action_provider(
 6538        &mut self,
 6539        id: Arc<str>,
 6540        window: &mut Window,
 6541        cx: &mut Context<Self>,
 6542    ) {
 6543        self.code_action_providers
 6544            .retain(|provider| provider.id() != id);
 6545        self.refresh_code_actions(window, cx);
 6546    }
 6547
 6548    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6549        !self.code_action_providers.is_empty()
 6550            && EditorSettings::get_global(cx).toolbar.code_actions
 6551    }
 6552
 6553    pub fn has_available_code_actions(&self) -> bool {
 6554        self.available_code_actions
 6555            .as_ref()
 6556            .is_some_and(|(_, actions)| !actions.is_empty())
 6557    }
 6558
 6559    fn render_inline_code_actions(
 6560        &self,
 6561        icon_size: ui::IconSize,
 6562        display_row: DisplayRow,
 6563        is_active: bool,
 6564        cx: &mut Context<Self>,
 6565    ) -> AnyElement {
 6566        let show_tooltip = !self.context_menu_visible();
 6567        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6568            .icon_size(icon_size)
 6569            .shape(ui::IconButtonShape::Square)
 6570            .icon_color(ui::Color::Hidden)
 6571            .toggle_state(is_active)
 6572            .when(show_tooltip, |this| {
 6573                this.tooltip({
 6574                    let focus_handle = self.focus_handle.clone();
 6575                    move |window, cx| {
 6576                        Tooltip::for_action_in(
 6577                            "Toggle Code Actions",
 6578                            &ToggleCodeActions {
 6579                                deployed_from: None,
 6580                                quick_launch: false,
 6581                            },
 6582                            &focus_handle,
 6583                            window,
 6584                            cx,
 6585                        )
 6586                    }
 6587                })
 6588            })
 6589            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6590                window.focus(&editor.focus_handle(cx));
 6591                editor.toggle_code_actions(
 6592                    &crate::actions::ToggleCodeActions {
 6593                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6594                            display_row,
 6595                        )),
 6596                        quick_launch: false,
 6597                    },
 6598                    window,
 6599                    cx,
 6600                );
 6601            }))
 6602            .into_any_element()
 6603    }
 6604
 6605    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6606        &self.context_menu
 6607    }
 6608
 6609    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6610        let newest_selection = self.selections.newest_anchor().clone();
 6611        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6612        let buffer = self.buffer.read(cx);
 6613        if newest_selection.head().diff_base_anchor.is_some() {
 6614            return None;
 6615        }
 6616        let (start_buffer, start) =
 6617            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6618        let (end_buffer, end) =
 6619            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6620        if start_buffer != end_buffer {
 6621            return None;
 6622        }
 6623
 6624        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6625            cx.background_executor()
 6626                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6627                .await;
 6628
 6629            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6630                let providers = this.code_action_providers.clone();
 6631                let tasks = this
 6632                    .code_action_providers
 6633                    .iter()
 6634                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6635                    .collect::<Vec<_>>();
 6636                (providers, tasks)
 6637            })?;
 6638
 6639            let mut actions = Vec::new();
 6640            for (provider, provider_actions) in
 6641                providers.into_iter().zip(future::join_all(tasks).await)
 6642            {
 6643                if let Some(provider_actions) = provider_actions.log_err() {
 6644                    actions.extend(provider_actions.into_iter().map(|action| {
 6645                        AvailableCodeAction {
 6646                            excerpt_id: newest_selection.start.excerpt_id,
 6647                            action,
 6648                            provider: provider.clone(),
 6649                        }
 6650                    }));
 6651                }
 6652            }
 6653
 6654            this.update(cx, |this, cx| {
 6655                this.available_code_actions = if actions.is_empty() {
 6656                    None
 6657                } else {
 6658                    Some((
 6659                        Location {
 6660                            buffer: start_buffer,
 6661                            range: start..end,
 6662                        },
 6663                        actions.into(),
 6664                    ))
 6665                };
 6666                cx.notify();
 6667            })
 6668        }));
 6669        None
 6670    }
 6671
 6672    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6673        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6674            self.show_git_blame_inline = false;
 6675
 6676            self.show_git_blame_inline_delay_task =
 6677                Some(cx.spawn_in(window, async move |this, cx| {
 6678                    cx.background_executor().timer(delay).await;
 6679
 6680                    this.update(cx, |this, cx| {
 6681                        this.show_git_blame_inline = true;
 6682                        cx.notify();
 6683                    })
 6684                    .log_err();
 6685                }));
 6686        }
 6687    }
 6688
 6689    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6690        let snapshot = self.snapshot(window, cx);
 6691        let cursor = self.selections.newest::<Point>(cx).head();
 6692        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6693        else {
 6694            return;
 6695        };
 6696
 6697        let Some(blame) = self.blame.as_ref() else {
 6698            return;
 6699        };
 6700
 6701        let row_info = RowInfo {
 6702            buffer_id: Some(buffer.remote_id()),
 6703            buffer_row: Some(point.row),
 6704            ..Default::default()
 6705        };
 6706        let Some((buffer, blame_entry)) = blame
 6707            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6708            .flatten()
 6709        else {
 6710            return;
 6711        };
 6712
 6713        let anchor = self.selections.newest_anchor().head();
 6714        let position = self.to_pixel_point(anchor, &snapshot, window);
 6715        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6716            self.show_blame_popover(
 6717                buffer,
 6718                &blame_entry,
 6719                position + last_bounds.origin,
 6720                true,
 6721                cx,
 6722            );
 6723        };
 6724    }
 6725
 6726    fn show_blame_popover(
 6727        &mut self,
 6728        buffer: BufferId,
 6729        blame_entry: &BlameEntry,
 6730        position: gpui::Point<Pixels>,
 6731        ignore_timeout: bool,
 6732        cx: &mut Context<Self>,
 6733    ) {
 6734        if let Some(state) = &mut self.inline_blame_popover {
 6735            state.hide_task.take();
 6736        } else {
 6737            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6738            let blame_entry = blame_entry.clone();
 6739            let show_task = cx.spawn(async move |editor, cx| {
 6740                if !ignore_timeout {
 6741                    cx.background_executor()
 6742                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6743                        .await;
 6744                }
 6745                editor
 6746                    .update(cx, |editor, cx| {
 6747                        editor.inline_blame_popover_show_task.take();
 6748                        let Some(blame) = editor.blame.as_ref() else {
 6749                            return;
 6750                        };
 6751                        let blame = blame.read(cx);
 6752                        let details = blame.details_for_entry(buffer, &blame_entry);
 6753                        let markdown = cx.new(|cx| {
 6754                            Markdown::new(
 6755                                details
 6756                                    .as_ref()
 6757                                    .map(|message| message.message.clone())
 6758                                    .unwrap_or_default(),
 6759                                None,
 6760                                None,
 6761                                cx,
 6762                            )
 6763                        });
 6764                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6765                            position,
 6766                            hide_task: None,
 6767                            popover_bounds: None,
 6768                            popover_state: InlineBlamePopoverState {
 6769                                scroll_handle: ScrollHandle::new(),
 6770                                commit_message: details,
 6771                                markdown,
 6772                            },
 6773                            keyboard_grace: ignore_timeout,
 6774                        });
 6775                        cx.notify();
 6776                    })
 6777                    .ok();
 6778            });
 6779            self.inline_blame_popover_show_task = Some(show_task);
 6780        }
 6781    }
 6782
 6783    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6784        self.inline_blame_popover_show_task.take();
 6785        if let Some(state) = &mut self.inline_blame_popover {
 6786            let hide_task = cx.spawn(async move |editor, cx| {
 6787                cx.background_executor()
 6788                    .timer(std::time::Duration::from_millis(100))
 6789                    .await;
 6790                editor
 6791                    .update(cx, |editor, cx| {
 6792                        editor.inline_blame_popover.take();
 6793                        cx.notify();
 6794                    })
 6795                    .ok();
 6796            });
 6797            state.hide_task = Some(hide_task);
 6798        }
 6799    }
 6800
 6801    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6802        if self.pending_rename.is_some() {
 6803            return None;
 6804        }
 6805
 6806        let provider = self.semantics_provider.clone()?;
 6807        let buffer = self.buffer.read(cx);
 6808        let newest_selection = self.selections.newest_anchor().clone();
 6809        let cursor_position = newest_selection.head();
 6810        let (cursor_buffer, cursor_buffer_position) =
 6811            buffer.text_anchor_for_position(cursor_position, cx)?;
 6812        let (tail_buffer, tail_buffer_position) =
 6813            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6814        if cursor_buffer != tail_buffer {
 6815            return None;
 6816        }
 6817
 6818        let snapshot = cursor_buffer.read(cx).snapshot();
 6819        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6820        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6821        if start_word_range != end_word_range {
 6822            self.document_highlights_task.take();
 6823            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6824            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6825            return None;
 6826        }
 6827
 6828        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6829        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6830            cx.background_executor()
 6831                .timer(Duration::from_millis(debounce))
 6832                .await;
 6833
 6834            let highlights = if let Some(highlights) = cx
 6835                .update(|cx| {
 6836                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6837                })
 6838                .ok()
 6839                .flatten()
 6840            {
 6841                highlights.await.log_err()
 6842            } else {
 6843                None
 6844            };
 6845
 6846            if let Some(highlights) = highlights {
 6847                this.update(cx, |this, cx| {
 6848                    if this.pending_rename.is_some() {
 6849                        return;
 6850                    }
 6851
 6852                    let buffer = this.buffer.read(cx);
 6853                    if buffer
 6854                        .text_anchor_for_position(cursor_position, cx)
 6855                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6856                    {
 6857                        return;
 6858                    }
 6859
 6860                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6861                    let mut write_ranges = Vec::new();
 6862                    let mut read_ranges = Vec::new();
 6863                    for highlight in highlights {
 6864                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6865                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6866                        {
 6867                            let start = highlight
 6868                                .range
 6869                                .start
 6870                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6871                            let end = highlight
 6872                                .range
 6873                                .end
 6874                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6875                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6876                                continue;
 6877                            }
 6878
 6879                            let range = Anchor::range_in_buffer(excerpt_id, buffer_id, start..end);
 6880                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6881                                write_ranges.push(range);
 6882                            } else {
 6883                                read_ranges.push(range);
 6884                            }
 6885                        }
 6886                    }
 6887
 6888                    this.highlight_background::<DocumentHighlightRead>(
 6889                        &read_ranges,
 6890                        |theme| theme.colors().editor_document_highlight_read_background,
 6891                        cx,
 6892                    );
 6893                    this.highlight_background::<DocumentHighlightWrite>(
 6894                        &write_ranges,
 6895                        |theme| theme.colors().editor_document_highlight_write_background,
 6896                        cx,
 6897                    );
 6898                    cx.notify();
 6899                })
 6900                .log_err();
 6901            }
 6902        }));
 6903        None
 6904    }
 6905
 6906    fn prepare_highlight_query_from_selection(
 6907        &mut self,
 6908        cx: &mut Context<Editor>,
 6909    ) -> Option<(String, Range<Anchor>)> {
 6910        if matches!(self.mode, EditorMode::SingleLine) {
 6911            return None;
 6912        }
 6913        if !EditorSettings::get_global(cx).selection_highlight {
 6914            return None;
 6915        }
 6916        if self.selections.count() != 1 || self.selections.line_mode() {
 6917            return None;
 6918        }
 6919        let selection = self.selections.newest::<Point>(cx);
 6920        if selection.is_empty() || selection.start.row != selection.end.row {
 6921            return None;
 6922        }
 6923        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6924        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6925        let query = multi_buffer_snapshot
 6926            .text_for_range(selection_anchor_range.clone())
 6927            .collect::<String>();
 6928        if query.trim().is_empty() {
 6929            return None;
 6930        }
 6931        Some((query, selection_anchor_range))
 6932    }
 6933
 6934    fn update_selection_occurrence_highlights(
 6935        &mut self,
 6936        query_text: String,
 6937        query_range: Range<Anchor>,
 6938        multi_buffer_range_to_query: Range<Point>,
 6939        use_debounce: bool,
 6940        window: &mut Window,
 6941        cx: &mut Context<Editor>,
 6942    ) -> Task<()> {
 6943        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6944        cx.spawn_in(window, async move |editor, cx| {
 6945            if use_debounce {
 6946                cx.background_executor()
 6947                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6948                    .await;
 6949            }
 6950            let match_task = cx.background_spawn(async move {
 6951                let buffer_ranges = multi_buffer_snapshot
 6952                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6953                    .into_iter()
 6954                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6955                let mut match_ranges = Vec::new();
 6956                let Ok(regex) = project::search::SearchQuery::text(
 6957                    query_text.clone(),
 6958                    false,
 6959                    false,
 6960                    false,
 6961                    Default::default(),
 6962                    Default::default(),
 6963                    false,
 6964                    None,
 6965                ) else {
 6966                    return Vec::default();
 6967                };
 6968                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6969                    match_ranges.extend(
 6970                        regex
 6971                            .search(buffer_snapshot, Some(search_range.clone()))
 6972                            .await
 6973                            .into_iter()
 6974                            .filter_map(|match_range| {
 6975                                let match_start = buffer_snapshot
 6976                                    .anchor_after(search_range.start + match_range.start);
 6977                                let match_end = buffer_snapshot
 6978                                    .anchor_before(search_range.start + match_range.end);
 6979                                let match_anchor_range = Anchor::range_in_buffer(
 6980                                    excerpt_id,
 6981                                    buffer_snapshot.remote_id(),
 6982                                    match_start..match_end,
 6983                                );
 6984                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6985                            }),
 6986                    );
 6987                }
 6988                match_ranges
 6989            });
 6990            let match_ranges = match_task.await;
 6991            editor
 6992                .update_in(cx, |editor, _, cx| {
 6993                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6994                    if !match_ranges.is_empty() {
 6995                        editor.highlight_background::<SelectedTextHighlight>(
 6996                            &match_ranges,
 6997                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6998                            cx,
 6999                        )
 7000                    }
 7001                })
 7002                .log_err();
 7003        })
 7004    }
 7005
 7006    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7007        struct NewlineFold;
 7008        let type_id = std::any::TypeId::of::<NewlineFold>();
 7009        if !self.mode.is_single_line() {
 7010            return;
 7011        }
 7012        let snapshot = self.snapshot(window, cx);
 7013        if snapshot.buffer_snapshot().max_point().row == 0 {
 7014            return;
 7015        }
 7016        let task = cx.background_spawn(async move {
 7017            let new_newlines = snapshot
 7018                .buffer_chars_at(0)
 7019                .filter_map(|(c, i)| {
 7020                    if c == '\n' {
 7021                        Some(
 7022                            snapshot.buffer_snapshot().anchor_after(i)
 7023                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7024                        )
 7025                    } else {
 7026                        None
 7027                    }
 7028                })
 7029                .collect::<Vec<_>>();
 7030            let existing_newlines = snapshot
 7031                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7032                .filter_map(|fold| {
 7033                    if fold.placeholder.type_tag == Some(type_id) {
 7034                        Some(fold.range.start..fold.range.end)
 7035                    } else {
 7036                        None
 7037                    }
 7038                })
 7039                .collect::<Vec<_>>();
 7040
 7041            (new_newlines, existing_newlines)
 7042        });
 7043        self.folding_newlines = cx.spawn(async move |this, cx| {
 7044            let (new_newlines, existing_newlines) = task.await;
 7045            if new_newlines == existing_newlines {
 7046                return;
 7047            }
 7048            let placeholder = FoldPlaceholder {
 7049                render: Arc::new(move |_, _, cx| {
 7050                    div()
 7051                        .bg(cx.theme().status().hint_background)
 7052                        .border_b_1()
 7053                        .size_full()
 7054                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7055                        .border_color(cx.theme().status().hint)
 7056                        .child("\\n")
 7057                        .into_any()
 7058                }),
 7059                constrain_width: false,
 7060                merge_adjacent: false,
 7061                type_tag: Some(type_id),
 7062            };
 7063            let creases = new_newlines
 7064                .into_iter()
 7065                .map(|range| Crease::simple(range, placeholder.clone()))
 7066                .collect();
 7067            this.update(cx, |this, cx| {
 7068                this.display_map.update(cx, |display_map, cx| {
 7069                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7070                    display_map.fold(creases, cx);
 7071                });
 7072            })
 7073            .ok();
 7074        });
 7075    }
 7076
 7077    fn refresh_selected_text_highlights(
 7078        &mut self,
 7079        on_buffer_edit: bool,
 7080        window: &mut Window,
 7081        cx: &mut Context<Editor>,
 7082    ) {
 7083        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7084        else {
 7085            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7086            self.quick_selection_highlight_task.take();
 7087            self.debounced_selection_highlight_task.take();
 7088            return;
 7089        };
 7090        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7091        if on_buffer_edit
 7092            || self
 7093                .quick_selection_highlight_task
 7094                .as_ref()
 7095                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7096        {
 7097            let multi_buffer_visible_start = self
 7098                .scroll_manager
 7099                .anchor()
 7100                .anchor
 7101                .to_point(&multi_buffer_snapshot);
 7102            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7103                multi_buffer_visible_start
 7104                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7105                Bias::Left,
 7106            );
 7107            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7108            self.quick_selection_highlight_task = Some((
 7109                query_range.clone(),
 7110                self.update_selection_occurrence_highlights(
 7111                    query_text.clone(),
 7112                    query_range.clone(),
 7113                    multi_buffer_visible_range,
 7114                    false,
 7115                    window,
 7116                    cx,
 7117                ),
 7118            ));
 7119        }
 7120        if on_buffer_edit
 7121            || self
 7122                .debounced_selection_highlight_task
 7123                .as_ref()
 7124                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7125        {
 7126            let multi_buffer_start = multi_buffer_snapshot
 7127                .anchor_before(0)
 7128                .to_point(&multi_buffer_snapshot);
 7129            let multi_buffer_end = multi_buffer_snapshot
 7130                .anchor_after(multi_buffer_snapshot.len())
 7131                .to_point(&multi_buffer_snapshot);
 7132            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7133            self.debounced_selection_highlight_task = Some((
 7134                query_range.clone(),
 7135                self.update_selection_occurrence_highlights(
 7136                    query_text,
 7137                    query_range,
 7138                    multi_buffer_full_range,
 7139                    true,
 7140                    window,
 7141                    cx,
 7142                ),
 7143            ));
 7144        }
 7145    }
 7146
 7147    pub fn refresh_edit_prediction(
 7148        &mut self,
 7149        debounce: bool,
 7150        user_requested: bool,
 7151        window: &mut Window,
 7152        cx: &mut Context<Self>,
 7153    ) -> Option<()> {
 7154        if DisableAiSettings::get_global(cx).disable_ai {
 7155            return None;
 7156        }
 7157
 7158        let provider = self.edit_prediction_provider()?;
 7159        let cursor = self.selections.newest_anchor().head();
 7160        let (buffer, cursor_buffer_position) =
 7161            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7162
 7163        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7164            self.discard_edit_prediction(false, cx);
 7165            return None;
 7166        }
 7167
 7168        self.update_visible_edit_prediction(window, cx);
 7169
 7170        if !user_requested
 7171            && (!self.should_show_edit_predictions()
 7172                || !self.is_focused(window)
 7173                || buffer.read(cx).is_empty())
 7174        {
 7175            self.discard_edit_prediction(false, cx);
 7176            return None;
 7177        }
 7178
 7179        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7180        Some(())
 7181    }
 7182
 7183    fn show_edit_predictions_in_menu(&self) -> bool {
 7184        match self.edit_prediction_settings {
 7185            EditPredictionSettings::Disabled => false,
 7186            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7187        }
 7188    }
 7189
 7190    pub fn edit_predictions_enabled(&self) -> bool {
 7191        match self.edit_prediction_settings {
 7192            EditPredictionSettings::Disabled => false,
 7193            EditPredictionSettings::Enabled { .. } => true,
 7194        }
 7195    }
 7196
 7197    fn edit_prediction_requires_modifier(&self) -> bool {
 7198        match self.edit_prediction_settings {
 7199            EditPredictionSettings::Disabled => false,
 7200            EditPredictionSettings::Enabled {
 7201                preview_requires_modifier,
 7202                ..
 7203            } => preview_requires_modifier,
 7204        }
 7205    }
 7206
 7207    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7208        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7209            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7210            self.discard_edit_prediction(false, cx);
 7211        } else {
 7212            let selection = self.selections.newest_anchor();
 7213            let cursor = selection.head();
 7214
 7215            if let Some((buffer, cursor_buffer_position)) =
 7216                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7217            {
 7218                self.edit_prediction_settings =
 7219                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7220            }
 7221        }
 7222    }
 7223
 7224    fn edit_prediction_settings_at_position(
 7225        &self,
 7226        buffer: &Entity<Buffer>,
 7227        buffer_position: language::Anchor,
 7228        cx: &App,
 7229    ) -> EditPredictionSettings {
 7230        if !self.mode.is_full()
 7231            || !self.show_edit_predictions_override.unwrap_or(true)
 7232            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7233        {
 7234            return EditPredictionSettings::Disabled;
 7235        }
 7236
 7237        let buffer = buffer.read(cx);
 7238
 7239        let file = buffer.file();
 7240
 7241        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7242            return EditPredictionSettings::Disabled;
 7243        };
 7244
 7245        let by_provider = matches!(
 7246            self.menu_edit_predictions_policy,
 7247            MenuEditPredictionsPolicy::ByProvider
 7248        );
 7249
 7250        let show_in_menu = by_provider
 7251            && self
 7252                .edit_prediction_provider
 7253                .as_ref()
 7254                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7255
 7256        let preview_requires_modifier =
 7257            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7258
 7259        EditPredictionSettings::Enabled {
 7260            show_in_menu,
 7261            preview_requires_modifier,
 7262        }
 7263    }
 7264
 7265    fn should_show_edit_predictions(&self) -> bool {
 7266        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7267    }
 7268
 7269    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7270        matches!(
 7271            self.edit_prediction_preview,
 7272            EditPredictionPreview::Active { .. }
 7273        )
 7274    }
 7275
 7276    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7277        let cursor = self.selections.newest_anchor().head();
 7278        if let Some((buffer, cursor_position)) =
 7279            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7280        {
 7281            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7282        } else {
 7283            false
 7284        }
 7285    }
 7286
 7287    pub fn supports_minimap(&self, cx: &App) -> bool {
 7288        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7289    }
 7290
 7291    fn edit_predictions_enabled_in_buffer(
 7292        &self,
 7293        buffer: &Entity<Buffer>,
 7294        buffer_position: language::Anchor,
 7295        cx: &App,
 7296    ) -> bool {
 7297        maybe!({
 7298            if self.read_only(cx) {
 7299                return Some(false);
 7300            }
 7301            let provider = self.edit_prediction_provider()?;
 7302            if !provider.is_enabled(buffer, buffer_position, cx) {
 7303                return Some(false);
 7304            }
 7305            let buffer = buffer.read(cx);
 7306            let Some(file) = buffer.file() else {
 7307                return Some(true);
 7308            };
 7309            let settings = all_language_settings(Some(file), cx);
 7310            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7311        })
 7312        .unwrap_or(false)
 7313    }
 7314
 7315    fn cycle_edit_prediction(
 7316        &mut self,
 7317        direction: Direction,
 7318        window: &mut Window,
 7319        cx: &mut Context<Self>,
 7320    ) -> Option<()> {
 7321        let provider = self.edit_prediction_provider()?;
 7322        let cursor = self.selections.newest_anchor().head();
 7323        let (buffer, cursor_buffer_position) =
 7324            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7325        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7326            return None;
 7327        }
 7328
 7329        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7330        self.update_visible_edit_prediction(window, cx);
 7331
 7332        Some(())
 7333    }
 7334
 7335    pub fn show_edit_prediction(
 7336        &mut self,
 7337        _: &ShowEditPrediction,
 7338        window: &mut Window,
 7339        cx: &mut Context<Self>,
 7340    ) {
 7341        if !self.has_active_edit_prediction() {
 7342            self.refresh_edit_prediction(false, true, window, cx);
 7343            return;
 7344        }
 7345
 7346        self.update_visible_edit_prediction(window, cx);
 7347    }
 7348
 7349    pub fn display_cursor_names(
 7350        &mut self,
 7351        _: &DisplayCursorNames,
 7352        window: &mut Window,
 7353        cx: &mut Context<Self>,
 7354    ) {
 7355        self.show_cursor_names(window, cx);
 7356    }
 7357
 7358    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7359        self.show_cursor_names = true;
 7360        cx.notify();
 7361        cx.spawn_in(window, async move |this, cx| {
 7362            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7363            this.update(cx, |this, cx| {
 7364                this.show_cursor_names = false;
 7365                cx.notify()
 7366            })
 7367            .ok()
 7368        })
 7369        .detach();
 7370    }
 7371
 7372    pub fn next_edit_prediction(
 7373        &mut self,
 7374        _: &NextEditPrediction,
 7375        window: &mut Window,
 7376        cx: &mut Context<Self>,
 7377    ) {
 7378        if self.has_active_edit_prediction() {
 7379            self.cycle_edit_prediction(Direction::Next, window, cx);
 7380        } else {
 7381            let is_copilot_disabled = self
 7382                .refresh_edit_prediction(false, true, window, cx)
 7383                .is_none();
 7384            if is_copilot_disabled {
 7385                cx.propagate();
 7386            }
 7387        }
 7388    }
 7389
 7390    pub fn previous_edit_prediction(
 7391        &mut self,
 7392        _: &PreviousEditPrediction,
 7393        window: &mut Window,
 7394        cx: &mut Context<Self>,
 7395    ) {
 7396        if self.has_active_edit_prediction() {
 7397            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7398        } else {
 7399            let is_copilot_disabled = self
 7400                .refresh_edit_prediction(false, true, window, cx)
 7401                .is_none();
 7402            if is_copilot_disabled {
 7403                cx.propagate();
 7404            }
 7405        }
 7406    }
 7407
 7408    pub fn accept_edit_prediction(
 7409        &mut self,
 7410        _: &AcceptEditPrediction,
 7411        window: &mut Window,
 7412        cx: &mut Context<Self>,
 7413    ) {
 7414        if self.show_edit_predictions_in_menu() {
 7415            self.hide_context_menu(window, cx);
 7416        }
 7417
 7418        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7419            return;
 7420        };
 7421
 7422        match &active_edit_prediction.completion {
 7423            EditPrediction::MoveWithin { target, .. } => {
 7424                let target = *target;
 7425
 7426                if let Some(position_map) = &self.last_position_map {
 7427                    if position_map
 7428                        .visible_row_range
 7429                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7430                        || !self.edit_prediction_requires_modifier()
 7431                    {
 7432                        self.unfold_ranges(&[target..target], true, false, cx);
 7433                        // Note that this is also done in vim's handler of the Tab action.
 7434                        self.change_selections(
 7435                            SelectionEffects::scroll(Autoscroll::newest()),
 7436                            window,
 7437                            cx,
 7438                            |selections| {
 7439                                selections.select_anchor_ranges([target..target]);
 7440                            },
 7441                        );
 7442                        self.clear_row_highlights::<EditPredictionPreview>();
 7443
 7444                        self.edit_prediction_preview
 7445                            .set_previous_scroll_position(None);
 7446                    } else {
 7447                        self.edit_prediction_preview
 7448                            .set_previous_scroll_position(Some(
 7449                                position_map.snapshot.scroll_anchor,
 7450                            ));
 7451
 7452                        self.highlight_rows::<EditPredictionPreview>(
 7453                            target..target,
 7454                            cx.theme().colors().editor_highlighted_line_background,
 7455                            RowHighlightOptions {
 7456                                autoscroll: true,
 7457                                ..Default::default()
 7458                            },
 7459                            cx,
 7460                        );
 7461                        self.request_autoscroll(Autoscroll::fit(), cx);
 7462                    }
 7463                }
 7464            }
 7465            EditPrediction::MoveOutside { snapshot, target } => {
 7466                if let Some(workspace) = self.workspace() {
 7467                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7468                        .detach_and_log_err(cx);
 7469                }
 7470            }
 7471            EditPrediction::Edit { edits, .. } => {
 7472                self.report_edit_prediction_event(
 7473                    active_edit_prediction.completion_id.clone(),
 7474                    true,
 7475                    cx,
 7476                );
 7477
 7478                if let Some(provider) = self.edit_prediction_provider() {
 7479                    provider.accept(cx);
 7480                }
 7481
 7482                // Store the transaction ID and selections before applying the edit
 7483                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7484
 7485                let snapshot = self.buffer.read(cx).snapshot(cx);
 7486                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7487
 7488                self.buffer.update(cx, |buffer, cx| {
 7489                    buffer.edit(edits.iter().cloned(), None, cx)
 7490                });
 7491
 7492                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7493                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7494                });
 7495
 7496                let selections = self.selections.disjoint_anchors_arc();
 7497                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7498                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7499                    if has_new_transaction {
 7500                        self.selection_history
 7501                            .insert_transaction(transaction_id_now, selections);
 7502                    }
 7503                }
 7504
 7505                self.update_visible_edit_prediction(window, cx);
 7506                if self.active_edit_prediction.is_none() {
 7507                    self.refresh_edit_prediction(true, true, window, cx);
 7508                }
 7509
 7510                cx.notify();
 7511            }
 7512        }
 7513
 7514        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7515    }
 7516
 7517    pub fn accept_partial_edit_prediction(
 7518        &mut self,
 7519        _: &AcceptPartialEditPrediction,
 7520        window: &mut Window,
 7521        cx: &mut Context<Self>,
 7522    ) {
 7523        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7524            return;
 7525        };
 7526        if self.selections.count() != 1 {
 7527            return;
 7528        }
 7529
 7530        match &active_edit_prediction.completion {
 7531            EditPrediction::MoveWithin { target, .. } => {
 7532                let target = *target;
 7533                self.change_selections(
 7534                    SelectionEffects::scroll(Autoscroll::newest()),
 7535                    window,
 7536                    cx,
 7537                    |selections| {
 7538                        selections.select_anchor_ranges([target..target]);
 7539                    },
 7540                );
 7541            }
 7542            EditPrediction::MoveOutside { snapshot, target } => {
 7543                if let Some(workspace) = self.workspace() {
 7544                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7545                        .detach_and_log_err(cx);
 7546                }
 7547            }
 7548            EditPrediction::Edit { edits, .. } => {
 7549                self.report_edit_prediction_event(
 7550                    active_edit_prediction.completion_id.clone(),
 7551                    true,
 7552                    cx,
 7553                );
 7554
 7555                // Find an insertion that starts at the cursor position.
 7556                let snapshot = self.buffer.read(cx).snapshot(cx);
 7557                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7558                let insertion = edits.iter().find_map(|(range, text)| {
 7559                    let range = range.to_offset(&snapshot);
 7560                    if range.is_empty() && range.start == cursor_offset {
 7561                        Some(text)
 7562                    } else {
 7563                        None
 7564                    }
 7565                });
 7566
 7567                if let Some(text) = insertion {
 7568                    let mut partial_completion = text
 7569                        .chars()
 7570                        .by_ref()
 7571                        .take_while(|c| c.is_alphabetic())
 7572                        .collect::<String>();
 7573                    if partial_completion.is_empty() {
 7574                        partial_completion = text
 7575                            .chars()
 7576                            .by_ref()
 7577                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7578                            .collect::<String>();
 7579                    }
 7580
 7581                    cx.emit(EditorEvent::InputHandled {
 7582                        utf16_range_to_replace: None,
 7583                        text: partial_completion.clone().into(),
 7584                    });
 7585
 7586                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7587
 7588                    self.refresh_edit_prediction(true, true, window, cx);
 7589                    cx.notify();
 7590                } else {
 7591                    self.accept_edit_prediction(&Default::default(), window, cx);
 7592                }
 7593            }
 7594        }
 7595    }
 7596
 7597    fn discard_edit_prediction(
 7598        &mut self,
 7599        should_report_edit_prediction_event: bool,
 7600        cx: &mut Context<Self>,
 7601    ) -> bool {
 7602        if should_report_edit_prediction_event {
 7603            let completion_id = self
 7604                .active_edit_prediction
 7605                .as_ref()
 7606                .and_then(|active_completion| active_completion.completion_id.clone());
 7607
 7608            self.report_edit_prediction_event(completion_id, false, cx);
 7609        }
 7610
 7611        if let Some(provider) = self.edit_prediction_provider() {
 7612            provider.discard(cx);
 7613        }
 7614
 7615        self.take_active_edit_prediction(cx)
 7616    }
 7617
 7618    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7619        let Some(provider) = self.edit_prediction_provider() else {
 7620            return;
 7621        };
 7622
 7623        let Some((_, buffer, _)) = self
 7624            .buffer
 7625            .read(cx)
 7626            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7627        else {
 7628            return;
 7629        };
 7630
 7631        let extension = buffer
 7632            .read(cx)
 7633            .file()
 7634            .and_then(|file| Some(file.path().extension()?.to_string()));
 7635
 7636        let event_type = match accepted {
 7637            true => "Edit Prediction Accepted",
 7638            false => "Edit Prediction Discarded",
 7639        };
 7640        telemetry::event!(
 7641            event_type,
 7642            provider = provider.name(),
 7643            prediction_id = id,
 7644            suggestion_accepted = accepted,
 7645            file_extension = extension,
 7646        );
 7647    }
 7648
 7649    fn open_editor_at_anchor(
 7650        snapshot: &language::BufferSnapshot,
 7651        target: language::Anchor,
 7652        workspace: &Entity<Workspace>,
 7653        window: &mut Window,
 7654        cx: &mut App,
 7655    ) -> Task<Result<()>> {
 7656        workspace.update(cx, |workspace, cx| {
 7657            let path = snapshot.file().map(|file| file.full_path(cx));
 7658            let Some(path) =
 7659                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7660            else {
 7661                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7662            };
 7663            let target = text::ToPoint::to_point(&target, snapshot);
 7664            let item = workspace.open_path(path, None, true, window, cx);
 7665            window.spawn(cx, async move |cx| {
 7666                let Some(editor) = item.await?.downcast::<Editor>() else {
 7667                    return Ok(());
 7668                };
 7669                editor
 7670                    .update_in(cx, |editor, window, cx| {
 7671                        editor.go_to_singleton_buffer_point(target, window, cx);
 7672                    })
 7673                    .ok();
 7674                anyhow::Ok(())
 7675            })
 7676        })
 7677    }
 7678
 7679    pub fn has_active_edit_prediction(&self) -> bool {
 7680        self.active_edit_prediction.is_some()
 7681    }
 7682
 7683    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7684        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7685            return false;
 7686        };
 7687
 7688        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7689        self.clear_highlights::<EditPredictionHighlight>(cx);
 7690        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7691        true
 7692    }
 7693
 7694    /// Returns true when we're displaying the edit prediction popover below the cursor
 7695    /// like we are not previewing and the LSP autocomplete menu is visible
 7696    /// or we are in `when_holding_modifier` mode.
 7697    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7698        if self.edit_prediction_preview_is_active()
 7699            || !self.show_edit_predictions_in_menu()
 7700            || !self.edit_predictions_enabled()
 7701        {
 7702            return false;
 7703        }
 7704
 7705        if self.has_visible_completions_menu() {
 7706            return true;
 7707        }
 7708
 7709        has_completion && self.edit_prediction_requires_modifier()
 7710    }
 7711
 7712    fn handle_modifiers_changed(
 7713        &mut self,
 7714        modifiers: Modifiers,
 7715        position_map: &PositionMap,
 7716        window: &mut Window,
 7717        cx: &mut Context<Self>,
 7718    ) {
 7719        if self.show_edit_predictions_in_menu() {
 7720            self.update_edit_prediction_preview(&modifiers, window, cx);
 7721        }
 7722
 7723        self.update_selection_mode(&modifiers, position_map, window, cx);
 7724
 7725        let mouse_position = window.mouse_position();
 7726        if !position_map.text_hitbox.is_hovered(window) {
 7727            return;
 7728        }
 7729
 7730        self.update_hovered_link(
 7731            position_map.point_for_position(mouse_position),
 7732            &position_map.snapshot,
 7733            modifiers,
 7734            window,
 7735            cx,
 7736        )
 7737    }
 7738
 7739    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7740        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7741        if invert {
 7742            match multi_cursor_setting {
 7743                MultiCursorModifier::Alt => modifiers.alt,
 7744                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7745            }
 7746        } else {
 7747            match multi_cursor_setting {
 7748                MultiCursorModifier::Alt => modifiers.secondary(),
 7749                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7750            }
 7751        }
 7752    }
 7753
 7754    fn columnar_selection_mode(
 7755        modifiers: &Modifiers,
 7756        cx: &mut Context<Self>,
 7757    ) -> Option<ColumnarMode> {
 7758        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7759            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7760                Some(ColumnarMode::FromMouse)
 7761            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7762                Some(ColumnarMode::FromSelection)
 7763            } else {
 7764                None
 7765            }
 7766        } else {
 7767            None
 7768        }
 7769    }
 7770
 7771    fn update_selection_mode(
 7772        &mut self,
 7773        modifiers: &Modifiers,
 7774        position_map: &PositionMap,
 7775        window: &mut Window,
 7776        cx: &mut Context<Self>,
 7777    ) {
 7778        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7779            return;
 7780        };
 7781        if self.selections.pending_anchor().is_none() {
 7782            return;
 7783        }
 7784
 7785        let mouse_position = window.mouse_position();
 7786        let point_for_position = position_map.point_for_position(mouse_position);
 7787        let position = point_for_position.previous_valid;
 7788
 7789        self.select(
 7790            SelectPhase::BeginColumnar {
 7791                position,
 7792                reset: false,
 7793                mode,
 7794                goal_column: point_for_position.exact_unclipped.column(),
 7795            },
 7796            window,
 7797            cx,
 7798        );
 7799    }
 7800
 7801    fn update_edit_prediction_preview(
 7802        &mut self,
 7803        modifiers: &Modifiers,
 7804        window: &mut Window,
 7805        cx: &mut Context<Self>,
 7806    ) {
 7807        let mut modifiers_held = false;
 7808        if let Some(accept_keystroke) = self
 7809            .accept_edit_prediction_keybind(false, window, cx)
 7810            .keystroke()
 7811        {
 7812            modifiers_held = modifiers_held
 7813                || (accept_keystroke.modifiers() == modifiers
 7814                    && accept_keystroke.modifiers().modified());
 7815        };
 7816        if let Some(accept_partial_keystroke) = self
 7817            .accept_edit_prediction_keybind(true, window, cx)
 7818            .keystroke()
 7819        {
 7820            modifiers_held = modifiers_held
 7821                || (accept_partial_keystroke.modifiers() == modifiers
 7822                    && accept_partial_keystroke.modifiers().modified());
 7823        }
 7824
 7825        if modifiers_held {
 7826            if matches!(
 7827                self.edit_prediction_preview,
 7828                EditPredictionPreview::Inactive { .. }
 7829            ) {
 7830                self.edit_prediction_preview = EditPredictionPreview::Active {
 7831                    previous_scroll_position: None,
 7832                    since: Instant::now(),
 7833                };
 7834
 7835                self.update_visible_edit_prediction(window, cx);
 7836                cx.notify();
 7837            }
 7838        } else if let EditPredictionPreview::Active {
 7839            previous_scroll_position,
 7840            since,
 7841        } = self.edit_prediction_preview
 7842        {
 7843            if let (Some(previous_scroll_position), Some(position_map)) =
 7844                (previous_scroll_position, self.last_position_map.as_ref())
 7845            {
 7846                self.set_scroll_position(
 7847                    previous_scroll_position
 7848                        .scroll_position(&position_map.snapshot.display_snapshot),
 7849                    window,
 7850                    cx,
 7851                );
 7852            }
 7853
 7854            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7855                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7856            };
 7857            self.clear_row_highlights::<EditPredictionPreview>();
 7858            self.update_visible_edit_prediction(window, cx);
 7859            cx.notify();
 7860        }
 7861    }
 7862
 7863    fn update_visible_edit_prediction(
 7864        &mut self,
 7865        _window: &mut Window,
 7866        cx: &mut Context<Self>,
 7867    ) -> Option<()> {
 7868        if DisableAiSettings::get_global(cx).disable_ai {
 7869            return None;
 7870        }
 7871
 7872        if self.ime_transaction.is_some() {
 7873            self.discard_edit_prediction(false, cx);
 7874            return None;
 7875        }
 7876
 7877        let selection = self.selections.newest_anchor();
 7878        let cursor = selection.head();
 7879        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7880        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7881        let excerpt_id = cursor.excerpt_id;
 7882
 7883        let show_in_menu = self.show_edit_predictions_in_menu();
 7884        let completions_menu_has_precedence = !show_in_menu
 7885            && (self.context_menu.borrow().is_some()
 7886                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7887
 7888        if completions_menu_has_precedence
 7889            || !offset_selection.is_empty()
 7890            || self
 7891                .active_edit_prediction
 7892                .as_ref()
 7893                .is_some_and(|completion| {
 7894                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7895                        return false;
 7896                    };
 7897                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7898                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7899                    !invalidation_range.contains(&offset_selection.head())
 7900                })
 7901        {
 7902            self.discard_edit_prediction(false, cx);
 7903            return None;
 7904        }
 7905
 7906        self.take_active_edit_prediction(cx);
 7907        let Some(provider) = self.edit_prediction_provider() else {
 7908            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7909            return None;
 7910        };
 7911
 7912        let (buffer, cursor_buffer_position) =
 7913            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7914
 7915        self.edit_prediction_settings =
 7916            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7917
 7918        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7919
 7920        if self.edit_prediction_indent_conflict {
 7921            let cursor_point = cursor.to_point(&multibuffer);
 7922
 7923            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7924
 7925            if let Some((_, indent)) = indents.iter().next()
 7926                && indent.len == cursor_point.column
 7927            {
 7928                self.edit_prediction_indent_conflict = false;
 7929            }
 7930        }
 7931
 7932        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7933
 7934        let (completion_id, edits, edit_preview) = match edit_prediction {
 7935            edit_prediction::EditPrediction::Local {
 7936                id,
 7937                edits,
 7938                edit_preview,
 7939            } => (id, edits, edit_preview),
 7940            edit_prediction::EditPrediction::Jump {
 7941                id,
 7942                snapshot,
 7943                target,
 7944            } => {
 7945                self.stale_edit_prediction_in_menu = None;
 7946                self.active_edit_prediction = Some(EditPredictionState {
 7947                    inlay_ids: vec![],
 7948                    completion: EditPrediction::MoveOutside { snapshot, target },
 7949                    completion_id: id,
 7950                    invalidation_range: None,
 7951                });
 7952                cx.notify();
 7953                return Some(());
 7954            }
 7955        };
 7956
 7957        let edits = edits
 7958            .into_iter()
 7959            .flat_map(|(range, new_text)| {
 7960                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7961                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7962                Some((start..end, new_text))
 7963            })
 7964            .collect::<Vec<_>>();
 7965        if edits.is_empty() {
 7966            return None;
 7967        }
 7968
 7969        let first_edit_start = edits.first().unwrap().0.start;
 7970        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7971        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7972
 7973        let last_edit_end = edits.last().unwrap().0.end;
 7974        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7975        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7976
 7977        let cursor_row = cursor.to_point(&multibuffer).row;
 7978
 7979        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7980
 7981        let mut inlay_ids = Vec::new();
 7982        let invalidation_row_range;
 7983        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7984            Some(cursor_row..edit_end_row)
 7985        } else if cursor_row > edit_end_row {
 7986            Some(edit_start_row..cursor_row)
 7987        } else {
 7988            None
 7989        };
 7990        let supports_jump = self
 7991            .edit_prediction_provider
 7992            .as_ref()
 7993            .map(|provider| provider.provider.supports_jump_to_edit())
 7994            .unwrap_or(true);
 7995
 7996        let is_move = supports_jump
 7997            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7998        let completion = if is_move {
 7999            invalidation_row_range =
 8000                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8001            let target = first_edit_start;
 8002            EditPrediction::MoveWithin { target, snapshot }
 8003        } else {
 8004            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8005                && !self.edit_predictions_hidden_for_vim_mode;
 8006
 8007            if show_completions_in_buffer {
 8008                if edits
 8009                    .iter()
 8010                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8011                {
 8012                    let mut inlays = Vec::new();
 8013                    for (range, new_text) in &edits {
 8014                        let inlay = Inlay::edit_prediction(
 8015                            post_inc(&mut self.next_inlay_id),
 8016                            range.start,
 8017                            new_text.as_str(),
 8018                        );
 8019                        inlay_ids.push(inlay.id);
 8020                        inlays.push(inlay);
 8021                    }
 8022
 8023                    self.splice_inlays(&[], inlays, cx);
 8024                } else {
 8025                    let background_color = cx.theme().status().deleted_background;
 8026                    self.highlight_text::<EditPredictionHighlight>(
 8027                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8028                        HighlightStyle {
 8029                            background_color: Some(background_color),
 8030                            ..Default::default()
 8031                        },
 8032                        cx,
 8033                    );
 8034                }
 8035            }
 8036
 8037            invalidation_row_range = edit_start_row..edit_end_row;
 8038
 8039            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8040                if provider.show_tab_accept_marker() {
 8041                    EditDisplayMode::TabAccept
 8042                } else {
 8043                    EditDisplayMode::Inline
 8044                }
 8045            } else {
 8046                EditDisplayMode::DiffPopover
 8047            };
 8048
 8049            EditPrediction::Edit {
 8050                edits,
 8051                edit_preview,
 8052                display_mode,
 8053                snapshot,
 8054            }
 8055        };
 8056
 8057        let invalidation_range = multibuffer
 8058            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8059            ..multibuffer.anchor_after(Point::new(
 8060                invalidation_row_range.end,
 8061                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8062            ));
 8063
 8064        self.stale_edit_prediction_in_menu = None;
 8065        self.active_edit_prediction = Some(EditPredictionState {
 8066            inlay_ids,
 8067            completion,
 8068            completion_id,
 8069            invalidation_range: Some(invalidation_range),
 8070        });
 8071
 8072        cx.notify();
 8073
 8074        Some(())
 8075    }
 8076
 8077    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8078        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8079    }
 8080
 8081    fn clear_tasks(&mut self) {
 8082        self.tasks.clear()
 8083    }
 8084
 8085    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8086        if self.tasks.insert(key, value).is_some() {
 8087            // This case should hopefully be rare, but just in case...
 8088            log::error!(
 8089                "multiple different run targets found on a single line, only the last target will be rendered"
 8090            )
 8091        }
 8092    }
 8093
 8094    /// Get all display points of breakpoints that will be rendered within editor
 8095    ///
 8096    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8097    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8098    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8099    fn active_breakpoints(
 8100        &self,
 8101        range: Range<DisplayRow>,
 8102        window: &mut Window,
 8103        cx: &mut Context<Self>,
 8104    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8105        let mut breakpoint_display_points = HashMap::default();
 8106
 8107        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8108            return breakpoint_display_points;
 8109        };
 8110
 8111        let snapshot = self.snapshot(window, cx);
 8112
 8113        let multi_buffer_snapshot = snapshot.display_snapshot.buffer_snapshot();
 8114        let Some(project) = self.project() else {
 8115            return breakpoint_display_points;
 8116        };
 8117
 8118        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8119            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8120
 8121        for (buffer_snapshot, range, excerpt_id) in
 8122            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8123        {
 8124            let Some(buffer) = project
 8125                .read(cx)
 8126                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8127            else {
 8128                continue;
 8129            };
 8130            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8131                &buffer,
 8132                Some(
 8133                    buffer_snapshot.anchor_before(range.start)
 8134                        ..buffer_snapshot.anchor_after(range.end),
 8135                ),
 8136                buffer_snapshot,
 8137                cx,
 8138            );
 8139            for (breakpoint, state) in breakpoints {
 8140                let multi_buffer_anchor =
 8141                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8142                let position = multi_buffer_anchor
 8143                    .to_point(multi_buffer_snapshot)
 8144                    .to_display_point(&snapshot);
 8145
 8146                breakpoint_display_points.insert(
 8147                    position.row(),
 8148                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8149                );
 8150            }
 8151        }
 8152
 8153        breakpoint_display_points
 8154    }
 8155
 8156    fn breakpoint_context_menu(
 8157        &self,
 8158        anchor: Anchor,
 8159        window: &mut Window,
 8160        cx: &mut Context<Self>,
 8161    ) -> Entity<ui::ContextMenu> {
 8162        let weak_editor = cx.weak_entity();
 8163        let focus_handle = self.focus_handle(cx);
 8164
 8165        let row = self
 8166            .buffer
 8167            .read(cx)
 8168            .snapshot(cx)
 8169            .summary_for_anchor::<Point>(&anchor)
 8170            .row;
 8171
 8172        let breakpoint = self
 8173            .breakpoint_at_row(row, window, cx)
 8174            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8175
 8176        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8177            "Edit Log Breakpoint"
 8178        } else {
 8179            "Set Log Breakpoint"
 8180        };
 8181
 8182        let condition_breakpoint_msg = if breakpoint
 8183            .as_ref()
 8184            .is_some_and(|bp| bp.1.condition.is_some())
 8185        {
 8186            "Edit Condition Breakpoint"
 8187        } else {
 8188            "Set Condition Breakpoint"
 8189        };
 8190
 8191        let hit_condition_breakpoint_msg = if breakpoint
 8192            .as_ref()
 8193            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8194        {
 8195            "Edit Hit Condition Breakpoint"
 8196        } else {
 8197            "Set Hit Condition Breakpoint"
 8198        };
 8199
 8200        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8201            "Unset Breakpoint"
 8202        } else {
 8203            "Set Breakpoint"
 8204        };
 8205
 8206        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8207
 8208        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8209            BreakpointState::Enabled => Some("Disable"),
 8210            BreakpointState::Disabled => Some("Enable"),
 8211        });
 8212
 8213        let (anchor, breakpoint) =
 8214            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8215
 8216        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8217            menu.on_blur_subscription(Subscription::new(|| {}))
 8218                .context(focus_handle)
 8219                .when(run_to_cursor, |this| {
 8220                    let weak_editor = weak_editor.clone();
 8221                    this.entry("Run to cursor", None, move |window, cx| {
 8222                        weak_editor
 8223                            .update(cx, |editor, cx| {
 8224                                editor.change_selections(
 8225                                    SelectionEffects::no_scroll(),
 8226                                    window,
 8227                                    cx,
 8228                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8229                                );
 8230                            })
 8231                            .ok();
 8232
 8233                        window.dispatch_action(Box::new(RunToCursor), cx);
 8234                    })
 8235                    .separator()
 8236                })
 8237                .when_some(toggle_state_msg, |this, msg| {
 8238                    this.entry(msg, None, {
 8239                        let weak_editor = weak_editor.clone();
 8240                        let breakpoint = breakpoint.clone();
 8241                        move |_window, cx| {
 8242                            weak_editor
 8243                                .update(cx, |this, cx| {
 8244                                    this.edit_breakpoint_at_anchor(
 8245                                        anchor,
 8246                                        breakpoint.as_ref().clone(),
 8247                                        BreakpointEditAction::InvertState,
 8248                                        cx,
 8249                                    );
 8250                                })
 8251                                .log_err();
 8252                        }
 8253                    })
 8254                })
 8255                .entry(set_breakpoint_msg, None, {
 8256                    let weak_editor = weak_editor.clone();
 8257                    let breakpoint = breakpoint.clone();
 8258                    move |_window, cx| {
 8259                        weak_editor
 8260                            .update(cx, |this, cx| {
 8261                                this.edit_breakpoint_at_anchor(
 8262                                    anchor,
 8263                                    breakpoint.as_ref().clone(),
 8264                                    BreakpointEditAction::Toggle,
 8265                                    cx,
 8266                                );
 8267                            })
 8268                            .log_err();
 8269                    }
 8270                })
 8271                .entry(log_breakpoint_msg, None, {
 8272                    let breakpoint = breakpoint.clone();
 8273                    let weak_editor = weak_editor.clone();
 8274                    move |window, cx| {
 8275                        weak_editor
 8276                            .update(cx, |this, cx| {
 8277                                this.add_edit_breakpoint_block(
 8278                                    anchor,
 8279                                    breakpoint.as_ref(),
 8280                                    BreakpointPromptEditAction::Log,
 8281                                    window,
 8282                                    cx,
 8283                                );
 8284                            })
 8285                            .log_err();
 8286                    }
 8287                })
 8288                .entry(condition_breakpoint_msg, None, {
 8289                    let breakpoint = breakpoint.clone();
 8290                    let weak_editor = weak_editor.clone();
 8291                    move |window, cx| {
 8292                        weak_editor
 8293                            .update(cx, |this, cx| {
 8294                                this.add_edit_breakpoint_block(
 8295                                    anchor,
 8296                                    breakpoint.as_ref(),
 8297                                    BreakpointPromptEditAction::Condition,
 8298                                    window,
 8299                                    cx,
 8300                                );
 8301                            })
 8302                            .log_err();
 8303                    }
 8304                })
 8305                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8306                    weak_editor
 8307                        .update(cx, |this, cx| {
 8308                            this.add_edit_breakpoint_block(
 8309                                anchor,
 8310                                breakpoint.as_ref(),
 8311                                BreakpointPromptEditAction::HitCondition,
 8312                                window,
 8313                                cx,
 8314                            );
 8315                        })
 8316                        .log_err();
 8317                })
 8318        })
 8319    }
 8320
 8321    fn render_breakpoint(
 8322        &self,
 8323        position: Anchor,
 8324        row: DisplayRow,
 8325        breakpoint: &Breakpoint,
 8326        state: Option<BreakpointSessionState>,
 8327        cx: &mut Context<Self>,
 8328    ) -> IconButton {
 8329        let is_rejected = state.is_some_and(|s| !s.verified);
 8330        // Is it a breakpoint that shows up when hovering over gutter?
 8331        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8332            (false, false),
 8333            |PhantomBreakpointIndicator {
 8334                 is_active,
 8335                 display_row,
 8336                 collides_with_existing_breakpoint,
 8337             }| {
 8338                (
 8339                    is_active && display_row == row,
 8340                    collides_with_existing_breakpoint,
 8341                )
 8342            },
 8343        );
 8344
 8345        let (color, icon) = {
 8346            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8347                (false, false) => ui::IconName::DebugBreakpoint,
 8348                (true, false) => ui::IconName::DebugLogBreakpoint,
 8349                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8350                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8351            };
 8352
 8353            let color = if is_phantom {
 8354                Color::Hint
 8355            } else if is_rejected {
 8356                Color::Disabled
 8357            } else {
 8358                Color::Debugger
 8359            };
 8360
 8361            (color, icon)
 8362        };
 8363
 8364        let breakpoint = Arc::from(breakpoint.clone());
 8365
 8366        let alt_as_text = gpui::Keystroke {
 8367            modifiers: Modifiers::secondary_key(),
 8368            ..Default::default()
 8369        };
 8370        let primary_action_text = if breakpoint.is_disabled() {
 8371            "Enable breakpoint"
 8372        } else if is_phantom && !collides_with_existing {
 8373            "Set breakpoint"
 8374        } else {
 8375            "Unset breakpoint"
 8376        };
 8377        let focus_handle = self.focus_handle.clone();
 8378
 8379        let meta = if is_rejected {
 8380            SharedString::from("No executable code is associated with this line.")
 8381        } else if collides_with_existing && !breakpoint.is_disabled() {
 8382            SharedString::from(format!(
 8383                "{alt_as_text}-click to disable,\nright-click for more options."
 8384            ))
 8385        } else {
 8386            SharedString::from("Right-click for more options.")
 8387        };
 8388        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8389            .icon_size(IconSize::XSmall)
 8390            .size(ui::ButtonSize::None)
 8391            .when(is_rejected, |this| {
 8392                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8393            })
 8394            .icon_color(color)
 8395            .style(ButtonStyle::Transparent)
 8396            .on_click(cx.listener({
 8397                move |editor, event: &ClickEvent, window, cx| {
 8398                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8399                        BreakpointEditAction::InvertState
 8400                    } else {
 8401                        BreakpointEditAction::Toggle
 8402                    };
 8403
 8404                    window.focus(&editor.focus_handle(cx));
 8405                    editor.edit_breakpoint_at_anchor(
 8406                        position,
 8407                        breakpoint.as_ref().clone(),
 8408                        edit_action,
 8409                        cx,
 8410                    );
 8411                }
 8412            }))
 8413            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8414                editor.set_breakpoint_context_menu(
 8415                    row,
 8416                    Some(position),
 8417                    event.position(),
 8418                    window,
 8419                    cx,
 8420                );
 8421            }))
 8422            .tooltip(move |window, cx| {
 8423                Tooltip::with_meta_in(
 8424                    primary_action_text,
 8425                    Some(&ToggleBreakpoint),
 8426                    meta.clone(),
 8427                    &focus_handle,
 8428                    window,
 8429                    cx,
 8430                )
 8431            })
 8432    }
 8433
 8434    fn build_tasks_context(
 8435        project: &Entity<Project>,
 8436        buffer: &Entity<Buffer>,
 8437        buffer_row: u32,
 8438        tasks: &Arc<RunnableTasks>,
 8439        cx: &mut Context<Self>,
 8440    ) -> Task<Option<task::TaskContext>> {
 8441        let position = Point::new(buffer_row, tasks.column);
 8442        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8443        let location = Location {
 8444            buffer: buffer.clone(),
 8445            range: range_start..range_start,
 8446        };
 8447        // Fill in the environmental variables from the tree-sitter captures
 8448        let mut captured_task_variables = TaskVariables::default();
 8449        for (capture_name, value) in tasks.extra_variables.clone() {
 8450            captured_task_variables.insert(
 8451                task::VariableName::Custom(capture_name.into()),
 8452                value.clone(),
 8453            );
 8454        }
 8455        project.update(cx, |project, cx| {
 8456            project.task_store().update(cx, |task_store, cx| {
 8457                task_store.task_context_for_location(captured_task_variables, location, cx)
 8458            })
 8459        })
 8460    }
 8461
 8462    pub fn spawn_nearest_task(
 8463        &mut self,
 8464        action: &SpawnNearestTask,
 8465        window: &mut Window,
 8466        cx: &mut Context<Self>,
 8467    ) {
 8468        let Some((workspace, _)) = self.workspace.clone() else {
 8469            return;
 8470        };
 8471        let Some(project) = self.project.clone() else {
 8472            return;
 8473        };
 8474
 8475        // Try to find a closest, enclosing node using tree-sitter that has a task
 8476        let Some((buffer, buffer_row, tasks)) = self
 8477            .find_enclosing_node_task(cx)
 8478            // Or find the task that's closest in row-distance.
 8479            .or_else(|| self.find_closest_task(cx))
 8480        else {
 8481            return;
 8482        };
 8483
 8484        let reveal_strategy = action.reveal;
 8485        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8486        cx.spawn_in(window, async move |_, cx| {
 8487            let context = task_context.await?;
 8488            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8489
 8490            let resolved = &mut resolved_task.resolved;
 8491            resolved.reveal = reveal_strategy;
 8492
 8493            workspace
 8494                .update_in(cx, |workspace, window, cx| {
 8495                    workspace.schedule_resolved_task(
 8496                        task_source_kind,
 8497                        resolved_task,
 8498                        false,
 8499                        window,
 8500                        cx,
 8501                    );
 8502                })
 8503                .ok()
 8504        })
 8505        .detach();
 8506    }
 8507
 8508    fn find_closest_task(
 8509        &mut self,
 8510        cx: &mut Context<Self>,
 8511    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8512        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8513
 8514        let ((buffer_id, row), tasks) = self
 8515            .tasks
 8516            .iter()
 8517            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8518
 8519        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8520        let tasks = Arc::new(tasks.to_owned());
 8521        Some((buffer, *row, tasks))
 8522    }
 8523
 8524    fn find_enclosing_node_task(
 8525        &mut self,
 8526        cx: &mut Context<Self>,
 8527    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8528        let snapshot = self.buffer.read(cx).snapshot(cx);
 8529        let offset = self.selections.newest::<usize>(cx).head();
 8530        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8531        let buffer_id = excerpt.buffer().remote_id();
 8532
 8533        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8534        let mut cursor = layer.node().walk();
 8535
 8536        while cursor.goto_first_child_for_byte(offset).is_some() {
 8537            if cursor.node().end_byte() == offset {
 8538                cursor.goto_next_sibling();
 8539            }
 8540        }
 8541
 8542        // Ascend to the smallest ancestor that contains the range and has a task.
 8543        loop {
 8544            let node = cursor.node();
 8545            let node_range = node.byte_range();
 8546            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8547
 8548            // Check if this node contains our offset
 8549            if node_range.start <= offset && node_range.end >= offset {
 8550                // If it contains offset, check for task
 8551                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8552                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8553                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8554                }
 8555            }
 8556
 8557            if !cursor.goto_parent() {
 8558                break;
 8559            }
 8560        }
 8561        None
 8562    }
 8563
 8564    fn render_run_indicator(
 8565        &self,
 8566        _style: &EditorStyle,
 8567        is_active: bool,
 8568        row: DisplayRow,
 8569        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8570        cx: &mut Context<Self>,
 8571    ) -> IconButton {
 8572        let color = Color::Muted;
 8573        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8574
 8575        IconButton::new(
 8576            ("run_indicator", row.0 as usize),
 8577            ui::IconName::PlayOutlined,
 8578        )
 8579        .shape(ui::IconButtonShape::Square)
 8580        .icon_size(IconSize::XSmall)
 8581        .icon_color(color)
 8582        .toggle_state(is_active)
 8583        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8584            let quick_launch = match e {
 8585                ClickEvent::Keyboard(_) => true,
 8586                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8587            };
 8588
 8589            window.focus(&editor.focus_handle(cx));
 8590            editor.toggle_code_actions(
 8591                &ToggleCodeActions {
 8592                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8593                    quick_launch,
 8594                },
 8595                window,
 8596                cx,
 8597            );
 8598        }))
 8599        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8600            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8601        }))
 8602    }
 8603
 8604    pub fn context_menu_visible(&self) -> bool {
 8605        !self.edit_prediction_preview_is_active()
 8606            && self
 8607                .context_menu
 8608                .borrow()
 8609                .as_ref()
 8610                .is_some_and(|menu| menu.visible())
 8611    }
 8612
 8613    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8614        self.context_menu
 8615            .borrow()
 8616            .as_ref()
 8617            .map(|menu| menu.origin())
 8618    }
 8619
 8620    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8621        self.context_menu_options = Some(options);
 8622    }
 8623
 8624    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8625    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8626
 8627    fn render_edit_prediction_popover(
 8628        &mut self,
 8629        text_bounds: &Bounds<Pixels>,
 8630        content_origin: gpui::Point<Pixels>,
 8631        right_margin: Pixels,
 8632        editor_snapshot: &EditorSnapshot,
 8633        visible_row_range: Range<DisplayRow>,
 8634        scroll_top: ScrollOffset,
 8635        scroll_bottom: ScrollOffset,
 8636        line_layouts: &[LineWithInvisibles],
 8637        line_height: Pixels,
 8638        scroll_position: gpui::Point<ScrollOffset>,
 8639        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8640        newest_selection_head: Option<DisplayPoint>,
 8641        editor_width: Pixels,
 8642        style: &EditorStyle,
 8643        window: &mut Window,
 8644        cx: &mut App,
 8645    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8646        if self.mode().is_minimap() {
 8647            return None;
 8648        }
 8649        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8650
 8651        if self.edit_prediction_visible_in_cursor_popover(true) {
 8652            return None;
 8653        }
 8654
 8655        match &active_edit_prediction.completion {
 8656            EditPrediction::MoveWithin { target, .. } => {
 8657                let target_display_point = target.to_display_point(editor_snapshot);
 8658
 8659                if self.edit_prediction_requires_modifier() {
 8660                    if !self.edit_prediction_preview_is_active() {
 8661                        return None;
 8662                    }
 8663
 8664                    self.render_edit_prediction_modifier_jump_popover(
 8665                        text_bounds,
 8666                        content_origin,
 8667                        visible_row_range,
 8668                        line_layouts,
 8669                        line_height,
 8670                        scroll_pixel_position,
 8671                        newest_selection_head,
 8672                        target_display_point,
 8673                        window,
 8674                        cx,
 8675                    )
 8676                } else {
 8677                    self.render_edit_prediction_eager_jump_popover(
 8678                        text_bounds,
 8679                        content_origin,
 8680                        editor_snapshot,
 8681                        visible_row_range,
 8682                        scroll_top,
 8683                        scroll_bottom,
 8684                        line_height,
 8685                        scroll_pixel_position,
 8686                        target_display_point,
 8687                        editor_width,
 8688                        window,
 8689                        cx,
 8690                    )
 8691                }
 8692            }
 8693            EditPrediction::Edit {
 8694                display_mode: EditDisplayMode::Inline,
 8695                ..
 8696            } => None,
 8697            EditPrediction::Edit {
 8698                display_mode: EditDisplayMode::TabAccept,
 8699                edits,
 8700                ..
 8701            } => {
 8702                let range = &edits.first()?.0;
 8703                let target_display_point = range.end.to_display_point(editor_snapshot);
 8704
 8705                self.render_edit_prediction_end_of_line_popover(
 8706                    "Accept",
 8707                    editor_snapshot,
 8708                    visible_row_range,
 8709                    target_display_point,
 8710                    line_height,
 8711                    scroll_pixel_position,
 8712                    content_origin,
 8713                    editor_width,
 8714                    window,
 8715                    cx,
 8716                )
 8717            }
 8718            EditPrediction::Edit {
 8719                edits,
 8720                edit_preview,
 8721                display_mode: EditDisplayMode::DiffPopover,
 8722                snapshot,
 8723            } => self.render_edit_prediction_diff_popover(
 8724                text_bounds,
 8725                content_origin,
 8726                right_margin,
 8727                editor_snapshot,
 8728                visible_row_range,
 8729                line_layouts,
 8730                line_height,
 8731                scroll_position,
 8732                scroll_pixel_position,
 8733                newest_selection_head,
 8734                editor_width,
 8735                style,
 8736                edits,
 8737                edit_preview,
 8738                snapshot,
 8739                window,
 8740                cx,
 8741            ),
 8742            EditPrediction::MoveOutside { snapshot, .. } => {
 8743                let file_name = snapshot
 8744                    .file()
 8745                    .map(|file| file.file_name(cx))
 8746                    .unwrap_or("untitled");
 8747                let mut element = self
 8748                    .render_edit_prediction_line_popover(
 8749                        format!("Jump to {file_name}"),
 8750                        Some(IconName::ZedPredict),
 8751                        window,
 8752                        cx,
 8753                    )
 8754                    .into_any();
 8755
 8756                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8757                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8758                let origin_y = text_bounds.size.height - size.height - px(30.);
 8759                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8760                element.prepaint_at(origin, window, cx);
 8761
 8762                Some((element, origin))
 8763            }
 8764        }
 8765    }
 8766
 8767    fn render_edit_prediction_modifier_jump_popover(
 8768        &mut self,
 8769        text_bounds: &Bounds<Pixels>,
 8770        content_origin: gpui::Point<Pixels>,
 8771        visible_row_range: Range<DisplayRow>,
 8772        line_layouts: &[LineWithInvisibles],
 8773        line_height: Pixels,
 8774        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8775        newest_selection_head: Option<DisplayPoint>,
 8776        target_display_point: DisplayPoint,
 8777        window: &mut Window,
 8778        cx: &mut App,
 8779    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8780        let scrolled_content_origin =
 8781            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8782
 8783        const SCROLL_PADDING_Y: Pixels = px(12.);
 8784
 8785        if target_display_point.row() < visible_row_range.start {
 8786            return self.render_edit_prediction_scroll_popover(
 8787                |_| SCROLL_PADDING_Y,
 8788                IconName::ArrowUp,
 8789                visible_row_range,
 8790                line_layouts,
 8791                newest_selection_head,
 8792                scrolled_content_origin,
 8793                window,
 8794                cx,
 8795            );
 8796        } else if target_display_point.row() >= visible_row_range.end {
 8797            return self.render_edit_prediction_scroll_popover(
 8798                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8799                IconName::ArrowDown,
 8800                visible_row_range,
 8801                line_layouts,
 8802                newest_selection_head,
 8803                scrolled_content_origin,
 8804                window,
 8805                cx,
 8806            );
 8807        }
 8808
 8809        const POLE_WIDTH: Pixels = px(2.);
 8810
 8811        let line_layout =
 8812            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8813        let target_column = target_display_point.column() as usize;
 8814
 8815        let target_x = line_layout.x_for_index(target_column);
 8816        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8817            - scroll_pixel_position.y;
 8818
 8819        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8820
 8821        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8822        border_color.l += 0.001;
 8823
 8824        let mut element = v_flex()
 8825            .items_end()
 8826            .when(flag_on_right, |el| el.items_start())
 8827            .child(if flag_on_right {
 8828                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8829                    .rounded_bl(px(0.))
 8830                    .rounded_tl(px(0.))
 8831                    .border_l_2()
 8832                    .border_color(border_color)
 8833            } else {
 8834                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8835                    .rounded_br(px(0.))
 8836                    .rounded_tr(px(0.))
 8837                    .border_r_2()
 8838                    .border_color(border_color)
 8839            })
 8840            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8841            .into_any();
 8842
 8843        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8844
 8845        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8846            - point(
 8847                if flag_on_right {
 8848                    POLE_WIDTH
 8849                } else {
 8850                    size.width - POLE_WIDTH
 8851                },
 8852                size.height - line_height,
 8853            );
 8854
 8855        origin.x = origin.x.max(content_origin.x);
 8856
 8857        element.prepaint_at(origin, window, cx);
 8858
 8859        Some((element, origin))
 8860    }
 8861
 8862    fn render_edit_prediction_scroll_popover(
 8863        &mut self,
 8864        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8865        scroll_icon: IconName,
 8866        visible_row_range: Range<DisplayRow>,
 8867        line_layouts: &[LineWithInvisibles],
 8868        newest_selection_head: Option<DisplayPoint>,
 8869        scrolled_content_origin: gpui::Point<Pixels>,
 8870        window: &mut Window,
 8871        cx: &mut App,
 8872    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8873        let mut element = self
 8874            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8875            .into_any();
 8876
 8877        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8878
 8879        let cursor = newest_selection_head?;
 8880        let cursor_row_layout =
 8881            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8882        let cursor_column = cursor.column() as usize;
 8883
 8884        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8885
 8886        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8887
 8888        element.prepaint_at(origin, window, cx);
 8889        Some((element, origin))
 8890    }
 8891
 8892    fn render_edit_prediction_eager_jump_popover(
 8893        &mut self,
 8894        text_bounds: &Bounds<Pixels>,
 8895        content_origin: gpui::Point<Pixels>,
 8896        editor_snapshot: &EditorSnapshot,
 8897        visible_row_range: Range<DisplayRow>,
 8898        scroll_top: ScrollOffset,
 8899        scroll_bottom: ScrollOffset,
 8900        line_height: Pixels,
 8901        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8902        target_display_point: DisplayPoint,
 8903        editor_width: Pixels,
 8904        window: &mut Window,
 8905        cx: &mut App,
 8906    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8907        if target_display_point.row().as_f64() < scroll_top {
 8908            let mut element = self
 8909                .render_edit_prediction_line_popover(
 8910                    "Jump to Edit",
 8911                    Some(IconName::ArrowUp),
 8912                    window,
 8913                    cx,
 8914                )
 8915                .into_any();
 8916
 8917            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8918            let offset = point(
 8919                (text_bounds.size.width - size.width) / 2.,
 8920                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8921            );
 8922
 8923            let origin = text_bounds.origin + offset;
 8924            element.prepaint_at(origin, window, cx);
 8925            Some((element, origin))
 8926        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8927            let mut element = self
 8928                .render_edit_prediction_line_popover(
 8929                    "Jump to Edit",
 8930                    Some(IconName::ArrowDown),
 8931                    window,
 8932                    cx,
 8933                )
 8934                .into_any();
 8935
 8936            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8937            let offset = point(
 8938                (text_bounds.size.width - size.width) / 2.,
 8939                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8940            );
 8941
 8942            let origin = text_bounds.origin + offset;
 8943            element.prepaint_at(origin, window, cx);
 8944            Some((element, origin))
 8945        } else {
 8946            self.render_edit_prediction_end_of_line_popover(
 8947                "Jump to Edit",
 8948                editor_snapshot,
 8949                visible_row_range,
 8950                target_display_point,
 8951                line_height,
 8952                scroll_pixel_position,
 8953                content_origin,
 8954                editor_width,
 8955                window,
 8956                cx,
 8957            )
 8958        }
 8959    }
 8960
 8961    fn render_edit_prediction_end_of_line_popover(
 8962        self: &mut Editor,
 8963        label: &'static str,
 8964        editor_snapshot: &EditorSnapshot,
 8965        visible_row_range: Range<DisplayRow>,
 8966        target_display_point: DisplayPoint,
 8967        line_height: Pixels,
 8968        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8969        content_origin: gpui::Point<Pixels>,
 8970        editor_width: Pixels,
 8971        window: &mut Window,
 8972        cx: &mut App,
 8973    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8974        let target_line_end = DisplayPoint::new(
 8975            target_display_point.row(),
 8976            editor_snapshot.line_len(target_display_point.row()),
 8977        );
 8978
 8979        let mut element = self
 8980            .render_edit_prediction_line_popover(label, None, window, cx)
 8981            .into_any();
 8982
 8983        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8984
 8985        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8986
 8987        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8988        let mut origin = start_point
 8989            + line_origin
 8990            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8991        origin.x = origin.x.max(content_origin.x);
 8992
 8993        let max_x = content_origin.x + editor_width - size.width;
 8994
 8995        if origin.x > max_x {
 8996            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8997
 8998            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8999                origin.y += offset;
 9000                IconName::ArrowUp
 9001            } else {
 9002                origin.y -= offset;
 9003                IconName::ArrowDown
 9004            };
 9005
 9006            element = self
 9007                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9008                .into_any();
 9009
 9010            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9011
 9012            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9013        }
 9014
 9015        element.prepaint_at(origin, window, cx);
 9016        Some((element, origin))
 9017    }
 9018
 9019    fn render_edit_prediction_diff_popover(
 9020        self: &Editor,
 9021        text_bounds: &Bounds<Pixels>,
 9022        content_origin: gpui::Point<Pixels>,
 9023        right_margin: Pixels,
 9024        editor_snapshot: &EditorSnapshot,
 9025        visible_row_range: Range<DisplayRow>,
 9026        line_layouts: &[LineWithInvisibles],
 9027        line_height: Pixels,
 9028        scroll_position: gpui::Point<ScrollOffset>,
 9029        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9030        newest_selection_head: Option<DisplayPoint>,
 9031        editor_width: Pixels,
 9032        style: &EditorStyle,
 9033        edits: &Vec<(Range<Anchor>, String)>,
 9034        edit_preview: &Option<language::EditPreview>,
 9035        snapshot: &language::BufferSnapshot,
 9036        window: &mut Window,
 9037        cx: &mut App,
 9038    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9039        let edit_start = edits
 9040            .first()
 9041            .unwrap()
 9042            .0
 9043            .start
 9044            .to_display_point(editor_snapshot);
 9045        let edit_end = edits
 9046            .last()
 9047            .unwrap()
 9048            .0
 9049            .end
 9050            .to_display_point(editor_snapshot);
 9051
 9052        let is_visible = visible_row_range.contains(&edit_start.row())
 9053            || visible_row_range.contains(&edit_end.row());
 9054        if !is_visible {
 9055            return None;
 9056        }
 9057
 9058        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9059            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9060        } else {
 9061            // Fallback for providers without edit_preview
 9062            crate::edit_prediction_fallback_text(edits, cx)
 9063        };
 9064
 9065        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9066        let line_count = highlighted_edits.text.lines().count();
 9067
 9068        const BORDER_WIDTH: Pixels = px(1.);
 9069
 9070        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9071        let has_keybind = keybind.is_some();
 9072
 9073        let mut element = h_flex()
 9074            .items_start()
 9075            .child(
 9076                h_flex()
 9077                    .bg(cx.theme().colors().editor_background)
 9078                    .border(BORDER_WIDTH)
 9079                    .shadow_xs()
 9080                    .border_color(cx.theme().colors().border)
 9081                    .rounded_l_lg()
 9082                    .when(line_count > 1, |el| el.rounded_br_lg())
 9083                    .pr_1()
 9084                    .child(styled_text),
 9085            )
 9086            .child(
 9087                h_flex()
 9088                    .h(line_height + BORDER_WIDTH * 2.)
 9089                    .px_1p5()
 9090                    .gap_1()
 9091                    // Workaround: For some reason, there's a gap if we don't do this
 9092                    .ml(-BORDER_WIDTH)
 9093                    .shadow(vec![gpui::BoxShadow {
 9094                        color: gpui::black().opacity(0.05),
 9095                        offset: point(px(1.), px(1.)),
 9096                        blur_radius: px(2.),
 9097                        spread_radius: px(0.),
 9098                    }])
 9099                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9100                    .border(BORDER_WIDTH)
 9101                    .border_color(cx.theme().colors().border)
 9102                    .rounded_r_lg()
 9103                    .id("edit_prediction_diff_popover_keybind")
 9104                    .when(!has_keybind, |el| {
 9105                        let status_colors = cx.theme().status();
 9106
 9107                        el.bg(status_colors.error_background)
 9108                            .border_color(status_colors.error.opacity(0.6))
 9109                            .child(Icon::new(IconName::Info).color(Color::Error))
 9110                            .cursor_default()
 9111                            .hoverable_tooltip(move |_window, cx| {
 9112                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9113                            })
 9114                    })
 9115                    .children(keybind),
 9116            )
 9117            .into_any();
 9118
 9119        let longest_row =
 9120            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9121        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9122            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9123        } else {
 9124            layout_line(
 9125                longest_row,
 9126                editor_snapshot,
 9127                style,
 9128                editor_width,
 9129                |_| false,
 9130                window,
 9131                cx,
 9132            )
 9133            .width
 9134        };
 9135
 9136        let viewport_bounds =
 9137            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9138                right: -right_margin,
 9139                ..Default::default()
 9140            });
 9141
 9142        let x_after_longest = Pixels::from(
 9143            ScrollPixelOffset::from(
 9144                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9145            ) - scroll_pixel_position.x,
 9146        );
 9147
 9148        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9149
 9150        // Fully visible if it can be displayed within the window (allow overlapping other
 9151        // panes). However, this is only allowed if the popover starts within text_bounds.
 9152        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9153            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9154
 9155        let mut origin = if can_position_to_the_right {
 9156            point(
 9157                x_after_longest,
 9158                text_bounds.origin.y
 9159                    + Pixels::from(
 9160                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9161                            - scroll_pixel_position.y,
 9162                    ),
 9163            )
 9164        } else {
 9165            let cursor_row = newest_selection_head.map(|head| head.row());
 9166            let above_edit = edit_start
 9167                .row()
 9168                .0
 9169                .checked_sub(line_count as u32)
 9170                .map(DisplayRow);
 9171            let below_edit = Some(edit_end.row() + 1);
 9172            let above_cursor =
 9173                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9174            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9175
 9176            // Place the edit popover adjacent to the edit if there is a location
 9177            // available that is onscreen and does not obscure the cursor. Otherwise,
 9178            // place it adjacent to the cursor.
 9179            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9180                .into_iter()
 9181                .flatten()
 9182                .find(|&start_row| {
 9183                    let end_row = start_row + line_count as u32;
 9184                    visible_row_range.contains(&start_row)
 9185                        && visible_row_range.contains(&end_row)
 9186                        && cursor_row
 9187                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9188                })?;
 9189
 9190            content_origin
 9191                + point(
 9192                    Pixels::from(-scroll_pixel_position.x),
 9193                    Pixels::from(
 9194                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9195                    ),
 9196                )
 9197        };
 9198
 9199        origin.x -= BORDER_WIDTH;
 9200
 9201        window.defer_draw(element, origin, 1);
 9202
 9203        // Do not return an element, since it will already be drawn due to defer_draw.
 9204        None
 9205    }
 9206
 9207    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9208        px(30.)
 9209    }
 9210
 9211    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9212        if self.read_only(cx) {
 9213            cx.theme().players().read_only()
 9214        } else {
 9215            self.style.as_ref().unwrap().local_player
 9216        }
 9217    }
 9218
 9219    fn render_edit_prediction_accept_keybind(
 9220        &self,
 9221        window: &mut Window,
 9222        cx: &App,
 9223    ) -> Option<AnyElement> {
 9224        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9225        let accept_keystroke = accept_binding.keystroke()?;
 9226
 9227        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9228
 9229        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9230            Color::Accent
 9231        } else {
 9232            Color::Muted
 9233        };
 9234
 9235        h_flex()
 9236            .px_0p5()
 9237            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9238            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9239            .text_size(TextSize::XSmall.rems(cx))
 9240            .child(h_flex().children(ui::render_modifiers(
 9241                accept_keystroke.modifiers(),
 9242                PlatformStyle::platform(),
 9243                Some(modifiers_color),
 9244                Some(IconSize::XSmall.rems().into()),
 9245                true,
 9246            )))
 9247            .when(is_platform_style_mac, |parent| {
 9248                parent.child(accept_keystroke.key().to_string())
 9249            })
 9250            .when(!is_platform_style_mac, |parent| {
 9251                parent.child(
 9252                    Key::new(
 9253                        util::capitalize(accept_keystroke.key()),
 9254                        Some(Color::Default),
 9255                    )
 9256                    .size(Some(IconSize::XSmall.rems().into())),
 9257                )
 9258            })
 9259            .into_any()
 9260            .into()
 9261    }
 9262
 9263    fn render_edit_prediction_line_popover(
 9264        &self,
 9265        label: impl Into<SharedString>,
 9266        icon: Option<IconName>,
 9267        window: &mut Window,
 9268        cx: &App,
 9269    ) -> Stateful<Div> {
 9270        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9271
 9272        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9273        let has_keybind = keybind.is_some();
 9274
 9275        h_flex()
 9276            .id("ep-line-popover")
 9277            .py_0p5()
 9278            .pl_1()
 9279            .pr(padding_right)
 9280            .gap_1()
 9281            .rounded_md()
 9282            .border_1()
 9283            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9284            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9285            .shadow_xs()
 9286            .when(!has_keybind, |el| {
 9287                let status_colors = cx.theme().status();
 9288
 9289                el.bg(status_colors.error_background)
 9290                    .border_color(status_colors.error.opacity(0.6))
 9291                    .pl_2()
 9292                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9293                    .cursor_default()
 9294                    .hoverable_tooltip(move |_window, cx| {
 9295                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9296                    })
 9297            })
 9298            .children(keybind)
 9299            .child(
 9300                Label::new(label)
 9301                    .size(LabelSize::Small)
 9302                    .when(!has_keybind, |el| {
 9303                        el.color(cx.theme().status().error.into()).strikethrough()
 9304                    }),
 9305            )
 9306            .when(!has_keybind, |el| {
 9307                el.child(
 9308                    h_flex().ml_1().child(
 9309                        Icon::new(IconName::Info)
 9310                            .size(IconSize::Small)
 9311                            .color(cx.theme().status().error.into()),
 9312                    ),
 9313                )
 9314            })
 9315            .when_some(icon, |element, icon| {
 9316                element.child(
 9317                    div()
 9318                        .mt(px(1.5))
 9319                        .child(Icon::new(icon).size(IconSize::Small)),
 9320                )
 9321            })
 9322    }
 9323
 9324    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9325        let accent_color = cx.theme().colors().text_accent;
 9326        let editor_bg_color = cx.theme().colors().editor_background;
 9327        editor_bg_color.blend(accent_color.opacity(0.1))
 9328    }
 9329
 9330    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9331        let accent_color = cx.theme().colors().text_accent;
 9332        let editor_bg_color = cx.theme().colors().editor_background;
 9333        editor_bg_color.blend(accent_color.opacity(0.6))
 9334    }
 9335    fn get_prediction_provider_icon_name(
 9336        provider: &Option<RegisteredEditPredictionProvider>,
 9337    ) -> IconName {
 9338        match provider {
 9339            Some(provider) => match provider.provider.name() {
 9340                "copilot" => IconName::Copilot,
 9341                "supermaven" => IconName::Supermaven,
 9342                _ => IconName::ZedPredict,
 9343            },
 9344            None => IconName::ZedPredict,
 9345        }
 9346    }
 9347
 9348    fn render_edit_prediction_cursor_popover(
 9349        &self,
 9350        min_width: Pixels,
 9351        max_width: Pixels,
 9352        cursor_point: Point,
 9353        style: &EditorStyle,
 9354        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9355        _window: &Window,
 9356        cx: &mut Context<Editor>,
 9357    ) -> Option<AnyElement> {
 9358        let provider = self.edit_prediction_provider.as_ref()?;
 9359        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9360
 9361        let is_refreshing = provider.provider.is_refreshing(cx);
 9362
 9363        fn pending_completion_container(icon: IconName) -> Div {
 9364            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9365        }
 9366
 9367        let completion = match &self.active_edit_prediction {
 9368            Some(prediction) => {
 9369                if !self.has_visible_completions_menu() {
 9370                    const RADIUS: Pixels = px(6.);
 9371                    const BORDER_WIDTH: Pixels = px(1.);
 9372
 9373                    return Some(
 9374                        h_flex()
 9375                            .elevation_2(cx)
 9376                            .border(BORDER_WIDTH)
 9377                            .border_color(cx.theme().colors().border)
 9378                            .when(accept_keystroke.is_none(), |el| {
 9379                                el.border_color(cx.theme().status().error)
 9380                            })
 9381                            .rounded(RADIUS)
 9382                            .rounded_tl(px(0.))
 9383                            .overflow_hidden()
 9384                            .child(div().px_1p5().child(match &prediction.completion {
 9385                                EditPrediction::MoveWithin { target, snapshot } => {
 9386                                    use text::ToPoint as _;
 9387                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9388                                    {
 9389                                        Icon::new(IconName::ZedPredictDown)
 9390                                    } else {
 9391                                        Icon::new(IconName::ZedPredictUp)
 9392                                    }
 9393                                }
 9394                                EditPrediction::MoveOutside { .. } => {
 9395                                    // TODO [zeta2] custom icon for external jump?
 9396                                    Icon::new(provider_icon)
 9397                                }
 9398                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9399                            }))
 9400                            .child(
 9401                                h_flex()
 9402                                    .gap_1()
 9403                                    .py_1()
 9404                                    .px_2()
 9405                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9406                                    .border_l_1()
 9407                                    .border_color(cx.theme().colors().border)
 9408                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9409                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9410                                        el.child(
 9411                                            Label::new("Hold")
 9412                                                .size(LabelSize::Small)
 9413                                                .when(accept_keystroke.is_none(), |el| {
 9414                                                    el.strikethrough()
 9415                                                })
 9416                                                .line_height_style(LineHeightStyle::UiLabel),
 9417                                        )
 9418                                    })
 9419                                    .id("edit_prediction_cursor_popover_keybind")
 9420                                    .when(accept_keystroke.is_none(), |el| {
 9421                                        let status_colors = cx.theme().status();
 9422
 9423                                        el.bg(status_colors.error_background)
 9424                                            .border_color(status_colors.error.opacity(0.6))
 9425                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9426                                            .cursor_default()
 9427                                            .hoverable_tooltip(move |_window, cx| {
 9428                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9429                                                    .into()
 9430                                            })
 9431                                    })
 9432                                    .when_some(
 9433                                        accept_keystroke.as_ref(),
 9434                                        |el, accept_keystroke| {
 9435                                            el.child(h_flex().children(ui::render_modifiers(
 9436                                                accept_keystroke.modifiers(),
 9437                                                PlatformStyle::platform(),
 9438                                                Some(Color::Default),
 9439                                                Some(IconSize::XSmall.rems().into()),
 9440                                                false,
 9441                                            )))
 9442                                        },
 9443                                    ),
 9444                            )
 9445                            .into_any(),
 9446                    );
 9447                }
 9448
 9449                self.render_edit_prediction_cursor_popover_preview(
 9450                    prediction,
 9451                    cursor_point,
 9452                    style,
 9453                    cx,
 9454                )?
 9455            }
 9456
 9457            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9458                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9459                    stale_completion,
 9460                    cursor_point,
 9461                    style,
 9462                    cx,
 9463                )?,
 9464
 9465                None => pending_completion_container(provider_icon)
 9466                    .child(Label::new("...").size(LabelSize::Small)),
 9467            },
 9468
 9469            None => pending_completion_container(provider_icon)
 9470                .child(Label::new("...").size(LabelSize::Small)),
 9471        };
 9472
 9473        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9474            completion
 9475                .with_animation(
 9476                    "loading-completion",
 9477                    Animation::new(Duration::from_secs(2))
 9478                        .repeat()
 9479                        .with_easing(pulsating_between(0.4, 0.8)),
 9480                    |label, delta| label.opacity(delta),
 9481                )
 9482                .into_any_element()
 9483        } else {
 9484            completion.into_any_element()
 9485        };
 9486
 9487        let has_completion = self.active_edit_prediction.is_some();
 9488
 9489        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9490        Some(
 9491            h_flex()
 9492                .min_w(min_width)
 9493                .max_w(max_width)
 9494                .flex_1()
 9495                .elevation_2(cx)
 9496                .border_color(cx.theme().colors().border)
 9497                .child(
 9498                    div()
 9499                        .flex_1()
 9500                        .py_1()
 9501                        .px_2()
 9502                        .overflow_hidden()
 9503                        .child(completion),
 9504                )
 9505                .when_some(accept_keystroke, |el, accept_keystroke| {
 9506                    if !accept_keystroke.modifiers().modified() {
 9507                        return el;
 9508                    }
 9509
 9510                    el.child(
 9511                        h_flex()
 9512                            .h_full()
 9513                            .border_l_1()
 9514                            .rounded_r_lg()
 9515                            .border_color(cx.theme().colors().border)
 9516                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9517                            .gap_1()
 9518                            .py_1()
 9519                            .px_2()
 9520                            .child(
 9521                                h_flex()
 9522                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9523                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9524                                    .child(h_flex().children(ui::render_modifiers(
 9525                                        accept_keystroke.modifiers(),
 9526                                        PlatformStyle::platform(),
 9527                                        Some(if !has_completion {
 9528                                            Color::Muted
 9529                                        } else {
 9530                                            Color::Default
 9531                                        }),
 9532                                        None,
 9533                                        false,
 9534                                    ))),
 9535                            )
 9536                            .child(Label::new("Preview").into_any_element())
 9537                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9538                    )
 9539                })
 9540                .into_any(),
 9541        )
 9542    }
 9543
 9544    fn render_edit_prediction_cursor_popover_preview(
 9545        &self,
 9546        completion: &EditPredictionState,
 9547        cursor_point: Point,
 9548        style: &EditorStyle,
 9549        cx: &mut Context<Editor>,
 9550    ) -> Option<Div> {
 9551        use text::ToPoint as _;
 9552
 9553        fn render_relative_row_jump(
 9554            prefix: impl Into<String>,
 9555            current_row: u32,
 9556            target_row: u32,
 9557        ) -> Div {
 9558            let (row_diff, arrow) = if target_row < current_row {
 9559                (current_row - target_row, IconName::ArrowUp)
 9560            } else {
 9561                (target_row - current_row, IconName::ArrowDown)
 9562            };
 9563
 9564            h_flex()
 9565                .child(
 9566                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9567                        .color(Color::Muted)
 9568                        .size(LabelSize::Small),
 9569                )
 9570                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9571        }
 9572
 9573        let supports_jump = self
 9574            .edit_prediction_provider
 9575            .as_ref()
 9576            .map(|provider| provider.provider.supports_jump_to_edit())
 9577            .unwrap_or(true);
 9578
 9579        match &completion.completion {
 9580            EditPrediction::MoveWithin {
 9581                target, snapshot, ..
 9582            } => {
 9583                if !supports_jump {
 9584                    return None;
 9585                }
 9586
 9587                Some(
 9588                    h_flex()
 9589                        .px_2()
 9590                        .gap_2()
 9591                        .flex_1()
 9592                        .child(
 9593                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9594                                Icon::new(IconName::ZedPredictDown)
 9595                            } else {
 9596                                Icon::new(IconName::ZedPredictUp)
 9597                            },
 9598                        )
 9599                        .child(Label::new("Jump to Edit")),
 9600                )
 9601            }
 9602            EditPrediction::MoveOutside { snapshot, .. } => {
 9603                let file_name = snapshot
 9604                    .file()
 9605                    .map(|file| file.file_name(cx))
 9606                    .unwrap_or("untitled");
 9607                Some(
 9608                    h_flex()
 9609                        .px_2()
 9610                        .gap_2()
 9611                        .flex_1()
 9612                        .child(Icon::new(IconName::ZedPredict))
 9613                        .child(Label::new(format!("Jump to {file_name}"))),
 9614                )
 9615            }
 9616            EditPrediction::Edit {
 9617                edits,
 9618                edit_preview,
 9619                snapshot,
 9620                display_mode: _,
 9621            } => {
 9622                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9623
 9624                let (highlighted_edits, has_more_lines) =
 9625                    if let Some(edit_preview) = edit_preview.as_ref() {
 9626                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9627                            .first_line_preview()
 9628                    } else {
 9629                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9630                    };
 9631
 9632                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9633                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9634
 9635                let preview = h_flex()
 9636                    .gap_1()
 9637                    .min_w_16()
 9638                    .child(styled_text)
 9639                    .when(has_more_lines, |parent| parent.child(""));
 9640
 9641                let left = if supports_jump && first_edit_row != cursor_point.row {
 9642                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9643                        .into_any_element()
 9644                } else {
 9645                    let icon_name =
 9646                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9647                    Icon::new(icon_name).into_any_element()
 9648                };
 9649
 9650                Some(
 9651                    h_flex()
 9652                        .h_full()
 9653                        .flex_1()
 9654                        .gap_2()
 9655                        .pr_1()
 9656                        .overflow_x_hidden()
 9657                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9658                        .child(left)
 9659                        .child(preview),
 9660                )
 9661            }
 9662        }
 9663    }
 9664
 9665    pub fn render_context_menu(
 9666        &self,
 9667        style: &EditorStyle,
 9668        max_height_in_lines: u32,
 9669        window: &mut Window,
 9670        cx: &mut Context<Editor>,
 9671    ) -> Option<AnyElement> {
 9672        let menu = self.context_menu.borrow();
 9673        let menu = menu.as_ref()?;
 9674        if !menu.visible() {
 9675            return None;
 9676        };
 9677        Some(menu.render(style, max_height_in_lines, window, cx))
 9678    }
 9679
 9680    fn render_context_menu_aside(
 9681        &mut self,
 9682        max_size: Size<Pixels>,
 9683        window: &mut Window,
 9684        cx: &mut Context<Editor>,
 9685    ) -> Option<AnyElement> {
 9686        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9687            if menu.visible() {
 9688                menu.render_aside(max_size, window, cx)
 9689            } else {
 9690                None
 9691            }
 9692        })
 9693    }
 9694
 9695    fn hide_context_menu(
 9696        &mut self,
 9697        window: &mut Window,
 9698        cx: &mut Context<Self>,
 9699    ) -> Option<CodeContextMenu> {
 9700        cx.notify();
 9701        self.completion_tasks.clear();
 9702        let context_menu = self.context_menu.borrow_mut().take();
 9703        self.stale_edit_prediction_in_menu.take();
 9704        self.update_visible_edit_prediction(window, cx);
 9705        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9706            && let Some(completion_provider) = &self.completion_provider
 9707        {
 9708            completion_provider.selection_changed(None, window, cx);
 9709        }
 9710        context_menu
 9711    }
 9712
 9713    fn show_snippet_choices(
 9714        &mut self,
 9715        choices: &Vec<String>,
 9716        selection: Range<Anchor>,
 9717        cx: &mut Context<Self>,
 9718    ) {
 9719        let Some((_, buffer, _)) = self
 9720            .buffer()
 9721            .read(cx)
 9722            .excerpt_containing(selection.start, cx)
 9723        else {
 9724            return;
 9725        };
 9726        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9727        else {
 9728            return;
 9729        };
 9730        if buffer != end_buffer {
 9731            log::error!("expected anchor range to have matching buffer IDs");
 9732            return;
 9733        }
 9734
 9735        let id = post_inc(&mut self.next_completion_id);
 9736        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9737        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9738            CompletionsMenu::new_snippet_choices(
 9739                id,
 9740                true,
 9741                choices,
 9742                selection,
 9743                buffer,
 9744                snippet_sort_order,
 9745            ),
 9746        ));
 9747    }
 9748
 9749    pub fn insert_snippet(
 9750        &mut self,
 9751        insertion_ranges: &[Range<usize>],
 9752        snippet: Snippet,
 9753        window: &mut Window,
 9754        cx: &mut Context<Self>,
 9755    ) -> Result<()> {
 9756        struct Tabstop<T> {
 9757            is_end_tabstop: bool,
 9758            ranges: Vec<Range<T>>,
 9759            choices: Option<Vec<String>>,
 9760        }
 9761
 9762        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9763            let snippet_text: Arc<str> = snippet.text.clone().into();
 9764            let edits = insertion_ranges
 9765                .iter()
 9766                .cloned()
 9767                .map(|range| (range, snippet_text.clone()));
 9768            let autoindent_mode = AutoindentMode::Block {
 9769                original_indent_columns: Vec::new(),
 9770            };
 9771            buffer.edit(edits, Some(autoindent_mode), cx);
 9772
 9773            let snapshot = &*buffer.read(cx);
 9774            let snippet = &snippet;
 9775            snippet
 9776                .tabstops
 9777                .iter()
 9778                .map(|tabstop| {
 9779                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9780                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9781                    });
 9782                    let mut tabstop_ranges = tabstop
 9783                        .ranges
 9784                        .iter()
 9785                        .flat_map(|tabstop_range| {
 9786                            let mut delta = 0_isize;
 9787                            insertion_ranges.iter().map(move |insertion_range| {
 9788                                let insertion_start = insertion_range.start as isize + delta;
 9789                                delta +=
 9790                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9791
 9792                                let start = ((insertion_start + tabstop_range.start) as usize)
 9793                                    .min(snapshot.len());
 9794                                let end = ((insertion_start + tabstop_range.end) as usize)
 9795                                    .min(snapshot.len());
 9796                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9797                            })
 9798                        })
 9799                        .collect::<Vec<_>>();
 9800                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9801
 9802                    Tabstop {
 9803                        is_end_tabstop,
 9804                        ranges: tabstop_ranges,
 9805                        choices: tabstop.choices.clone(),
 9806                    }
 9807                })
 9808                .collect::<Vec<_>>()
 9809        });
 9810        if let Some(tabstop) = tabstops.first() {
 9811            self.change_selections(Default::default(), window, cx, |s| {
 9812                // Reverse order so that the first range is the newest created selection.
 9813                // Completions will use it and autoscroll will prioritize it.
 9814                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9815            });
 9816
 9817            if let Some(choices) = &tabstop.choices
 9818                && let Some(selection) = tabstop.ranges.first()
 9819            {
 9820                self.show_snippet_choices(choices, selection.clone(), cx)
 9821            }
 9822
 9823            // If we're already at the last tabstop and it's at the end of the snippet,
 9824            // we're done, we don't need to keep the state around.
 9825            if !tabstop.is_end_tabstop {
 9826                let choices = tabstops
 9827                    .iter()
 9828                    .map(|tabstop| tabstop.choices.clone())
 9829                    .collect();
 9830
 9831                let ranges = tabstops
 9832                    .into_iter()
 9833                    .map(|tabstop| tabstop.ranges)
 9834                    .collect::<Vec<_>>();
 9835
 9836                self.snippet_stack.push(SnippetState {
 9837                    active_index: 0,
 9838                    ranges,
 9839                    choices,
 9840                });
 9841            }
 9842
 9843            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9844            if self.autoclose_regions.is_empty() {
 9845                let snapshot = self.buffer.read(cx).snapshot(cx);
 9846                let mut all_selections = self.selections.all::<Point>(cx);
 9847                for selection in &mut all_selections {
 9848                    let selection_head = selection.head();
 9849                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9850                        continue;
 9851                    };
 9852
 9853                    let mut bracket_pair = None;
 9854                    let max_lookup_length = scope
 9855                        .brackets()
 9856                        .map(|(pair, _)| {
 9857                            pair.start
 9858                                .as_str()
 9859                                .chars()
 9860                                .count()
 9861                                .max(pair.end.as_str().chars().count())
 9862                        })
 9863                        .max();
 9864                    if let Some(max_lookup_length) = max_lookup_length {
 9865                        let next_text = snapshot
 9866                            .chars_at(selection_head)
 9867                            .take(max_lookup_length)
 9868                            .collect::<String>();
 9869                        let prev_text = snapshot
 9870                            .reversed_chars_at(selection_head)
 9871                            .take(max_lookup_length)
 9872                            .collect::<String>();
 9873
 9874                        for (pair, enabled) in scope.brackets() {
 9875                            if enabled
 9876                                && pair.close
 9877                                && prev_text.starts_with(pair.start.as_str())
 9878                                && next_text.starts_with(pair.end.as_str())
 9879                            {
 9880                                bracket_pair = Some(pair.clone());
 9881                                break;
 9882                            }
 9883                        }
 9884                    }
 9885
 9886                    if let Some(pair) = bracket_pair {
 9887                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9888                        let autoclose_enabled =
 9889                            self.use_autoclose && snapshot_settings.use_autoclose;
 9890                        if autoclose_enabled {
 9891                            let start = snapshot.anchor_after(selection_head);
 9892                            let end = snapshot.anchor_after(selection_head);
 9893                            self.autoclose_regions.push(AutocloseRegion {
 9894                                selection_id: selection.id,
 9895                                range: start..end,
 9896                                pair,
 9897                            });
 9898                        }
 9899                    }
 9900                }
 9901            }
 9902        }
 9903        Ok(())
 9904    }
 9905
 9906    pub fn move_to_next_snippet_tabstop(
 9907        &mut self,
 9908        window: &mut Window,
 9909        cx: &mut Context<Self>,
 9910    ) -> bool {
 9911        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9912    }
 9913
 9914    pub fn move_to_prev_snippet_tabstop(
 9915        &mut self,
 9916        window: &mut Window,
 9917        cx: &mut Context<Self>,
 9918    ) -> bool {
 9919        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9920    }
 9921
 9922    pub fn move_to_snippet_tabstop(
 9923        &mut self,
 9924        bias: Bias,
 9925        window: &mut Window,
 9926        cx: &mut Context<Self>,
 9927    ) -> bool {
 9928        if let Some(mut snippet) = self.snippet_stack.pop() {
 9929            match bias {
 9930                Bias::Left => {
 9931                    if snippet.active_index > 0 {
 9932                        snippet.active_index -= 1;
 9933                    } else {
 9934                        self.snippet_stack.push(snippet);
 9935                        return false;
 9936                    }
 9937                }
 9938                Bias::Right => {
 9939                    if snippet.active_index + 1 < snippet.ranges.len() {
 9940                        snippet.active_index += 1;
 9941                    } else {
 9942                        self.snippet_stack.push(snippet);
 9943                        return false;
 9944                    }
 9945                }
 9946            }
 9947            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9948                self.change_selections(Default::default(), window, cx, |s| {
 9949                    // Reverse order so that the first range is the newest created selection.
 9950                    // Completions will use it and autoscroll will prioritize it.
 9951                    s.select_ranges(current_ranges.iter().rev().cloned())
 9952                });
 9953
 9954                if let Some(choices) = &snippet.choices[snippet.active_index]
 9955                    && let Some(selection) = current_ranges.first()
 9956                {
 9957                    self.show_snippet_choices(choices, selection.clone(), cx);
 9958                }
 9959
 9960                // If snippet state is not at the last tabstop, push it back on the stack
 9961                if snippet.active_index + 1 < snippet.ranges.len() {
 9962                    self.snippet_stack.push(snippet);
 9963                }
 9964                return true;
 9965            }
 9966        }
 9967
 9968        false
 9969    }
 9970
 9971    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9972        self.transact(window, cx, |this, window, cx| {
 9973            this.select_all(&SelectAll, window, cx);
 9974            this.insert("", window, cx);
 9975        });
 9976    }
 9977
 9978    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9979        if self.read_only(cx) {
 9980            return;
 9981        }
 9982        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9983        self.transact(window, cx, |this, window, cx| {
 9984            this.select_autoclose_pair(window, cx);
 9985            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9986            if !this.linked_edit_ranges.is_empty() {
 9987                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9988                let snapshot = this.buffer.read(cx).snapshot(cx);
 9989
 9990                for selection in selections.iter() {
 9991                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9992                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9993                    if selection_start.buffer_id != selection_end.buffer_id {
 9994                        continue;
 9995                    }
 9996                    if let Some(ranges) =
 9997                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9998                    {
 9999                        for (buffer, entries) in ranges {
10000                            linked_ranges.entry(buffer).or_default().extend(entries);
10001                        }
10002                    }
10003                }
10004            }
10005
10006            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
10007            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10008            for selection in &mut selections {
10009                if selection.is_empty() {
10010                    let old_head = selection.head();
10011                    let mut new_head =
10012                        movement::left(&display_map, old_head.to_display_point(&display_map))
10013                            .to_point(&display_map);
10014                    if let Some((buffer, line_buffer_range)) = display_map
10015                        .buffer_snapshot()
10016                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10017                    {
10018                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10019                        let indent_len = match indent_size.kind {
10020                            IndentKind::Space => {
10021                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10022                            }
10023                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10024                        };
10025                        if old_head.column <= indent_size.len && old_head.column > 0 {
10026                            let indent_len = indent_len.get();
10027                            new_head = cmp::min(
10028                                new_head,
10029                                MultiBufferPoint::new(
10030                                    old_head.row,
10031                                    ((old_head.column - 1) / indent_len) * indent_len,
10032                                ),
10033                            );
10034                        }
10035                    }
10036
10037                    selection.set_head(new_head, SelectionGoal::None);
10038                }
10039            }
10040
10041            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10042            this.insert("", window, cx);
10043            let empty_str: Arc<str> = Arc::from("");
10044            for (buffer, edits) in linked_ranges {
10045                let snapshot = buffer.read(cx).snapshot();
10046                use text::ToPoint as TP;
10047
10048                let edits = edits
10049                    .into_iter()
10050                    .map(|range| {
10051                        let end_point = TP::to_point(&range.end, &snapshot);
10052                        let mut start_point = TP::to_point(&range.start, &snapshot);
10053
10054                        if end_point == start_point {
10055                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10056                                .saturating_sub(1);
10057                            start_point =
10058                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10059                        };
10060
10061                        (start_point..end_point, empty_str.clone())
10062                    })
10063                    .sorted_by_key(|(range, _)| range.start)
10064                    .collect::<Vec<_>>();
10065                buffer.update(cx, |this, cx| {
10066                    this.edit(edits, None, cx);
10067                })
10068            }
10069            this.refresh_edit_prediction(true, false, window, cx);
10070            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
10071        });
10072    }
10073
10074    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10075        if self.read_only(cx) {
10076            return;
10077        }
10078        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10079        self.transact(window, cx, |this, window, cx| {
10080            this.change_selections(Default::default(), window, cx, |s| {
10081                s.move_with(|map, selection| {
10082                    if selection.is_empty() {
10083                        let cursor = movement::right(map, selection.head());
10084                        selection.end = cursor;
10085                        selection.reversed = true;
10086                        selection.goal = SelectionGoal::None;
10087                    }
10088                })
10089            });
10090            this.insert("", window, cx);
10091            this.refresh_edit_prediction(true, false, window, cx);
10092        });
10093    }
10094
10095    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10096        if self.mode.is_single_line() {
10097            cx.propagate();
10098            return;
10099        }
10100
10101        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10102        if self.move_to_prev_snippet_tabstop(window, cx) {
10103            return;
10104        }
10105        self.outdent(&Outdent, window, cx);
10106    }
10107
10108    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10109        if self.mode.is_single_line() {
10110            cx.propagate();
10111            return;
10112        }
10113
10114        if self.move_to_next_snippet_tabstop(window, cx) {
10115            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10116            return;
10117        }
10118        if self.read_only(cx) {
10119            return;
10120        }
10121        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10122        let mut selections = self.selections.all_adjusted(cx);
10123        let buffer = self.buffer.read(cx);
10124        let snapshot = buffer.snapshot(cx);
10125        let rows_iter = selections.iter().map(|s| s.head().row);
10126        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10127
10128        let has_some_cursor_in_whitespace = selections
10129            .iter()
10130            .filter(|selection| selection.is_empty())
10131            .any(|selection| {
10132                let cursor = selection.head();
10133                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10134                cursor.column < current_indent.len
10135            });
10136
10137        let mut edits = Vec::new();
10138        let mut prev_edited_row = 0;
10139        let mut row_delta = 0;
10140        for selection in &mut selections {
10141            if selection.start.row != prev_edited_row {
10142                row_delta = 0;
10143            }
10144            prev_edited_row = selection.end.row;
10145
10146            // If the selection is non-empty, then increase the indentation of the selected lines.
10147            if !selection.is_empty() {
10148                row_delta =
10149                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10150                continue;
10151            }
10152
10153            let cursor = selection.head();
10154            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10155            if let Some(suggested_indent) =
10156                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10157            {
10158                // Don't do anything if already at suggested indent
10159                // and there is any other cursor which is not
10160                if has_some_cursor_in_whitespace
10161                    && cursor.column == current_indent.len
10162                    && current_indent.len == suggested_indent.len
10163                {
10164                    continue;
10165                }
10166
10167                // Adjust line and move cursor to suggested indent
10168                // if cursor is not at suggested indent
10169                if cursor.column < suggested_indent.len
10170                    && cursor.column <= current_indent.len
10171                    && current_indent.len <= suggested_indent.len
10172                {
10173                    selection.start = Point::new(cursor.row, suggested_indent.len);
10174                    selection.end = selection.start;
10175                    if row_delta == 0 {
10176                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10177                            cursor.row,
10178                            current_indent,
10179                            suggested_indent,
10180                        ));
10181                        row_delta = suggested_indent.len - current_indent.len;
10182                    }
10183                    continue;
10184                }
10185
10186                // If current indent is more than suggested indent
10187                // only move cursor to current indent and skip indent
10188                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10189                    selection.start = Point::new(cursor.row, current_indent.len);
10190                    selection.end = selection.start;
10191                    continue;
10192                }
10193            }
10194
10195            // Otherwise, insert a hard or soft tab.
10196            let settings = buffer.language_settings_at(cursor, cx);
10197            let tab_size = if settings.hard_tabs {
10198                IndentSize::tab()
10199            } else {
10200                let tab_size = settings.tab_size.get();
10201                let indent_remainder = snapshot
10202                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10203                    .flat_map(str::chars)
10204                    .fold(row_delta % tab_size, |counter: u32, c| {
10205                        if c == '\t' {
10206                            0
10207                        } else {
10208                            (counter + 1) % tab_size
10209                        }
10210                    });
10211
10212                let chars_to_next_tab_stop = tab_size - indent_remainder;
10213                IndentSize::spaces(chars_to_next_tab_stop)
10214            };
10215            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10216            selection.end = selection.start;
10217            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10218            row_delta += tab_size.len;
10219        }
10220
10221        self.transact(window, cx, |this, window, cx| {
10222            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10223            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10224            this.refresh_edit_prediction(true, false, window, cx);
10225        });
10226    }
10227
10228    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10229        if self.read_only(cx) {
10230            return;
10231        }
10232        if self.mode.is_single_line() {
10233            cx.propagate();
10234            return;
10235        }
10236
10237        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10238        let mut selections = self.selections.all::<Point>(cx);
10239        let mut prev_edited_row = 0;
10240        let mut row_delta = 0;
10241        let mut edits = Vec::new();
10242        let buffer = self.buffer.read(cx);
10243        let snapshot = buffer.snapshot(cx);
10244        for selection in &mut selections {
10245            if selection.start.row != prev_edited_row {
10246                row_delta = 0;
10247            }
10248            prev_edited_row = selection.end.row;
10249
10250            row_delta =
10251                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10252        }
10253
10254        self.transact(window, cx, |this, window, cx| {
10255            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10256            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10257        });
10258    }
10259
10260    fn indent_selection(
10261        buffer: &MultiBuffer,
10262        snapshot: &MultiBufferSnapshot,
10263        selection: &mut Selection<Point>,
10264        edits: &mut Vec<(Range<Point>, String)>,
10265        delta_for_start_row: u32,
10266        cx: &App,
10267    ) -> u32 {
10268        let settings = buffer.language_settings_at(selection.start, cx);
10269        let tab_size = settings.tab_size.get();
10270        let indent_kind = if settings.hard_tabs {
10271            IndentKind::Tab
10272        } else {
10273            IndentKind::Space
10274        };
10275        let mut start_row = selection.start.row;
10276        let mut end_row = selection.end.row + 1;
10277
10278        // If a selection ends at the beginning of a line, don't indent
10279        // that last line.
10280        if selection.end.column == 0 && selection.end.row > selection.start.row {
10281            end_row -= 1;
10282        }
10283
10284        // Avoid re-indenting a row that has already been indented by a
10285        // previous selection, but still update this selection's column
10286        // to reflect that indentation.
10287        if delta_for_start_row > 0 {
10288            start_row += 1;
10289            selection.start.column += delta_for_start_row;
10290            if selection.end.row == selection.start.row {
10291                selection.end.column += delta_for_start_row;
10292            }
10293        }
10294
10295        let mut delta_for_end_row = 0;
10296        let has_multiple_rows = start_row + 1 != end_row;
10297        for row in start_row..end_row {
10298            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10299            let indent_delta = match (current_indent.kind, indent_kind) {
10300                (IndentKind::Space, IndentKind::Space) => {
10301                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10302                    IndentSize::spaces(columns_to_next_tab_stop)
10303                }
10304                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10305                (_, IndentKind::Tab) => IndentSize::tab(),
10306            };
10307
10308            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10309                0
10310            } else {
10311                selection.start.column
10312            };
10313            let row_start = Point::new(row, start);
10314            edits.push((
10315                row_start..row_start,
10316                indent_delta.chars().collect::<String>(),
10317            ));
10318
10319            // Update this selection's endpoints to reflect the indentation.
10320            if row == selection.start.row {
10321                selection.start.column += indent_delta.len;
10322            }
10323            if row == selection.end.row {
10324                selection.end.column += indent_delta.len;
10325                delta_for_end_row = indent_delta.len;
10326            }
10327        }
10328
10329        if selection.start.row == selection.end.row {
10330            delta_for_start_row + delta_for_end_row
10331        } else {
10332            delta_for_end_row
10333        }
10334    }
10335
10336    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10337        if self.read_only(cx) {
10338            return;
10339        }
10340        if self.mode.is_single_line() {
10341            cx.propagate();
10342            return;
10343        }
10344
10345        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10346        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10347        let selections = self.selections.all::<Point>(cx);
10348        let mut deletion_ranges = Vec::new();
10349        let mut last_outdent = None;
10350        {
10351            let buffer = self.buffer.read(cx);
10352            let snapshot = buffer.snapshot(cx);
10353            for selection in &selections {
10354                let settings = buffer.language_settings_at(selection.start, cx);
10355                let tab_size = settings.tab_size.get();
10356                let mut rows = selection.spanned_rows(false, &display_map);
10357
10358                // Avoid re-outdenting a row that has already been outdented by a
10359                // previous selection.
10360                if let Some(last_row) = last_outdent
10361                    && last_row == rows.start
10362                {
10363                    rows.start = rows.start.next_row();
10364                }
10365                let has_multiple_rows = rows.len() > 1;
10366                for row in rows.iter_rows() {
10367                    let indent_size = snapshot.indent_size_for_line(row);
10368                    if indent_size.len > 0 {
10369                        let deletion_len = match indent_size.kind {
10370                            IndentKind::Space => {
10371                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10372                                if columns_to_prev_tab_stop == 0 {
10373                                    tab_size
10374                                } else {
10375                                    columns_to_prev_tab_stop
10376                                }
10377                            }
10378                            IndentKind::Tab => 1,
10379                        };
10380                        let start = if has_multiple_rows
10381                            || deletion_len > selection.start.column
10382                            || indent_size.len < selection.start.column
10383                        {
10384                            0
10385                        } else {
10386                            selection.start.column - deletion_len
10387                        };
10388                        deletion_ranges.push(
10389                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10390                        );
10391                        last_outdent = Some(row);
10392                    }
10393                }
10394            }
10395        }
10396
10397        self.transact(window, cx, |this, window, cx| {
10398            this.buffer.update(cx, |buffer, cx| {
10399                let empty_str: Arc<str> = Arc::default();
10400                buffer.edit(
10401                    deletion_ranges
10402                        .into_iter()
10403                        .map(|range| (range, empty_str.clone())),
10404                    None,
10405                    cx,
10406                );
10407            });
10408            let selections = this.selections.all::<usize>(cx);
10409            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10410        });
10411    }
10412
10413    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10414        if self.read_only(cx) {
10415            return;
10416        }
10417        if self.mode.is_single_line() {
10418            cx.propagate();
10419            return;
10420        }
10421
10422        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10423        let selections = self
10424            .selections
10425            .all::<usize>(cx)
10426            .into_iter()
10427            .map(|s| s.range());
10428
10429        self.transact(window, cx, |this, window, cx| {
10430            this.buffer.update(cx, |buffer, cx| {
10431                buffer.autoindent_ranges(selections, cx);
10432            });
10433            let selections = this.selections.all::<usize>(cx);
10434            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10435        });
10436    }
10437
10438    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10439        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10440        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10441        let selections = self.selections.all::<Point>(cx);
10442
10443        let mut new_cursors = Vec::new();
10444        let mut edit_ranges = Vec::new();
10445        let mut selections = selections.iter().peekable();
10446        while let Some(selection) = selections.next() {
10447            let mut rows = selection.spanned_rows(false, &display_map);
10448
10449            // Accumulate contiguous regions of rows that we want to delete.
10450            while let Some(next_selection) = selections.peek() {
10451                let next_rows = next_selection.spanned_rows(false, &display_map);
10452                if next_rows.start <= rows.end {
10453                    rows.end = next_rows.end;
10454                    selections.next().unwrap();
10455                } else {
10456                    break;
10457                }
10458            }
10459
10460            let buffer = display_map.buffer_snapshot();
10461            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10462            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10463                // If there's a line after the range, delete the \n from the end of the row range
10464                (
10465                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10466                    rows.end,
10467                )
10468            } else {
10469                // If there isn't a line after the range, delete the \n from the line before the
10470                // start of the row range
10471                edit_start = edit_start.saturating_sub(1);
10472                (buffer.len(), rows.start.previous_row())
10473            };
10474
10475            let text_layout_details = self.text_layout_details(window);
10476            let x = display_map.x_for_display_point(
10477                selection.head().to_display_point(&display_map),
10478                &text_layout_details,
10479            );
10480            let row = Point::new(target_row.0, 0)
10481                .to_display_point(&display_map)
10482                .row();
10483            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10484
10485            new_cursors.push((
10486                selection.id,
10487                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10488                SelectionGoal::None,
10489            ));
10490            edit_ranges.push(edit_start..edit_end);
10491        }
10492
10493        self.transact(window, cx, |this, window, cx| {
10494            let buffer = this.buffer.update(cx, |buffer, cx| {
10495                let empty_str: Arc<str> = Arc::default();
10496                buffer.edit(
10497                    edit_ranges
10498                        .into_iter()
10499                        .map(|range| (range, empty_str.clone())),
10500                    None,
10501                    cx,
10502                );
10503                buffer.snapshot(cx)
10504            });
10505            let new_selections = new_cursors
10506                .into_iter()
10507                .map(|(id, cursor, goal)| {
10508                    let cursor = cursor.to_point(&buffer);
10509                    Selection {
10510                        id,
10511                        start: cursor,
10512                        end: cursor,
10513                        reversed: false,
10514                        goal,
10515                    }
10516                })
10517                .collect();
10518
10519            this.change_selections(Default::default(), window, cx, |s| {
10520                s.select(new_selections);
10521            });
10522        });
10523    }
10524
10525    pub fn join_lines_impl(
10526        &mut self,
10527        insert_whitespace: bool,
10528        window: &mut Window,
10529        cx: &mut Context<Self>,
10530    ) {
10531        if self.read_only(cx) {
10532            return;
10533        }
10534        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10535        for selection in self.selections.all::<Point>(cx) {
10536            let start = MultiBufferRow(selection.start.row);
10537            // Treat single line selections as if they include the next line. Otherwise this action
10538            // would do nothing for single line selections individual cursors.
10539            let end = if selection.start.row == selection.end.row {
10540                MultiBufferRow(selection.start.row + 1)
10541            } else {
10542                MultiBufferRow(selection.end.row)
10543            };
10544
10545            if let Some(last_row_range) = row_ranges.last_mut()
10546                && start <= last_row_range.end
10547            {
10548                last_row_range.end = end;
10549                continue;
10550            }
10551            row_ranges.push(start..end);
10552        }
10553
10554        let snapshot = self.buffer.read(cx).snapshot(cx);
10555        let mut cursor_positions = Vec::new();
10556        for row_range in &row_ranges {
10557            let anchor = snapshot.anchor_before(Point::new(
10558                row_range.end.previous_row().0,
10559                snapshot.line_len(row_range.end.previous_row()),
10560            ));
10561            cursor_positions.push(anchor..anchor);
10562        }
10563
10564        self.transact(window, cx, |this, window, cx| {
10565            for row_range in row_ranges.into_iter().rev() {
10566                for row in row_range.iter_rows().rev() {
10567                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10568                    let next_line_row = row.next_row();
10569                    let indent = snapshot.indent_size_for_line(next_line_row);
10570                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10571
10572                    let replace =
10573                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10574                            " "
10575                        } else {
10576                            ""
10577                        };
10578
10579                    this.buffer.update(cx, |buffer, cx| {
10580                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10581                    });
10582                }
10583            }
10584
10585            this.change_selections(Default::default(), window, cx, |s| {
10586                s.select_anchor_ranges(cursor_positions)
10587            });
10588        });
10589    }
10590
10591    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10592        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10593        self.join_lines_impl(true, window, cx);
10594    }
10595
10596    pub fn sort_lines_case_sensitive(
10597        &mut self,
10598        _: &SortLinesCaseSensitive,
10599        window: &mut Window,
10600        cx: &mut Context<Self>,
10601    ) {
10602        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10603    }
10604
10605    pub fn sort_lines_by_length(
10606        &mut self,
10607        _: &SortLinesByLength,
10608        window: &mut Window,
10609        cx: &mut Context<Self>,
10610    ) {
10611        self.manipulate_immutable_lines(window, cx, |lines| {
10612            lines.sort_by_key(|&line| line.chars().count())
10613        })
10614    }
10615
10616    pub fn sort_lines_case_insensitive(
10617        &mut self,
10618        _: &SortLinesCaseInsensitive,
10619        window: &mut Window,
10620        cx: &mut Context<Self>,
10621    ) {
10622        self.manipulate_immutable_lines(window, cx, |lines| {
10623            lines.sort_by_key(|line| line.to_lowercase())
10624        })
10625    }
10626
10627    pub fn unique_lines_case_insensitive(
10628        &mut self,
10629        _: &UniqueLinesCaseInsensitive,
10630        window: &mut Window,
10631        cx: &mut Context<Self>,
10632    ) {
10633        self.manipulate_immutable_lines(window, cx, |lines| {
10634            let mut seen = HashSet::default();
10635            lines.retain(|line| seen.insert(line.to_lowercase()));
10636        })
10637    }
10638
10639    pub fn unique_lines_case_sensitive(
10640        &mut self,
10641        _: &UniqueLinesCaseSensitive,
10642        window: &mut Window,
10643        cx: &mut Context<Self>,
10644    ) {
10645        self.manipulate_immutable_lines(window, cx, |lines| {
10646            let mut seen = HashSet::default();
10647            lines.retain(|line| seen.insert(*line));
10648        })
10649    }
10650
10651    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10652        let snapshot = self.buffer.read(cx).snapshot(cx);
10653        for selection in self.selections.disjoint_anchors_arc().iter() {
10654            if snapshot
10655                .language_at(selection.start)
10656                .and_then(|lang| lang.config().wrap_characters.as_ref())
10657                .is_some()
10658            {
10659                return true;
10660            }
10661        }
10662        false
10663    }
10664
10665    fn wrap_selections_in_tag(
10666        &mut self,
10667        _: &WrapSelectionsInTag,
10668        window: &mut Window,
10669        cx: &mut Context<Self>,
10670    ) {
10671        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10672
10673        let snapshot = self.buffer.read(cx).snapshot(cx);
10674
10675        let mut edits = Vec::new();
10676        let mut boundaries = Vec::new();
10677
10678        for selection in self.selections.all::<Point>(cx).iter() {
10679            let Some(wrap_config) = snapshot
10680                .language_at(selection.start)
10681                .and_then(|lang| lang.config().wrap_characters.clone())
10682            else {
10683                continue;
10684            };
10685
10686            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10687            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10688
10689            let start_before = snapshot.anchor_before(selection.start);
10690            let end_after = snapshot.anchor_after(selection.end);
10691
10692            edits.push((start_before..start_before, open_tag));
10693            edits.push((end_after..end_after, close_tag));
10694
10695            boundaries.push((
10696                start_before,
10697                end_after,
10698                wrap_config.start_prefix.len(),
10699                wrap_config.end_suffix.len(),
10700            ));
10701        }
10702
10703        if edits.is_empty() {
10704            return;
10705        }
10706
10707        self.transact(window, cx, |this, window, cx| {
10708            let buffer = this.buffer.update(cx, |buffer, cx| {
10709                buffer.edit(edits, None, cx);
10710                buffer.snapshot(cx)
10711            });
10712
10713            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10714            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10715                boundaries.into_iter()
10716            {
10717                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10718                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10719                new_selections.push(open_offset..open_offset);
10720                new_selections.push(close_offset..close_offset);
10721            }
10722
10723            this.change_selections(Default::default(), window, cx, |s| {
10724                s.select_ranges(new_selections);
10725            });
10726
10727            this.request_autoscroll(Autoscroll::fit(), cx);
10728        });
10729    }
10730
10731    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10732        let Some(project) = self.project.clone() else {
10733            return;
10734        };
10735        self.reload(project, window, cx)
10736            .detach_and_notify_err(window, cx);
10737    }
10738
10739    pub fn restore_file(
10740        &mut self,
10741        _: &::git::RestoreFile,
10742        window: &mut Window,
10743        cx: &mut Context<Self>,
10744    ) {
10745        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10746        let mut buffer_ids = HashSet::default();
10747        let snapshot = self.buffer().read(cx).snapshot(cx);
10748        for selection in self.selections.all::<usize>(cx) {
10749            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10750        }
10751
10752        let buffer = self.buffer().read(cx);
10753        let ranges = buffer_ids
10754            .into_iter()
10755            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10756            .collect::<Vec<_>>();
10757
10758        self.restore_hunks_in_ranges(ranges, window, cx);
10759    }
10760
10761    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10762        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10763        let selections = self
10764            .selections
10765            .all(cx)
10766            .into_iter()
10767            .map(|s| s.range())
10768            .collect();
10769        self.restore_hunks_in_ranges(selections, window, cx);
10770    }
10771
10772    pub fn restore_hunks_in_ranges(
10773        &mut self,
10774        ranges: Vec<Range<Point>>,
10775        window: &mut Window,
10776        cx: &mut Context<Editor>,
10777    ) {
10778        let mut revert_changes = HashMap::default();
10779        let chunk_by = self
10780            .snapshot(window, cx)
10781            .hunks_for_ranges(ranges)
10782            .into_iter()
10783            .chunk_by(|hunk| hunk.buffer_id);
10784        for (buffer_id, hunks) in &chunk_by {
10785            let hunks = hunks.collect::<Vec<_>>();
10786            for hunk in &hunks {
10787                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10788            }
10789            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10790        }
10791        drop(chunk_by);
10792        if !revert_changes.is_empty() {
10793            self.transact(window, cx, |editor, window, cx| {
10794                editor.restore(revert_changes, window, cx);
10795            });
10796        }
10797    }
10798
10799    pub fn open_active_item_in_terminal(
10800        &mut self,
10801        _: &OpenInTerminal,
10802        window: &mut Window,
10803        cx: &mut Context<Self>,
10804    ) {
10805        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10806            let project_path = buffer.read(cx).project_path(cx)?;
10807            let project = self.project()?.read(cx);
10808            let entry = project.entry_for_path(&project_path, cx)?;
10809            let parent = match &entry.canonical_path {
10810                Some(canonical_path) => canonical_path.to_path_buf(),
10811                None => project.absolute_path(&project_path, cx)?,
10812            }
10813            .parent()?
10814            .to_path_buf();
10815            Some(parent)
10816        }) {
10817            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10818        }
10819    }
10820
10821    fn set_breakpoint_context_menu(
10822        &mut self,
10823        display_row: DisplayRow,
10824        position: Option<Anchor>,
10825        clicked_point: gpui::Point<Pixels>,
10826        window: &mut Window,
10827        cx: &mut Context<Self>,
10828    ) {
10829        let source = self
10830            .buffer
10831            .read(cx)
10832            .snapshot(cx)
10833            .anchor_before(Point::new(display_row.0, 0u32));
10834
10835        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10836
10837        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10838            self,
10839            source,
10840            clicked_point,
10841            context_menu,
10842            window,
10843            cx,
10844        );
10845    }
10846
10847    fn add_edit_breakpoint_block(
10848        &mut self,
10849        anchor: Anchor,
10850        breakpoint: &Breakpoint,
10851        edit_action: BreakpointPromptEditAction,
10852        window: &mut Window,
10853        cx: &mut Context<Self>,
10854    ) {
10855        let weak_editor = cx.weak_entity();
10856        let bp_prompt = cx.new(|cx| {
10857            BreakpointPromptEditor::new(
10858                weak_editor,
10859                anchor,
10860                breakpoint.clone(),
10861                edit_action,
10862                window,
10863                cx,
10864            )
10865        });
10866
10867        let height = bp_prompt.update(cx, |this, cx| {
10868            this.prompt
10869                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10870        });
10871        let cloned_prompt = bp_prompt.clone();
10872        let blocks = vec![BlockProperties {
10873            style: BlockStyle::Sticky,
10874            placement: BlockPlacement::Above(anchor),
10875            height: Some(height),
10876            render: Arc::new(move |cx| {
10877                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10878                cloned_prompt.clone().into_any_element()
10879            }),
10880            priority: 0,
10881        }];
10882
10883        let focus_handle = bp_prompt.focus_handle(cx);
10884        window.focus(&focus_handle);
10885
10886        let block_ids = self.insert_blocks(blocks, None, cx);
10887        bp_prompt.update(cx, |prompt, _| {
10888            prompt.add_block_ids(block_ids);
10889        });
10890    }
10891
10892    pub(crate) fn breakpoint_at_row(
10893        &self,
10894        row: u32,
10895        window: &mut Window,
10896        cx: &mut Context<Self>,
10897    ) -> Option<(Anchor, Breakpoint)> {
10898        let snapshot = self.snapshot(window, cx);
10899        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10900
10901        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10902    }
10903
10904    pub(crate) fn breakpoint_at_anchor(
10905        &self,
10906        breakpoint_position: Anchor,
10907        snapshot: &EditorSnapshot,
10908        cx: &mut Context<Self>,
10909    ) -> Option<(Anchor, Breakpoint)> {
10910        let buffer = self
10911            .buffer
10912            .read(cx)
10913            .buffer_for_anchor(breakpoint_position, cx)?;
10914
10915        let enclosing_excerpt = breakpoint_position.excerpt_id;
10916        let buffer_snapshot = buffer.read(cx).snapshot();
10917
10918        let row = buffer_snapshot
10919            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10920            .row;
10921
10922        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10923        let anchor_end = snapshot
10924            .buffer_snapshot()
10925            .anchor_after(Point::new(row, line_len));
10926
10927        self.breakpoint_store
10928            .as_ref()?
10929            .read_with(cx, |breakpoint_store, cx| {
10930                breakpoint_store
10931                    .breakpoints(
10932                        &buffer,
10933                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10934                        &buffer_snapshot,
10935                        cx,
10936                    )
10937                    .next()
10938                    .and_then(|(bp, _)| {
10939                        let breakpoint_row = buffer_snapshot
10940                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10941                            .row;
10942
10943                        if breakpoint_row == row {
10944                            snapshot
10945                                .buffer_snapshot()
10946                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10947                                .map(|position| (position, bp.bp.clone()))
10948                        } else {
10949                            None
10950                        }
10951                    })
10952            })
10953    }
10954
10955    pub fn edit_log_breakpoint(
10956        &mut self,
10957        _: &EditLogBreakpoint,
10958        window: &mut Window,
10959        cx: &mut Context<Self>,
10960    ) {
10961        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10962            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10963                message: None,
10964                state: BreakpointState::Enabled,
10965                condition: None,
10966                hit_condition: None,
10967            });
10968
10969            self.add_edit_breakpoint_block(
10970                anchor,
10971                &breakpoint,
10972                BreakpointPromptEditAction::Log,
10973                window,
10974                cx,
10975            );
10976        }
10977    }
10978
10979    fn breakpoints_at_cursors(
10980        &self,
10981        window: &mut Window,
10982        cx: &mut Context<Self>,
10983    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10984        let snapshot = self.snapshot(window, cx);
10985        let cursors = self
10986            .selections
10987            .disjoint_anchors_arc()
10988            .iter()
10989            .map(|selection| {
10990                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
10991
10992                let breakpoint_position = self
10993                    .breakpoint_at_row(cursor_position.row, window, cx)
10994                    .map(|bp| bp.0)
10995                    .unwrap_or_else(|| {
10996                        snapshot
10997                            .display_snapshot
10998                            .buffer_snapshot()
10999                            .anchor_after(Point::new(cursor_position.row, 0))
11000                    });
11001
11002                let breakpoint = self
11003                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11004                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11005
11006                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11007            })
11008            // 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.
11009            .collect::<HashMap<Anchor, _>>();
11010
11011        cursors.into_iter().collect()
11012    }
11013
11014    pub fn enable_breakpoint(
11015        &mut self,
11016        _: &crate::actions::EnableBreakpoint,
11017        window: &mut Window,
11018        cx: &mut Context<Self>,
11019    ) {
11020        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11021            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11022                continue;
11023            };
11024            self.edit_breakpoint_at_anchor(
11025                anchor,
11026                breakpoint,
11027                BreakpointEditAction::InvertState,
11028                cx,
11029            );
11030        }
11031    }
11032
11033    pub fn disable_breakpoint(
11034        &mut self,
11035        _: &crate::actions::DisableBreakpoint,
11036        window: &mut Window,
11037        cx: &mut Context<Self>,
11038    ) {
11039        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11040            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11041                continue;
11042            };
11043            self.edit_breakpoint_at_anchor(
11044                anchor,
11045                breakpoint,
11046                BreakpointEditAction::InvertState,
11047                cx,
11048            );
11049        }
11050    }
11051
11052    pub fn toggle_breakpoint(
11053        &mut self,
11054        _: &crate::actions::ToggleBreakpoint,
11055        window: &mut Window,
11056        cx: &mut Context<Self>,
11057    ) {
11058        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11059            if let Some(breakpoint) = breakpoint {
11060                self.edit_breakpoint_at_anchor(
11061                    anchor,
11062                    breakpoint,
11063                    BreakpointEditAction::Toggle,
11064                    cx,
11065                );
11066            } else {
11067                self.edit_breakpoint_at_anchor(
11068                    anchor,
11069                    Breakpoint::new_standard(),
11070                    BreakpointEditAction::Toggle,
11071                    cx,
11072                );
11073            }
11074        }
11075    }
11076
11077    pub fn edit_breakpoint_at_anchor(
11078        &mut self,
11079        breakpoint_position: Anchor,
11080        breakpoint: Breakpoint,
11081        edit_action: BreakpointEditAction,
11082        cx: &mut Context<Self>,
11083    ) {
11084        let Some(breakpoint_store) = &self.breakpoint_store else {
11085            return;
11086        };
11087
11088        let Some(buffer) = self
11089            .buffer
11090            .read(cx)
11091            .buffer_for_anchor(breakpoint_position, cx)
11092        else {
11093            return;
11094        };
11095
11096        breakpoint_store.update(cx, |breakpoint_store, cx| {
11097            breakpoint_store.toggle_breakpoint(
11098                buffer,
11099                BreakpointWithPosition {
11100                    position: breakpoint_position.text_anchor,
11101                    bp: breakpoint,
11102                },
11103                edit_action,
11104                cx,
11105            );
11106        });
11107
11108        cx.notify();
11109    }
11110
11111    #[cfg(any(test, feature = "test-support"))]
11112    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11113        self.breakpoint_store.clone()
11114    }
11115
11116    pub fn prepare_restore_change(
11117        &self,
11118        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11119        hunk: &MultiBufferDiffHunk,
11120        cx: &mut App,
11121    ) -> Option<()> {
11122        if hunk.is_created_file() {
11123            return None;
11124        }
11125        let buffer = self.buffer.read(cx);
11126        let diff = buffer.diff_for(hunk.buffer_id)?;
11127        let buffer = buffer.buffer(hunk.buffer_id)?;
11128        let buffer = buffer.read(cx);
11129        let original_text = diff
11130            .read(cx)
11131            .base_text()
11132            .as_rope()
11133            .slice(hunk.diff_base_byte_range.clone());
11134        let buffer_snapshot = buffer.snapshot();
11135        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11136        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11137            probe
11138                .0
11139                .start
11140                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11141                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11142        }) {
11143            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11144            Some(())
11145        } else {
11146            None
11147        }
11148    }
11149
11150    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11151        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11152    }
11153
11154    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11155        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11156    }
11157
11158    fn manipulate_lines<M>(
11159        &mut self,
11160        window: &mut Window,
11161        cx: &mut Context<Self>,
11162        mut manipulate: M,
11163    ) where
11164        M: FnMut(&str) -> LineManipulationResult,
11165    {
11166        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11167
11168        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11169        let buffer = self.buffer.read(cx).snapshot(cx);
11170
11171        let mut edits = Vec::new();
11172
11173        let selections = self.selections.all::<Point>(cx);
11174        let mut selections = selections.iter().peekable();
11175        let mut contiguous_row_selections = Vec::new();
11176        let mut new_selections = Vec::new();
11177        let mut added_lines = 0;
11178        let mut removed_lines = 0;
11179
11180        while let Some(selection) = selections.next() {
11181            let (start_row, end_row) = consume_contiguous_rows(
11182                &mut contiguous_row_selections,
11183                selection,
11184                &display_map,
11185                &mut selections,
11186            );
11187
11188            let start_point = Point::new(start_row.0, 0);
11189            let end_point = Point::new(
11190                end_row.previous_row().0,
11191                buffer.line_len(end_row.previous_row()),
11192            );
11193            let text = buffer
11194                .text_for_range(start_point..end_point)
11195                .collect::<String>();
11196
11197            let LineManipulationResult {
11198                new_text,
11199                line_count_before,
11200                line_count_after,
11201            } = manipulate(&text);
11202
11203            edits.push((start_point..end_point, new_text));
11204
11205            // Selections must change based on added and removed line count
11206            let start_row =
11207                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11208            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11209            new_selections.push(Selection {
11210                id: selection.id,
11211                start: start_row,
11212                end: end_row,
11213                goal: SelectionGoal::None,
11214                reversed: selection.reversed,
11215            });
11216
11217            if line_count_after > line_count_before {
11218                added_lines += line_count_after - line_count_before;
11219            } else if line_count_before > line_count_after {
11220                removed_lines += line_count_before - line_count_after;
11221            }
11222        }
11223
11224        self.transact(window, cx, |this, window, cx| {
11225            let buffer = this.buffer.update(cx, |buffer, cx| {
11226                buffer.edit(edits, None, cx);
11227                buffer.snapshot(cx)
11228            });
11229
11230            // Recalculate offsets on newly edited buffer
11231            let new_selections = new_selections
11232                .iter()
11233                .map(|s| {
11234                    let start_point = Point::new(s.start.0, 0);
11235                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11236                    Selection {
11237                        id: s.id,
11238                        start: buffer.point_to_offset(start_point),
11239                        end: buffer.point_to_offset(end_point),
11240                        goal: s.goal,
11241                        reversed: s.reversed,
11242                    }
11243                })
11244                .collect();
11245
11246            this.change_selections(Default::default(), window, cx, |s| {
11247                s.select(new_selections);
11248            });
11249
11250            this.request_autoscroll(Autoscroll::fit(), cx);
11251        });
11252    }
11253
11254    fn manipulate_immutable_lines<Fn>(
11255        &mut self,
11256        window: &mut Window,
11257        cx: &mut Context<Self>,
11258        mut callback: Fn,
11259    ) where
11260        Fn: FnMut(&mut Vec<&str>),
11261    {
11262        self.manipulate_lines(window, cx, |text| {
11263            let mut lines: Vec<&str> = text.split('\n').collect();
11264            let line_count_before = lines.len();
11265
11266            callback(&mut lines);
11267
11268            LineManipulationResult {
11269                new_text: lines.join("\n"),
11270                line_count_before,
11271                line_count_after: lines.len(),
11272            }
11273        });
11274    }
11275
11276    fn manipulate_mutable_lines<Fn>(
11277        &mut self,
11278        window: &mut Window,
11279        cx: &mut Context<Self>,
11280        mut callback: Fn,
11281    ) where
11282        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11283    {
11284        self.manipulate_lines(window, cx, |text| {
11285            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11286            let line_count_before = lines.len();
11287
11288            callback(&mut lines);
11289
11290            LineManipulationResult {
11291                new_text: lines.join("\n"),
11292                line_count_before,
11293                line_count_after: lines.len(),
11294            }
11295        });
11296    }
11297
11298    pub fn convert_indentation_to_spaces(
11299        &mut self,
11300        _: &ConvertIndentationToSpaces,
11301        window: &mut Window,
11302        cx: &mut Context<Self>,
11303    ) {
11304        let settings = self.buffer.read(cx).language_settings(cx);
11305        let tab_size = settings.tab_size.get() as usize;
11306
11307        self.manipulate_mutable_lines(window, cx, |lines| {
11308            // Allocates a reasonably sized scratch buffer once for the whole loop
11309            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11310            // Avoids recomputing spaces that could be inserted many times
11311            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11312                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11313                .collect();
11314
11315            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11316                let mut chars = line.as_ref().chars();
11317                let mut col = 0;
11318                let mut changed = false;
11319
11320                for ch in chars.by_ref() {
11321                    match ch {
11322                        ' ' => {
11323                            reindented_line.push(' ');
11324                            col += 1;
11325                        }
11326                        '\t' => {
11327                            // \t are converted to spaces depending on the current column
11328                            let spaces_len = tab_size - (col % tab_size);
11329                            reindented_line.extend(&space_cache[spaces_len - 1]);
11330                            col += spaces_len;
11331                            changed = true;
11332                        }
11333                        _ => {
11334                            // If we dont append before break, the character is consumed
11335                            reindented_line.push(ch);
11336                            break;
11337                        }
11338                    }
11339                }
11340
11341                if !changed {
11342                    reindented_line.clear();
11343                    continue;
11344                }
11345                // Append the rest of the line and replace old reference with new one
11346                reindented_line.extend(chars);
11347                *line = Cow::Owned(reindented_line.clone());
11348                reindented_line.clear();
11349            }
11350        });
11351    }
11352
11353    pub fn convert_indentation_to_tabs(
11354        &mut self,
11355        _: &ConvertIndentationToTabs,
11356        window: &mut Window,
11357        cx: &mut Context<Self>,
11358    ) {
11359        let settings = self.buffer.read(cx).language_settings(cx);
11360        let tab_size = settings.tab_size.get() as usize;
11361
11362        self.manipulate_mutable_lines(window, cx, |lines| {
11363            // Allocates a reasonably sized buffer once for the whole loop
11364            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11365            // Avoids recomputing spaces that could be inserted many times
11366            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11367                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11368                .collect();
11369
11370            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11371                let mut chars = line.chars();
11372                let mut spaces_count = 0;
11373                let mut first_non_indent_char = None;
11374                let mut changed = false;
11375
11376                for ch in chars.by_ref() {
11377                    match ch {
11378                        ' ' => {
11379                            // Keep track of spaces. Append \t when we reach tab_size
11380                            spaces_count += 1;
11381                            changed = true;
11382                            if spaces_count == tab_size {
11383                                reindented_line.push('\t');
11384                                spaces_count = 0;
11385                            }
11386                        }
11387                        '\t' => {
11388                            reindented_line.push('\t');
11389                            spaces_count = 0;
11390                        }
11391                        _ => {
11392                            // Dont append it yet, we might have remaining spaces
11393                            first_non_indent_char = Some(ch);
11394                            break;
11395                        }
11396                    }
11397                }
11398
11399                if !changed {
11400                    reindented_line.clear();
11401                    continue;
11402                }
11403                // Remaining spaces that didn't make a full tab stop
11404                if spaces_count > 0 {
11405                    reindented_line.extend(&space_cache[spaces_count - 1]);
11406                }
11407                // If we consume an extra character that was not indentation, add it back
11408                if let Some(extra_char) = first_non_indent_char {
11409                    reindented_line.push(extra_char);
11410                }
11411                // Append the rest of the line and replace old reference with new one
11412                reindented_line.extend(chars);
11413                *line = Cow::Owned(reindented_line.clone());
11414                reindented_line.clear();
11415            }
11416        });
11417    }
11418
11419    pub fn convert_to_upper_case(
11420        &mut self,
11421        _: &ConvertToUpperCase,
11422        window: &mut Window,
11423        cx: &mut Context<Self>,
11424    ) {
11425        self.manipulate_text(window, cx, |text| text.to_uppercase())
11426    }
11427
11428    pub fn convert_to_lower_case(
11429        &mut self,
11430        _: &ConvertToLowerCase,
11431        window: &mut Window,
11432        cx: &mut Context<Self>,
11433    ) {
11434        self.manipulate_text(window, cx, |text| text.to_lowercase())
11435    }
11436
11437    pub fn convert_to_title_case(
11438        &mut self,
11439        _: &ConvertToTitleCase,
11440        window: &mut Window,
11441        cx: &mut Context<Self>,
11442    ) {
11443        self.manipulate_text(window, cx, |text| {
11444            text.split('\n')
11445                .map(|line| line.to_case(Case::Title))
11446                .join("\n")
11447        })
11448    }
11449
11450    pub fn convert_to_snake_case(
11451        &mut self,
11452        _: &ConvertToSnakeCase,
11453        window: &mut Window,
11454        cx: &mut Context<Self>,
11455    ) {
11456        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11457    }
11458
11459    pub fn convert_to_kebab_case(
11460        &mut self,
11461        _: &ConvertToKebabCase,
11462        window: &mut Window,
11463        cx: &mut Context<Self>,
11464    ) {
11465        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11466    }
11467
11468    pub fn convert_to_upper_camel_case(
11469        &mut self,
11470        _: &ConvertToUpperCamelCase,
11471        window: &mut Window,
11472        cx: &mut Context<Self>,
11473    ) {
11474        self.manipulate_text(window, cx, |text| {
11475            text.split('\n')
11476                .map(|line| line.to_case(Case::UpperCamel))
11477                .join("\n")
11478        })
11479    }
11480
11481    pub fn convert_to_lower_camel_case(
11482        &mut self,
11483        _: &ConvertToLowerCamelCase,
11484        window: &mut Window,
11485        cx: &mut Context<Self>,
11486    ) {
11487        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11488    }
11489
11490    pub fn convert_to_opposite_case(
11491        &mut self,
11492        _: &ConvertToOppositeCase,
11493        window: &mut Window,
11494        cx: &mut Context<Self>,
11495    ) {
11496        self.manipulate_text(window, cx, |text| {
11497            text.chars()
11498                .fold(String::with_capacity(text.len()), |mut t, c| {
11499                    if c.is_uppercase() {
11500                        t.extend(c.to_lowercase());
11501                    } else {
11502                        t.extend(c.to_uppercase());
11503                    }
11504                    t
11505                })
11506        })
11507    }
11508
11509    pub fn convert_to_sentence_case(
11510        &mut self,
11511        _: &ConvertToSentenceCase,
11512        window: &mut Window,
11513        cx: &mut Context<Self>,
11514    ) {
11515        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11516    }
11517
11518    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11519        self.manipulate_text(window, cx, |text| {
11520            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11521            if has_upper_case_characters {
11522                text.to_lowercase()
11523            } else {
11524                text.to_uppercase()
11525            }
11526        })
11527    }
11528
11529    pub fn convert_to_rot13(
11530        &mut self,
11531        _: &ConvertToRot13,
11532        window: &mut Window,
11533        cx: &mut Context<Self>,
11534    ) {
11535        self.manipulate_text(window, cx, |text| {
11536            text.chars()
11537                .map(|c| match c {
11538                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11539                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11540                    _ => c,
11541                })
11542                .collect()
11543        })
11544    }
11545
11546    pub fn convert_to_rot47(
11547        &mut self,
11548        _: &ConvertToRot47,
11549        window: &mut Window,
11550        cx: &mut Context<Self>,
11551    ) {
11552        self.manipulate_text(window, cx, |text| {
11553            text.chars()
11554                .map(|c| {
11555                    let code_point = c as u32;
11556                    if code_point >= 33 && code_point <= 126 {
11557                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11558                    }
11559                    c
11560                })
11561                .collect()
11562        })
11563    }
11564
11565    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11566    where
11567        Fn: FnMut(&str) -> String,
11568    {
11569        let buffer = self.buffer.read(cx).snapshot(cx);
11570
11571        let mut new_selections = Vec::new();
11572        let mut edits = Vec::new();
11573        let mut selection_adjustment = 0i32;
11574
11575        for selection in self.selections.all_adjusted(cx) {
11576            let selection_is_empty = selection.is_empty();
11577
11578            let (start, end) = if selection_is_empty {
11579                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11580                (word_range.start, word_range.end)
11581            } else {
11582                (
11583                    buffer.point_to_offset(selection.start),
11584                    buffer.point_to_offset(selection.end),
11585                )
11586            };
11587
11588            let text = buffer.text_for_range(start..end).collect::<String>();
11589            let old_length = text.len() as i32;
11590            let text = callback(&text);
11591
11592            new_selections.push(Selection {
11593                start: (start as i32 - selection_adjustment) as usize,
11594                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11595                goal: SelectionGoal::None,
11596                id: selection.id,
11597                reversed: selection.reversed,
11598            });
11599
11600            selection_adjustment += old_length - text.len() as i32;
11601
11602            edits.push((start..end, text));
11603        }
11604
11605        self.transact(window, cx, |this, window, cx| {
11606            this.buffer.update(cx, |buffer, cx| {
11607                buffer.edit(edits, None, cx);
11608            });
11609
11610            this.change_selections(Default::default(), window, cx, |s| {
11611                s.select(new_selections);
11612            });
11613
11614            this.request_autoscroll(Autoscroll::fit(), cx);
11615        });
11616    }
11617
11618    pub fn move_selection_on_drop(
11619        &mut self,
11620        selection: &Selection<Anchor>,
11621        target: DisplayPoint,
11622        is_cut: bool,
11623        window: &mut Window,
11624        cx: &mut Context<Self>,
11625    ) {
11626        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11627        let buffer = display_map.buffer_snapshot();
11628        let mut edits = Vec::new();
11629        let insert_point = display_map
11630            .clip_point(target, Bias::Left)
11631            .to_point(&display_map);
11632        let text = buffer
11633            .text_for_range(selection.start..selection.end)
11634            .collect::<String>();
11635        if is_cut {
11636            edits.push(((selection.start..selection.end), String::new()));
11637        }
11638        let insert_anchor = buffer.anchor_before(insert_point);
11639        edits.push(((insert_anchor..insert_anchor), text));
11640        let last_edit_start = insert_anchor.bias_left(buffer);
11641        let last_edit_end = insert_anchor.bias_right(buffer);
11642        self.transact(window, cx, |this, window, cx| {
11643            this.buffer.update(cx, |buffer, cx| {
11644                buffer.edit(edits, None, cx);
11645            });
11646            this.change_selections(Default::default(), window, cx, |s| {
11647                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11648            });
11649        });
11650    }
11651
11652    pub fn clear_selection_drag_state(&mut self) {
11653        self.selection_drag_state = SelectionDragState::None;
11654    }
11655
11656    pub fn duplicate(
11657        &mut self,
11658        upwards: bool,
11659        whole_lines: bool,
11660        window: &mut Window,
11661        cx: &mut Context<Self>,
11662    ) {
11663        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11664
11665        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11666        let buffer = display_map.buffer_snapshot();
11667        let selections = self.selections.all::<Point>(cx);
11668
11669        let mut edits = Vec::new();
11670        let mut selections_iter = selections.iter().peekable();
11671        while let Some(selection) = selections_iter.next() {
11672            let mut rows = selection.spanned_rows(false, &display_map);
11673            // duplicate line-wise
11674            if whole_lines || selection.start == selection.end {
11675                // Avoid duplicating the same lines twice.
11676                while let Some(next_selection) = selections_iter.peek() {
11677                    let next_rows = next_selection.spanned_rows(false, &display_map);
11678                    if next_rows.start < rows.end {
11679                        rows.end = next_rows.end;
11680                        selections_iter.next().unwrap();
11681                    } else {
11682                        break;
11683                    }
11684                }
11685
11686                // Copy the text from the selected row region and splice it either at the start
11687                // or end of the region.
11688                let start = Point::new(rows.start.0, 0);
11689                let end = Point::new(
11690                    rows.end.previous_row().0,
11691                    buffer.line_len(rows.end.previous_row()),
11692                );
11693                let text = buffer
11694                    .text_for_range(start..end)
11695                    .chain(Some("\n"))
11696                    .collect::<String>();
11697                let insert_location = if upwards {
11698                    Point::new(rows.end.0, 0)
11699                } else {
11700                    start
11701                };
11702                edits.push((insert_location..insert_location, text));
11703            } else {
11704                // duplicate character-wise
11705                let start = selection.start;
11706                let end = selection.end;
11707                let text = buffer.text_for_range(start..end).collect::<String>();
11708                edits.push((selection.end..selection.end, text));
11709            }
11710        }
11711
11712        self.transact(window, cx, |this, _, cx| {
11713            this.buffer.update(cx, |buffer, cx| {
11714                buffer.edit(edits, None, cx);
11715            });
11716
11717            this.request_autoscroll(Autoscroll::fit(), cx);
11718        });
11719    }
11720
11721    pub fn duplicate_line_up(
11722        &mut self,
11723        _: &DuplicateLineUp,
11724        window: &mut Window,
11725        cx: &mut Context<Self>,
11726    ) {
11727        self.duplicate(true, true, window, cx);
11728    }
11729
11730    pub fn duplicate_line_down(
11731        &mut self,
11732        _: &DuplicateLineDown,
11733        window: &mut Window,
11734        cx: &mut Context<Self>,
11735    ) {
11736        self.duplicate(false, true, window, cx);
11737    }
11738
11739    pub fn duplicate_selection(
11740        &mut self,
11741        _: &DuplicateSelection,
11742        window: &mut Window,
11743        cx: &mut Context<Self>,
11744    ) {
11745        self.duplicate(false, false, window, cx);
11746    }
11747
11748    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11749        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11750        if self.mode.is_single_line() {
11751            cx.propagate();
11752            return;
11753        }
11754
11755        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11756        let buffer = self.buffer.read(cx).snapshot(cx);
11757
11758        let mut edits = Vec::new();
11759        let mut unfold_ranges = Vec::new();
11760        let mut refold_creases = Vec::new();
11761
11762        let selections = self.selections.all::<Point>(cx);
11763        let mut selections = selections.iter().peekable();
11764        let mut contiguous_row_selections = Vec::new();
11765        let mut new_selections = Vec::new();
11766
11767        while let Some(selection) = selections.next() {
11768            // Find all the selections that span a contiguous row range
11769            let (start_row, end_row) = consume_contiguous_rows(
11770                &mut contiguous_row_selections,
11771                selection,
11772                &display_map,
11773                &mut selections,
11774            );
11775
11776            // Move the text spanned by the row range to be before the line preceding the row range
11777            if start_row.0 > 0 {
11778                let range_to_move = Point::new(
11779                    start_row.previous_row().0,
11780                    buffer.line_len(start_row.previous_row()),
11781                )
11782                    ..Point::new(
11783                        end_row.previous_row().0,
11784                        buffer.line_len(end_row.previous_row()),
11785                    );
11786                let insertion_point = display_map
11787                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11788                    .0;
11789
11790                // Don't move lines across excerpts
11791                if buffer
11792                    .excerpt_containing(insertion_point..range_to_move.end)
11793                    .is_some()
11794                {
11795                    let text = buffer
11796                        .text_for_range(range_to_move.clone())
11797                        .flat_map(|s| s.chars())
11798                        .skip(1)
11799                        .chain(['\n'])
11800                        .collect::<String>();
11801
11802                    edits.push((
11803                        buffer.anchor_after(range_to_move.start)
11804                            ..buffer.anchor_before(range_to_move.end),
11805                        String::new(),
11806                    ));
11807                    let insertion_anchor = buffer.anchor_after(insertion_point);
11808                    edits.push((insertion_anchor..insertion_anchor, text));
11809
11810                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11811
11812                    // Move selections up
11813                    new_selections.extend(contiguous_row_selections.drain(..).map(
11814                        |mut selection| {
11815                            selection.start.row -= row_delta;
11816                            selection.end.row -= row_delta;
11817                            selection
11818                        },
11819                    ));
11820
11821                    // Move folds up
11822                    unfold_ranges.push(range_to_move.clone());
11823                    for fold in display_map.folds_in_range(
11824                        buffer.anchor_before(range_to_move.start)
11825                            ..buffer.anchor_after(range_to_move.end),
11826                    ) {
11827                        let mut start = fold.range.start.to_point(&buffer);
11828                        let mut end = fold.range.end.to_point(&buffer);
11829                        start.row -= row_delta;
11830                        end.row -= row_delta;
11831                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11832                    }
11833                }
11834            }
11835
11836            // If we didn't move line(s), preserve the existing selections
11837            new_selections.append(&mut contiguous_row_selections);
11838        }
11839
11840        self.transact(window, cx, |this, window, cx| {
11841            this.unfold_ranges(&unfold_ranges, true, true, cx);
11842            this.buffer.update(cx, |buffer, cx| {
11843                for (range, text) in edits {
11844                    buffer.edit([(range, text)], None, cx);
11845                }
11846            });
11847            this.fold_creases(refold_creases, true, window, cx);
11848            this.change_selections(Default::default(), window, cx, |s| {
11849                s.select(new_selections);
11850            })
11851        });
11852    }
11853
11854    pub fn move_line_down(
11855        &mut self,
11856        _: &MoveLineDown,
11857        window: &mut Window,
11858        cx: &mut Context<Self>,
11859    ) {
11860        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11861        if self.mode.is_single_line() {
11862            cx.propagate();
11863            return;
11864        }
11865
11866        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11867        let buffer = self.buffer.read(cx).snapshot(cx);
11868
11869        let mut edits = Vec::new();
11870        let mut unfold_ranges = Vec::new();
11871        let mut refold_creases = Vec::new();
11872
11873        let selections = self.selections.all::<Point>(cx);
11874        let mut selections = selections.iter().peekable();
11875        let mut contiguous_row_selections = Vec::new();
11876        let mut new_selections = Vec::new();
11877
11878        while let Some(selection) = selections.next() {
11879            // Find all the selections that span a contiguous row range
11880            let (start_row, end_row) = consume_contiguous_rows(
11881                &mut contiguous_row_selections,
11882                selection,
11883                &display_map,
11884                &mut selections,
11885            );
11886
11887            // Move the text spanned by the row range to be after the last line of the row range
11888            if end_row.0 <= buffer.max_point().row {
11889                let range_to_move =
11890                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11891                let insertion_point = display_map
11892                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11893                    .0;
11894
11895                // Don't move lines across excerpt boundaries
11896                if buffer
11897                    .excerpt_containing(range_to_move.start..insertion_point)
11898                    .is_some()
11899                {
11900                    let mut text = String::from("\n");
11901                    text.extend(buffer.text_for_range(range_to_move.clone()));
11902                    text.pop(); // Drop trailing newline
11903                    edits.push((
11904                        buffer.anchor_after(range_to_move.start)
11905                            ..buffer.anchor_before(range_to_move.end),
11906                        String::new(),
11907                    ));
11908                    let insertion_anchor = buffer.anchor_after(insertion_point);
11909                    edits.push((insertion_anchor..insertion_anchor, text));
11910
11911                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11912
11913                    // Move selections down
11914                    new_selections.extend(contiguous_row_selections.drain(..).map(
11915                        |mut selection| {
11916                            selection.start.row += row_delta;
11917                            selection.end.row += row_delta;
11918                            selection
11919                        },
11920                    ));
11921
11922                    // Move folds down
11923                    unfold_ranges.push(range_to_move.clone());
11924                    for fold in display_map.folds_in_range(
11925                        buffer.anchor_before(range_to_move.start)
11926                            ..buffer.anchor_after(range_to_move.end),
11927                    ) {
11928                        let mut start = fold.range.start.to_point(&buffer);
11929                        let mut end = fold.range.end.to_point(&buffer);
11930                        start.row += row_delta;
11931                        end.row += row_delta;
11932                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11933                    }
11934                }
11935            }
11936
11937            // If we didn't move line(s), preserve the existing selections
11938            new_selections.append(&mut contiguous_row_selections);
11939        }
11940
11941        self.transact(window, cx, |this, window, cx| {
11942            this.unfold_ranges(&unfold_ranges, true, true, cx);
11943            this.buffer.update(cx, |buffer, cx| {
11944                for (range, text) in edits {
11945                    buffer.edit([(range, text)], None, cx);
11946                }
11947            });
11948            this.fold_creases(refold_creases, true, window, cx);
11949            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11950        });
11951    }
11952
11953    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11954        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11955        let text_layout_details = &self.text_layout_details(window);
11956        self.transact(window, cx, |this, window, cx| {
11957            let edits = this.change_selections(Default::default(), window, cx, |s| {
11958                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11959                s.move_with(|display_map, selection| {
11960                    if !selection.is_empty() {
11961                        return;
11962                    }
11963
11964                    let mut head = selection.head();
11965                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11966                    if head.column() == display_map.line_len(head.row()) {
11967                        transpose_offset = display_map
11968                            .buffer_snapshot()
11969                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11970                    }
11971
11972                    if transpose_offset == 0 {
11973                        return;
11974                    }
11975
11976                    *head.column_mut() += 1;
11977                    head = display_map.clip_point(head, Bias::Right);
11978                    let goal = SelectionGoal::HorizontalPosition(
11979                        display_map
11980                            .x_for_display_point(head, text_layout_details)
11981                            .into(),
11982                    );
11983                    selection.collapse_to(head, goal);
11984
11985                    let transpose_start = display_map
11986                        .buffer_snapshot()
11987                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11988                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11989                        let transpose_end = display_map
11990                            .buffer_snapshot()
11991                            .clip_offset(transpose_offset + 1, Bias::Right);
11992                        if let Some(ch) = display_map
11993                            .buffer_snapshot()
11994                            .chars_at(transpose_start)
11995                            .next()
11996                        {
11997                            edits.push((transpose_start..transpose_offset, String::new()));
11998                            edits.push((transpose_end..transpose_end, ch.to_string()));
11999                        }
12000                    }
12001                });
12002                edits
12003            });
12004            this.buffer
12005                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12006            let selections = this.selections.all::<usize>(cx);
12007            this.change_selections(Default::default(), window, cx, |s| {
12008                s.select(selections);
12009            });
12010        });
12011    }
12012
12013    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12014        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12015        if self.mode.is_single_line() {
12016            cx.propagate();
12017            return;
12018        }
12019
12020        self.rewrap_impl(RewrapOptions::default(), cx)
12021    }
12022
12023    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12024        let buffer = self.buffer.read(cx).snapshot(cx);
12025        let selections = self.selections.all::<Point>(cx);
12026
12027        #[derive(Clone, Debug, PartialEq)]
12028        enum CommentFormat {
12029            /// single line comment, with prefix for line
12030            Line(String),
12031            /// single line within a block comment, with prefix for line
12032            BlockLine(String),
12033            /// a single line of a block comment that includes the initial delimiter
12034            BlockCommentWithStart(BlockCommentConfig),
12035            /// a single line of a block comment that includes the ending delimiter
12036            BlockCommentWithEnd(BlockCommentConfig),
12037        }
12038
12039        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12040        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12041            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12042                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12043                .peekable();
12044
12045            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12046                row
12047            } else {
12048                return Vec::new();
12049            };
12050
12051            let language_settings = buffer.language_settings_at(selection.head(), cx);
12052            let language_scope = buffer.language_scope_at(selection.head());
12053
12054            let indent_and_prefix_for_row =
12055                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12056                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12057                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12058                        &language_scope
12059                    {
12060                        let indent_end = Point::new(row, indent.len);
12061                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12062                        let line_text_after_indent = buffer
12063                            .text_for_range(indent_end..line_end)
12064                            .collect::<String>();
12065
12066                        let is_within_comment_override = buffer
12067                            .language_scope_at(indent_end)
12068                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12069                        let comment_delimiters = if is_within_comment_override {
12070                            // we are within a comment syntax node, but we don't
12071                            // yet know what kind of comment: block, doc or line
12072                            match (
12073                                language_scope.documentation_comment(),
12074                                language_scope.block_comment(),
12075                            ) {
12076                                (Some(config), _) | (_, Some(config))
12077                                    if buffer.contains_str_at(indent_end, &config.start) =>
12078                                {
12079                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12080                                }
12081                                (Some(config), _) | (_, Some(config))
12082                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12083                                {
12084                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12085                                }
12086                                (Some(config), _) | (_, Some(config))
12087                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12088                                {
12089                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12090                                }
12091                                (_, _) => language_scope
12092                                    .line_comment_prefixes()
12093                                    .iter()
12094                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12095                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12096                            }
12097                        } else {
12098                            // we not in an overridden comment node, but we may
12099                            // be within a non-overridden line comment node
12100                            language_scope
12101                                .line_comment_prefixes()
12102                                .iter()
12103                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12104                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12105                        };
12106
12107                        let rewrap_prefix = language_scope
12108                            .rewrap_prefixes()
12109                            .iter()
12110                            .find_map(|prefix_regex| {
12111                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12112                                    if mat.start() == 0 {
12113                                        Some(mat.as_str().to_string())
12114                                    } else {
12115                                        None
12116                                    }
12117                                })
12118                            })
12119                            .flatten();
12120                        (comment_delimiters, rewrap_prefix)
12121                    } else {
12122                        (None, None)
12123                    };
12124                    (indent, comment_prefix, rewrap_prefix)
12125                };
12126
12127            let mut ranges = Vec::new();
12128            let from_empty_selection = selection.is_empty();
12129
12130            let mut current_range_start = first_row;
12131            let mut prev_row = first_row;
12132            let (
12133                mut current_range_indent,
12134                mut current_range_comment_delimiters,
12135                mut current_range_rewrap_prefix,
12136            ) = indent_and_prefix_for_row(first_row);
12137
12138            for row in non_blank_rows_iter.skip(1) {
12139                let has_paragraph_break = row > prev_row + 1;
12140
12141                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12142                    indent_and_prefix_for_row(row);
12143
12144                let has_indent_change = row_indent != current_range_indent;
12145                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12146
12147                let has_boundary_change = has_comment_change
12148                    || row_rewrap_prefix.is_some()
12149                    || (has_indent_change && current_range_comment_delimiters.is_some());
12150
12151                if has_paragraph_break || has_boundary_change {
12152                    ranges.push((
12153                        language_settings.clone(),
12154                        Point::new(current_range_start, 0)
12155                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12156                        current_range_indent,
12157                        current_range_comment_delimiters.clone(),
12158                        current_range_rewrap_prefix.clone(),
12159                        from_empty_selection,
12160                    ));
12161                    current_range_start = row;
12162                    current_range_indent = row_indent;
12163                    current_range_comment_delimiters = row_comment_delimiters;
12164                    current_range_rewrap_prefix = row_rewrap_prefix;
12165                }
12166                prev_row = row;
12167            }
12168
12169            ranges.push((
12170                language_settings.clone(),
12171                Point::new(current_range_start, 0)
12172                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12173                current_range_indent,
12174                current_range_comment_delimiters,
12175                current_range_rewrap_prefix,
12176                from_empty_selection,
12177            ));
12178
12179            ranges
12180        });
12181
12182        let mut edits = Vec::new();
12183        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12184
12185        for (
12186            language_settings,
12187            wrap_range,
12188            mut indent_size,
12189            comment_prefix,
12190            rewrap_prefix,
12191            from_empty_selection,
12192        ) in wrap_ranges
12193        {
12194            let mut start_row = wrap_range.start.row;
12195            let mut end_row = wrap_range.end.row;
12196
12197            // Skip selections that overlap with a range that has already been rewrapped.
12198            let selection_range = start_row..end_row;
12199            if rewrapped_row_ranges
12200                .iter()
12201                .any(|range| range.overlaps(&selection_range))
12202            {
12203                continue;
12204            }
12205
12206            let tab_size = language_settings.tab_size;
12207
12208            let (line_prefix, inside_comment) = match &comment_prefix {
12209                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12210                    (Some(prefix.as_str()), true)
12211                }
12212                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12213                    (Some(prefix.as_ref()), true)
12214                }
12215                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12216                    start: _,
12217                    end: _,
12218                    prefix,
12219                    tab_size,
12220                })) => {
12221                    indent_size.len += tab_size;
12222                    (Some(prefix.as_ref()), true)
12223                }
12224                None => (None, false),
12225            };
12226            let indent_prefix = indent_size.chars().collect::<String>();
12227            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12228
12229            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12230                RewrapBehavior::InComments => inside_comment,
12231                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12232                RewrapBehavior::Anywhere => true,
12233            };
12234
12235            let should_rewrap = options.override_language_settings
12236                || allow_rewrap_based_on_language
12237                || self.hard_wrap.is_some();
12238            if !should_rewrap {
12239                continue;
12240            }
12241
12242            if from_empty_selection {
12243                'expand_upwards: while start_row > 0 {
12244                    let prev_row = start_row - 1;
12245                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12246                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12247                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12248                    {
12249                        start_row = prev_row;
12250                    } else {
12251                        break 'expand_upwards;
12252                    }
12253                }
12254
12255                'expand_downwards: while end_row < buffer.max_point().row {
12256                    let next_row = end_row + 1;
12257                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12258                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12259                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12260                    {
12261                        end_row = next_row;
12262                    } else {
12263                        break 'expand_downwards;
12264                    }
12265                }
12266            }
12267
12268            let start = Point::new(start_row, 0);
12269            let start_offset = ToOffset::to_offset(&start, &buffer);
12270            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12271            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12272            let mut first_line_delimiter = None;
12273            let mut last_line_delimiter = None;
12274            let Some(lines_without_prefixes) = selection_text
12275                .lines()
12276                .enumerate()
12277                .map(|(ix, line)| {
12278                    let line_trimmed = line.trim_start();
12279                    if rewrap_prefix.is_some() && ix > 0 {
12280                        Ok(line_trimmed)
12281                    } else if let Some(
12282                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12283                            start,
12284                            prefix,
12285                            end,
12286                            tab_size,
12287                        })
12288                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12289                            start,
12290                            prefix,
12291                            end,
12292                            tab_size,
12293                        }),
12294                    ) = &comment_prefix
12295                    {
12296                        let line_trimmed = line_trimmed
12297                            .strip_prefix(start.as_ref())
12298                            .map(|s| {
12299                                let mut indent_size = indent_size;
12300                                indent_size.len -= tab_size;
12301                                let indent_prefix: String = indent_size.chars().collect();
12302                                first_line_delimiter = Some((indent_prefix, start));
12303                                s.trim_start()
12304                            })
12305                            .unwrap_or(line_trimmed);
12306                        let line_trimmed = line_trimmed
12307                            .strip_suffix(end.as_ref())
12308                            .map(|s| {
12309                                last_line_delimiter = Some(end);
12310                                s.trim_end()
12311                            })
12312                            .unwrap_or(line_trimmed);
12313                        let line_trimmed = line_trimmed
12314                            .strip_prefix(prefix.as_ref())
12315                            .unwrap_or(line_trimmed);
12316                        Ok(line_trimmed)
12317                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12318                        line_trimmed.strip_prefix(prefix).with_context(|| {
12319                            format!("line did not start with prefix {prefix:?}: {line:?}")
12320                        })
12321                    } else {
12322                        line_trimmed
12323                            .strip_prefix(&line_prefix.trim_start())
12324                            .with_context(|| {
12325                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12326                            })
12327                    }
12328                })
12329                .collect::<Result<Vec<_>, _>>()
12330                .log_err()
12331            else {
12332                continue;
12333            };
12334
12335            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12336                buffer
12337                    .language_settings_at(Point::new(start_row, 0), cx)
12338                    .preferred_line_length as usize
12339            });
12340
12341            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12342                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12343            } else {
12344                line_prefix.clone()
12345            };
12346
12347            let wrapped_text = {
12348                let mut wrapped_text = wrap_with_prefix(
12349                    line_prefix,
12350                    subsequent_lines_prefix,
12351                    lines_without_prefixes.join("\n"),
12352                    wrap_column,
12353                    tab_size,
12354                    options.preserve_existing_whitespace,
12355                );
12356
12357                if let Some((indent, delimiter)) = first_line_delimiter {
12358                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12359                }
12360                if let Some(last_line) = last_line_delimiter {
12361                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12362                }
12363
12364                wrapped_text
12365            };
12366
12367            // TODO: should always use char-based diff while still supporting cursor behavior that
12368            // matches vim.
12369            let mut diff_options = DiffOptions::default();
12370            if options.override_language_settings {
12371                diff_options.max_word_diff_len = 0;
12372                diff_options.max_word_diff_line_count = 0;
12373            } else {
12374                diff_options.max_word_diff_len = usize::MAX;
12375                diff_options.max_word_diff_line_count = usize::MAX;
12376            }
12377
12378            for (old_range, new_text) in
12379                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12380            {
12381                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12382                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12383                edits.push((edit_start..edit_end, new_text));
12384            }
12385
12386            rewrapped_row_ranges.push(start_row..=end_row);
12387        }
12388
12389        self.buffer
12390            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12391    }
12392
12393    pub fn cut_common(
12394        &mut self,
12395        cut_no_selection_line: bool,
12396        window: &mut Window,
12397        cx: &mut Context<Self>,
12398    ) -> ClipboardItem {
12399        let mut text = String::new();
12400        let buffer = self.buffer.read(cx).snapshot(cx);
12401        let mut selections = self.selections.all::<Point>(cx);
12402        let mut clipboard_selections = Vec::with_capacity(selections.len());
12403        {
12404            let max_point = buffer.max_point();
12405            let mut is_first = true;
12406            for selection in &mut selections {
12407                let is_entire_line =
12408                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12409                if is_entire_line {
12410                    selection.start = Point::new(selection.start.row, 0);
12411                    if !selection.is_empty() && selection.end.column == 0 {
12412                        selection.end = cmp::min(max_point, selection.end);
12413                    } else {
12414                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12415                    }
12416                    selection.goal = SelectionGoal::None;
12417                }
12418                if is_first {
12419                    is_first = false;
12420                } else {
12421                    text += "\n";
12422                }
12423                let mut len = 0;
12424                for chunk in buffer.text_for_range(selection.start..selection.end) {
12425                    text.push_str(chunk);
12426                    len += chunk.len();
12427                }
12428                clipboard_selections.push(ClipboardSelection {
12429                    len,
12430                    is_entire_line,
12431                    first_line_indent: buffer
12432                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12433                        .len,
12434                });
12435            }
12436        }
12437
12438        self.transact(window, cx, |this, window, cx| {
12439            this.change_selections(Default::default(), window, cx, |s| {
12440                s.select(selections);
12441            });
12442            this.insert("", window, cx);
12443        });
12444        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12445    }
12446
12447    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12448        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12449        let item = self.cut_common(true, window, cx);
12450        cx.write_to_clipboard(item);
12451    }
12452
12453    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12454        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12455        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12456            s.move_with(|snapshot, sel| {
12457                if sel.is_empty() {
12458                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12459                }
12460                if sel.is_empty() {
12461                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12462                }
12463            });
12464        });
12465        let item = self.cut_common(false, window, cx);
12466        cx.set_global(KillRing(item))
12467    }
12468
12469    pub fn kill_ring_yank(
12470        &mut self,
12471        _: &KillRingYank,
12472        window: &mut Window,
12473        cx: &mut Context<Self>,
12474    ) {
12475        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12476        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12477            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12478                (kill_ring.text().to_string(), kill_ring.metadata_json())
12479            } else {
12480                return;
12481            }
12482        } else {
12483            return;
12484        };
12485        self.do_paste(&text, metadata, false, window, cx);
12486    }
12487
12488    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12489        self.do_copy(true, cx);
12490    }
12491
12492    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12493        self.do_copy(false, cx);
12494    }
12495
12496    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12497        let selections = self.selections.all::<Point>(cx);
12498        let buffer = self.buffer.read(cx).read(cx);
12499        let mut text = String::new();
12500
12501        let mut clipboard_selections = Vec::with_capacity(selections.len());
12502        {
12503            let max_point = buffer.max_point();
12504            let mut is_first = true;
12505            for selection in &selections {
12506                let mut start = selection.start;
12507                let mut end = selection.end;
12508                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12509                if is_entire_line {
12510                    start = Point::new(start.row, 0);
12511                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12512                }
12513
12514                let mut trimmed_selections = Vec::new();
12515                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12516                    let row = MultiBufferRow(start.row);
12517                    let first_indent = buffer.indent_size_for_line(row);
12518                    if first_indent.len == 0 || start.column > first_indent.len {
12519                        trimmed_selections.push(start..end);
12520                    } else {
12521                        trimmed_selections.push(
12522                            Point::new(row.0, first_indent.len)
12523                                ..Point::new(row.0, buffer.line_len(row)),
12524                        );
12525                        for row in start.row + 1..=end.row {
12526                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12527                            if row == end.row {
12528                                line_len = end.column;
12529                            }
12530                            if line_len == 0 {
12531                                trimmed_selections
12532                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12533                                continue;
12534                            }
12535                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12536                            if row_indent_size.len >= first_indent.len {
12537                                trimmed_selections.push(
12538                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12539                                );
12540                            } else {
12541                                trimmed_selections.clear();
12542                                trimmed_selections.push(start..end);
12543                                break;
12544                            }
12545                        }
12546                    }
12547                } else {
12548                    trimmed_selections.push(start..end);
12549                }
12550
12551                for trimmed_range in trimmed_selections {
12552                    if is_first {
12553                        is_first = false;
12554                    } else {
12555                        text += "\n";
12556                    }
12557                    let mut len = 0;
12558                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12559                        text.push_str(chunk);
12560                        len += chunk.len();
12561                    }
12562                    clipboard_selections.push(ClipboardSelection {
12563                        len,
12564                        is_entire_line,
12565                        first_line_indent: buffer
12566                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12567                            .len,
12568                    });
12569                }
12570            }
12571        }
12572
12573        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12574            text,
12575            clipboard_selections,
12576        ));
12577    }
12578
12579    pub fn do_paste(
12580        &mut self,
12581        text: &String,
12582        clipboard_selections: Option<Vec<ClipboardSelection>>,
12583        handle_entire_lines: bool,
12584        window: &mut Window,
12585        cx: &mut Context<Self>,
12586    ) {
12587        if self.read_only(cx) {
12588            return;
12589        }
12590
12591        let clipboard_text = Cow::Borrowed(text.as_str());
12592
12593        self.transact(window, cx, |this, window, cx| {
12594            let had_active_edit_prediction = this.has_active_edit_prediction();
12595            let old_selections = this.selections.all::<usize>(cx);
12596            let cursor_offset = this.selections.last::<usize>(cx).head();
12597
12598            if let Some(mut clipboard_selections) = clipboard_selections {
12599                let all_selections_were_entire_line =
12600                    clipboard_selections.iter().all(|s| s.is_entire_line);
12601                let first_selection_indent_column =
12602                    clipboard_selections.first().map(|s| s.first_line_indent);
12603                if clipboard_selections.len() != old_selections.len() {
12604                    clipboard_selections.drain(..);
12605                }
12606                let mut auto_indent_on_paste = true;
12607
12608                this.buffer.update(cx, |buffer, cx| {
12609                    let snapshot = buffer.read(cx);
12610                    auto_indent_on_paste = snapshot
12611                        .language_settings_at(cursor_offset, cx)
12612                        .auto_indent_on_paste;
12613
12614                    let mut start_offset = 0;
12615                    let mut edits = Vec::new();
12616                    let mut original_indent_columns = Vec::new();
12617                    for (ix, selection) in old_selections.iter().enumerate() {
12618                        let to_insert;
12619                        let entire_line;
12620                        let original_indent_column;
12621                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12622                            let end_offset = start_offset + clipboard_selection.len;
12623                            to_insert = &clipboard_text[start_offset..end_offset];
12624                            entire_line = clipboard_selection.is_entire_line;
12625                            start_offset = end_offset + 1;
12626                            original_indent_column = Some(clipboard_selection.first_line_indent);
12627                        } else {
12628                            to_insert = &*clipboard_text;
12629                            entire_line = all_selections_were_entire_line;
12630                            original_indent_column = first_selection_indent_column
12631                        }
12632
12633                        let (range, to_insert) =
12634                            if selection.is_empty() && handle_entire_lines && entire_line {
12635                                // If the corresponding selection was empty when this slice of the
12636                                // clipboard text was written, then the entire line containing the
12637                                // selection was copied. If this selection is also currently empty,
12638                                // then paste the line before the current line of the buffer.
12639                                let column = selection.start.to_point(&snapshot).column as usize;
12640                                let line_start = selection.start - column;
12641                                (line_start..line_start, Cow::Borrowed(to_insert))
12642                            } else {
12643                                let language = snapshot.language_at(selection.head());
12644                                let range = selection.range();
12645                                if let Some(language) = language
12646                                    && language.name() == "Markdown".into()
12647                                {
12648                                    edit_for_markdown_paste(
12649                                        &snapshot,
12650                                        range,
12651                                        to_insert,
12652                                        url::Url::parse(to_insert).ok(),
12653                                    )
12654                                } else {
12655                                    (range, Cow::Borrowed(to_insert))
12656                                }
12657                            };
12658
12659                        edits.push((range, to_insert));
12660                        original_indent_columns.push(original_indent_column);
12661                    }
12662                    drop(snapshot);
12663
12664                    buffer.edit(
12665                        edits,
12666                        if auto_indent_on_paste {
12667                            Some(AutoindentMode::Block {
12668                                original_indent_columns,
12669                            })
12670                        } else {
12671                            None
12672                        },
12673                        cx,
12674                    );
12675                });
12676
12677                let selections = this.selections.all::<usize>(cx);
12678                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12679            } else {
12680                let url = url::Url::parse(&clipboard_text).ok();
12681
12682                let auto_indent_mode = if !clipboard_text.is_empty() {
12683                    Some(AutoindentMode::Block {
12684                        original_indent_columns: Vec::new(),
12685                    })
12686                } else {
12687                    None
12688                };
12689
12690                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12691                    let snapshot = buffer.snapshot(cx);
12692
12693                    let anchors = old_selections
12694                        .iter()
12695                        .map(|s| {
12696                            let anchor = snapshot.anchor_after(s.head());
12697                            s.map(|_| anchor)
12698                        })
12699                        .collect::<Vec<_>>();
12700
12701                    let mut edits = Vec::new();
12702
12703                    for selection in old_selections.iter() {
12704                        let language = snapshot.language_at(selection.head());
12705                        let range = selection.range();
12706
12707                        let (edit_range, edit_text) = if let Some(language) = language
12708                            && language.name() == "Markdown".into()
12709                        {
12710                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12711                        } else {
12712                            (range, clipboard_text.clone())
12713                        };
12714
12715                        edits.push((edit_range, edit_text));
12716                    }
12717
12718                    drop(snapshot);
12719                    buffer.edit(edits, auto_indent_mode, cx);
12720
12721                    anchors
12722                });
12723
12724                this.change_selections(Default::default(), window, cx, |s| {
12725                    s.select_anchors(selection_anchors);
12726                });
12727            }
12728
12729            let trigger_in_words =
12730                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12731
12732            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12733        });
12734    }
12735
12736    pub fn diff_clipboard_with_selection(
12737        &mut self,
12738        _: &DiffClipboardWithSelection,
12739        window: &mut Window,
12740        cx: &mut Context<Self>,
12741    ) {
12742        let selections = self.selections.all::<usize>(cx);
12743
12744        if selections.is_empty() {
12745            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12746            return;
12747        };
12748
12749        let clipboard_text = match cx.read_from_clipboard() {
12750            Some(item) => match item.entries().first() {
12751                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12752                _ => None,
12753            },
12754            None => None,
12755        };
12756
12757        let Some(clipboard_text) = clipboard_text else {
12758            log::warn!("Clipboard doesn't contain text.");
12759            return;
12760        };
12761
12762        window.dispatch_action(
12763            Box::new(DiffClipboardWithSelectionData {
12764                clipboard_text,
12765                editor: cx.entity(),
12766            }),
12767            cx,
12768        );
12769    }
12770
12771    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12772        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12773        if let Some(item) = cx.read_from_clipboard() {
12774            let entries = item.entries();
12775
12776            match entries.first() {
12777                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12778                // of all the pasted entries.
12779                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12780                    .do_paste(
12781                        clipboard_string.text(),
12782                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12783                        true,
12784                        window,
12785                        cx,
12786                    ),
12787                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12788            }
12789        }
12790    }
12791
12792    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12793        if self.read_only(cx) {
12794            return;
12795        }
12796
12797        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12798
12799        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12800            if let Some((selections, _)) =
12801                self.selection_history.transaction(transaction_id).cloned()
12802            {
12803                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12804                    s.select_anchors(selections.to_vec());
12805                });
12806            } else {
12807                log::error!(
12808                    "No entry in selection_history found for undo. \
12809                     This may correspond to a bug where undo does not update the selection. \
12810                     If this is occurring, please add details to \
12811                     https://github.com/zed-industries/zed/issues/22692"
12812                );
12813            }
12814            self.request_autoscroll(Autoscroll::fit(), cx);
12815            self.unmark_text(window, cx);
12816            self.refresh_edit_prediction(true, false, window, cx);
12817            cx.emit(EditorEvent::Edited { transaction_id });
12818            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12819        }
12820    }
12821
12822    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12823        if self.read_only(cx) {
12824            return;
12825        }
12826
12827        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12828
12829        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12830            if let Some((_, Some(selections))) =
12831                self.selection_history.transaction(transaction_id).cloned()
12832            {
12833                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12834                    s.select_anchors(selections.to_vec());
12835                });
12836            } else {
12837                log::error!(
12838                    "No entry in selection_history found for redo. \
12839                     This may correspond to a bug where undo does not update the selection. \
12840                     If this is occurring, please add details to \
12841                     https://github.com/zed-industries/zed/issues/22692"
12842                );
12843            }
12844            self.request_autoscroll(Autoscroll::fit(), cx);
12845            self.unmark_text(window, cx);
12846            self.refresh_edit_prediction(true, false, window, cx);
12847            cx.emit(EditorEvent::Edited { transaction_id });
12848        }
12849    }
12850
12851    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12852        self.buffer
12853            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12854    }
12855
12856    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12857        self.buffer
12858            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12859    }
12860
12861    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12862        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12863        self.change_selections(Default::default(), window, cx, |s| {
12864            s.move_with(|map, selection| {
12865                let cursor = if selection.is_empty() {
12866                    movement::left(map, selection.start)
12867                } else {
12868                    selection.start
12869                };
12870                selection.collapse_to(cursor, SelectionGoal::None);
12871            });
12872        })
12873    }
12874
12875    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12876        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12877        self.change_selections(Default::default(), window, cx, |s| {
12878            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12879        })
12880    }
12881
12882    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12883        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12884        self.change_selections(Default::default(), window, cx, |s| {
12885            s.move_with(|map, selection| {
12886                let cursor = if selection.is_empty() {
12887                    movement::right(map, selection.end)
12888                } else {
12889                    selection.end
12890                };
12891                selection.collapse_to(cursor, SelectionGoal::None)
12892            });
12893        })
12894    }
12895
12896    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12897        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12898        self.change_selections(Default::default(), window, cx, |s| {
12899            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12900        });
12901    }
12902
12903    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12904        if self.take_rename(true, window, cx).is_some() {
12905            return;
12906        }
12907
12908        if self.mode.is_single_line() {
12909            cx.propagate();
12910            return;
12911        }
12912
12913        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12914
12915        let text_layout_details = &self.text_layout_details(window);
12916        let selection_count = self.selections.count();
12917        let first_selection = self.selections.first_anchor();
12918
12919        self.change_selections(Default::default(), window, cx, |s| {
12920            s.move_with(|map, selection| {
12921                if !selection.is_empty() {
12922                    selection.goal = SelectionGoal::None;
12923                }
12924                let (cursor, goal) = movement::up(
12925                    map,
12926                    selection.start,
12927                    selection.goal,
12928                    false,
12929                    text_layout_details,
12930                );
12931                selection.collapse_to(cursor, goal);
12932            });
12933        });
12934
12935        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12936        {
12937            cx.propagate();
12938        }
12939    }
12940
12941    pub fn move_up_by_lines(
12942        &mut self,
12943        action: &MoveUpByLines,
12944        window: &mut Window,
12945        cx: &mut Context<Self>,
12946    ) {
12947        if self.take_rename(true, window, cx).is_some() {
12948            return;
12949        }
12950
12951        if self.mode.is_single_line() {
12952            cx.propagate();
12953            return;
12954        }
12955
12956        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12957
12958        let text_layout_details = &self.text_layout_details(window);
12959
12960        self.change_selections(Default::default(), window, cx, |s| {
12961            s.move_with(|map, selection| {
12962                if !selection.is_empty() {
12963                    selection.goal = SelectionGoal::None;
12964                }
12965                let (cursor, goal) = movement::up_by_rows(
12966                    map,
12967                    selection.start,
12968                    action.lines,
12969                    selection.goal,
12970                    false,
12971                    text_layout_details,
12972                );
12973                selection.collapse_to(cursor, goal);
12974            });
12975        })
12976    }
12977
12978    pub fn move_down_by_lines(
12979        &mut self,
12980        action: &MoveDownByLines,
12981        window: &mut Window,
12982        cx: &mut Context<Self>,
12983    ) {
12984        if self.take_rename(true, window, cx).is_some() {
12985            return;
12986        }
12987
12988        if self.mode.is_single_line() {
12989            cx.propagate();
12990            return;
12991        }
12992
12993        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12994
12995        let text_layout_details = &self.text_layout_details(window);
12996
12997        self.change_selections(Default::default(), window, cx, |s| {
12998            s.move_with(|map, selection| {
12999                if !selection.is_empty() {
13000                    selection.goal = SelectionGoal::None;
13001                }
13002                let (cursor, goal) = movement::down_by_rows(
13003                    map,
13004                    selection.start,
13005                    action.lines,
13006                    selection.goal,
13007                    false,
13008                    text_layout_details,
13009                );
13010                selection.collapse_to(cursor, goal);
13011            });
13012        })
13013    }
13014
13015    pub fn select_down_by_lines(
13016        &mut self,
13017        action: &SelectDownByLines,
13018        window: &mut Window,
13019        cx: &mut Context<Self>,
13020    ) {
13021        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13022        let text_layout_details = &self.text_layout_details(window);
13023        self.change_selections(Default::default(), window, cx, |s| {
13024            s.move_heads_with(|map, head, goal| {
13025                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13026            })
13027        })
13028    }
13029
13030    pub fn select_up_by_lines(
13031        &mut self,
13032        action: &SelectUpByLines,
13033        window: &mut Window,
13034        cx: &mut Context<Self>,
13035    ) {
13036        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13037        let text_layout_details = &self.text_layout_details(window);
13038        self.change_selections(Default::default(), window, cx, |s| {
13039            s.move_heads_with(|map, head, goal| {
13040                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13041            })
13042        })
13043    }
13044
13045    pub fn select_page_up(
13046        &mut self,
13047        _: &SelectPageUp,
13048        window: &mut Window,
13049        cx: &mut Context<Self>,
13050    ) {
13051        let Some(row_count) = self.visible_row_count() else {
13052            return;
13053        };
13054
13055        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13056
13057        let text_layout_details = &self.text_layout_details(window);
13058
13059        self.change_selections(Default::default(), window, cx, |s| {
13060            s.move_heads_with(|map, head, goal| {
13061                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13062            })
13063        })
13064    }
13065
13066    pub fn move_page_up(
13067        &mut self,
13068        action: &MovePageUp,
13069        window: &mut Window,
13070        cx: &mut Context<Self>,
13071    ) {
13072        if self.take_rename(true, window, cx).is_some() {
13073            return;
13074        }
13075
13076        if self
13077            .context_menu
13078            .borrow_mut()
13079            .as_mut()
13080            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13081            .unwrap_or(false)
13082        {
13083            return;
13084        }
13085
13086        if matches!(self.mode, EditorMode::SingleLine) {
13087            cx.propagate();
13088            return;
13089        }
13090
13091        let Some(row_count) = self.visible_row_count() else {
13092            return;
13093        };
13094
13095        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13096
13097        let effects = if action.center_cursor {
13098            SelectionEffects::scroll(Autoscroll::center())
13099        } else {
13100            SelectionEffects::default()
13101        };
13102
13103        let text_layout_details = &self.text_layout_details(window);
13104
13105        self.change_selections(effects, window, cx, |s| {
13106            s.move_with(|map, selection| {
13107                if !selection.is_empty() {
13108                    selection.goal = SelectionGoal::None;
13109                }
13110                let (cursor, goal) = movement::up_by_rows(
13111                    map,
13112                    selection.end,
13113                    row_count,
13114                    selection.goal,
13115                    false,
13116                    text_layout_details,
13117                );
13118                selection.collapse_to(cursor, goal);
13119            });
13120        });
13121    }
13122
13123    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13124        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13125        let text_layout_details = &self.text_layout_details(window);
13126        self.change_selections(Default::default(), window, cx, |s| {
13127            s.move_heads_with(|map, head, goal| {
13128                movement::up(map, head, goal, false, text_layout_details)
13129            })
13130        })
13131    }
13132
13133    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13134        self.take_rename(true, window, cx);
13135
13136        if self.mode.is_single_line() {
13137            cx.propagate();
13138            return;
13139        }
13140
13141        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13142
13143        let text_layout_details = &self.text_layout_details(window);
13144        let selection_count = self.selections.count();
13145        let first_selection = self.selections.first_anchor();
13146
13147        self.change_selections(Default::default(), window, cx, |s| {
13148            s.move_with(|map, selection| {
13149                if !selection.is_empty() {
13150                    selection.goal = SelectionGoal::None;
13151                }
13152                let (cursor, goal) = movement::down(
13153                    map,
13154                    selection.end,
13155                    selection.goal,
13156                    false,
13157                    text_layout_details,
13158                );
13159                selection.collapse_to(cursor, goal);
13160            });
13161        });
13162
13163        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13164        {
13165            cx.propagate();
13166        }
13167    }
13168
13169    pub fn select_page_down(
13170        &mut self,
13171        _: &SelectPageDown,
13172        window: &mut Window,
13173        cx: &mut Context<Self>,
13174    ) {
13175        let Some(row_count) = self.visible_row_count() else {
13176            return;
13177        };
13178
13179        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13180
13181        let text_layout_details = &self.text_layout_details(window);
13182
13183        self.change_selections(Default::default(), window, cx, |s| {
13184            s.move_heads_with(|map, head, goal| {
13185                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13186            })
13187        })
13188    }
13189
13190    pub fn move_page_down(
13191        &mut self,
13192        action: &MovePageDown,
13193        window: &mut Window,
13194        cx: &mut Context<Self>,
13195    ) {
13196        if self.take_rename(true, window, cx).is_some() {
13197            return;
13198        }
13199
13200        if self
13201            .context_menu
13202            .borrow_mut()
13203            .as_mut()
13204            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13205            .unwrap_or(false)
13206        {
13207            return;
13208        }
13209
13210        if matches!(self.mode, EditorMode::SingleLine) {
13211            cx.propagate();
13212            return;
13213        }
13214
13215        let Some(row_count) = self.visible_row_count() else {
13216            return;
13217        };
13218
13219        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13220
13221        let effects = if action.center_cursor {
13222            SelectionEffects::scroll(Autoscroll::center())
13223        } else {
13224            SelectionEffects::default()
13225        };
13226
13227        let text_layout_details = &self.text_layout_details(window);
13228        self.change_selections(effects, window, cx, |s| {
13229            s.move_with(|map, selection| {
13230                if !selection.is_empty() {
13231                    selection.goal = SelectionGoal::None;
13232                }
13233                let (cursor, goal) = movement::down_by_rows(
13234                    map,
13235                    selection.end,
13236                    row_count,
13237                    selection.goal,
13238                    false,
13239                    text_layout_details,
13240                );
13241                selection.collapse_to(cursor, goal);
13242            });
13243        });
13244    }
13245
13246    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13247        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13248        let text_layout_details = &self.text_layout_details(window);
13249        self.change_selections(Default::default(), window, cx, |s| {
13250            s.move_heads_with(|map, head, goal| {
13251                movement::down(map, head, goal, false, text_layout_details)
13252            })
13253        });
13254    }
13255
13256    pub fn context_menu_first(
13257        &mut self,
13258        _: &ContextMenuFirst,
13259        window: &mut Window,
13260        cx: &mut Context<Self>,
13261    ) {
13262        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13263            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13264        }
13265    }
13266
13267    pub fn context_menu_prev(
13268        &mut self,
13269        _: &ContextMenuPrevious,
13270        window: &mut Window,
13271        cx: &mut Context<Self>,
13272    ) {
13273        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13274            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13275        }
13276    }
13277
13278    pub fn context_menu_next(
13279        &mut self,
13280        _: &ContextMenuNext,
13281        window: &mut Window,
13282        cx: &mut Context<Self>,
13283    ) {
13284        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13285            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13286        }
13287    }
13288
13289    pub fn context_menu_last(
13290        &mut self,
13291        _: &ContextMenuLast,
13292        window: &mut Window,
13293        cx: &mut Context<Self>,
13294    ) {
13295        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13296            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13297        }
13298    }
13299
13300    pub fn signature_help_prev(
13301        &mut self,
13302        _: &SignatureHelpPrevious,
13303        _: &mut Window,
13304        cx: &mut Context<Self>,
13305    ) {
13306        if let Some(popover) = self.signature_help_state.popover_mut() {
13307            if popover.current_signature == 0 {
13308                popover.current_signature = popover.signatures.len() - 1;
13309            } else {
13310                popover.current_signature -= 1;
13311            }
13312            cx.notify();
13313        }
13314    }
13315
13316    pub fn signature_help_next(
13317        &mut self,
13318        _: &SignatureHelpNext,
13319        _: &mut Window,
13320        cx: &mut Context<Self>,
13321    ) {
13322        if let Some(popover) = self.signature_help_state.popover_mut() {
13323            if popover.current_signature + 1 == popover.signatures.len() {
13324                popover.current_signature = 0;
13325            } else {
13326                popover.current_signature += 1;
13327            }
13328            cx.notify();
13329        }
13330    }
13331
13332    pub fn move_to_previous_word_start(
13333        &mut self,
13334        _: &MoveToPreviousWordStart,
13335        window: &mut Window,
13336        cx: &mut Context<Self>,
13337    ) {
13338        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13339        self.change_selections(Default::default(), window, cx, |s| {
13340            s.move_cursors_with(|map, head, _| {
13341                (
13342                    movement::previous_word_start(map, head),
13343                    SelectionGoal::None,
13344                )
13345            });
13346        })
13347    }
13348
13349    pub fn move_to_previous_subword_start(
13350        &mut self,
13351        _: &MoveToPreviousSubwordStart,
13352        window: &mut Window,
13353        cx: &mut Context<Self>,
13354    ) {
13355        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13356        self.change_selections(Default::default(), window, cx, |s| {
13357            s.move_cursors_with(|map, head, _| {
13358                (
13359                    movement::previous_subword_start(map, head),
13360                    SelectionGoal::None,
13361                )
13362            });
13363        })
13364    }
13365
13366    pub fn select_to_previous_word_start(
13367        &mut self,
13368        _: &SelectToPreviousWordStart,
13369        window: &mut Window,
13370        cx: &mut Context<Self>,
13371    ) {
13372        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13373        self.change_selections(Default::default(), window, cx, |s| {
13374            s.move_heads_with(|map, head, _| {
13375                (
13376                    movement::previous_word_start(map, head),
13377                    SelectionGoal::None,
13378                )
13379            });
13380        })
13381    }
13382
13383    pub fn select_to_previous_subword_start(
13384        &mut self,
13385        _: &SelectToPreviousSubwordStart,
13386        window: &mut Window,
13387        cx: &mut Context<Self>,
13388    ) {
13389        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13390        self.change_selections(Default::default(), window, cx, |s| {
13391            s.move_heads_with(|map, head, _| {
13392                (
13393                    movement::previous_subword_start(map, head),
13394                    SelectionGoal::None,
13395                )
13396            });
13397        })
13398    }
13399
13400    pub fn delete_to_previous_word_start(
13401        &mut self,
13402        action: &DeleteToPreviousWordStart,
13403        window: &mut Window,
13404        cx: &mut Context<Self>,
13405    ) {
13406        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13407        self.transact(window, cx, |this, window, cx| {
13408            this.select_autoclose_pair(window, cx);
13409            this.change_selections(Default::default(), window, cx, |s| {
13410                s.move_with(|map, selection| {
13411                    if selection.is_empty() {
13412                        let mut cursor = if action.ignore_newlines {
13413                            movement::previous_word_start(map, selection.head())
13414                        } else {
13415                            movement::previous_word_start_or_newline(map, selection.head())
13416                        };
13417                        cursor = movement::adjust_greedy_deletion(
13418                            map,
13419                            selection.head(),
13420                            cursor,
13421                            action.ignore_brackets,
13422                        );
13423                        selection.set_head(cursor, SelectionGoal::None);
13424                    }
13425                });
13426            });
13427            this.insert("", window, cx);
13428        });
13429    }
13430
13431    pub fn delete_to_previous_subword_start(
13432        &mut self,
13433        _: &DeleteToPreviousSubwordStart,
13434        window: &mut Window,
13435        cx: &mut Context<Self>,
13436    ) {
13437        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13438        self.transact(window, cx, |this, window, cx| {
13439            this.select_autoclose_pair(window, cx);
13440            this.change_selections(Default::default(), window, cx, |s| {
13441                s.move_with(|map, selection| {
13442                    if selection.is_empty() {
13443                        let mut cursor = movement::previous_subword_start(map, selection.head());
13444                        cursor =
13445                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13446                        selection.set_head(cursor, SelectionGoal::None);
13447                    }
13448                });
13449            });
13450            this.insert("", window, cx);
13451        });
13452    }
13453
13454    pub fn move_to_next_word_end(
13455        &mut self,
13456        _: &MoveToNextWordEnd,
13457        window: &mut Window,
13458        cx: &mut Context<Self>,
13459    ) {
13460        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13461        self.change_selections(Default::default(), window, cx, |s| {
13462            s.move_cursors_with(|map, head, _| {
13463                (movement::next_word_end(map, head), SelectionGoal::None)
13464            });
13465        })
13466    }
13467
13468    pub fn move_to_next_subword_end(
13469        &mut self,
13470        _: &MoveToNextSubwordEnd,
13471        window: &mut Window,
13472        cx: &mut Context<Self>,
13473    ) {
13474        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13475        self.change_selections(Default::default(), window, cx, |s| {
13476            s.move_cursors_with(|map, head, _| {
13477                (movement::next_subword_end(map, head), SelectionGoal::None)
13478            });
13479        })
13480    }
13481
13482    pub fn select_to_next_word_end(
13483        &mut self,
13484        _: &SelectToNextWordEnd,
13485        window: &mut Window,
13486        cx: &mut Context<Self>,
13487    ) {
13488        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13489        self.change_selections(Default::default(), window, cx, |s| {
13490            s.move_heads_with(|map, head, _| {
13491                (movement::next_word_end(map, head), SelectionGoal::None)
13492            });
13493        })
13494    }
13495
13496    pub fn select_to_next_subword_end(
13497        &mut self,
13498        _: &SelectToNextSubwordEnd,
13499        window: &mut Window,
13500        cx: &mut Context<Self>,
13501    ) {
13502        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13503        self.change_selections(Default::default(), window, cx, |s| {
13504            s.move_heads_with(|map, head, _| {
13505                (movement::next_subword_end(map, head), SelectionGoal::None)
13506            });
13507        })
13508    }
13509
13510    pub fn delete_to_next_word_end(
13511        &mut self,
13512        action: &DeleteToNextWordEnd,
13513        window: &mut Window,
13514        cx: &mut Context<Self>,
13515    ) {
13516        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13517        self.transact(window, cx, |this, window, cx| {
13518            this.change_selections(Default::default(), window, cx, |s| {
13519                s.move_with(|map, selection| {
13520                    if selection.is_empty() {
13521                        let mut cursor = if action.ignore_newlines {
13522                            movement::next_word_end(map, selection.head())
13523                        } else {
13524                            movement::next_word_end_or_newline(map, selection.head())
13525                        };
13526                        cursor = movement::adjust_greedy_deletion(
13527                            map,
13528                            selection.head(),
13529                            cursor,
13530                            action.ignore_brackets,
13531                        );
13532                        selection.set_head(cursor, SelectionGoal::None);
13533                    }
13534                });
13535            });
13536            this.insert("", window, cx);
13537        });
13538    }
13539
13540    pub fn delete_to_next_subword_end(
13541        &mut self,
13542        _: &DeleteToNextSubwordEnd,
13543        window: &mut Window,
13544        cx: &mut Context<Self>,
13545    ) {
13546        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13547        self.transact(window, cx, |this, window, cx| {
13548            this.change_selections(Default::default(), window, cx, |s| {
13549                s.move_with(|map, selection| {
13550                    if selection.is_empty() {
13551                        let mut cursor = movement::next_subword_end(map, selection.head());
13552                        cursor =
13553                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13554                        selection.set_head(cursor, SelectionGoal::None);
13555                    }
13556                });
13557            });
13558            this.insert("", window, cx);
13559        });
13560    }
13561
13562    pub fn move_to_beginning_of_line(
13563        &mut self,
13564        action: &MoveToBeginningOfLine,
13565        window: &mut Window,
13566        cx: &mut Context<Self>,
13567    ) {
13568        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13569        self.change_selections(Default::default(), window, cx, |s| {
13570            s.move_cursors_with(|map, head, _| {
13571                (
13572                    movement::indented_line_beginning(
13573                        map,
13574                        head,
13575                        action.stop_at_soft_wraps,
13576                        action.stop_at_indent,
13577                    ),
13578                    SelectionGoal::None,
13579                )
13580            });
13581        })
13582    }
13583
13584    pub fn select_to_beginning_of_line(
13585        &mut self,
13586        action: &SelectToBeginningOfLine,
13587        window: &mut Window,
13588        cx: &mut Context<Self>,
13589    ) {
13590        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13591        self.change_selections(Default::default(), window, cx, |s| {
13592            s.move_heads_with(|map, head, _| {
13593                (
13594                    movement::indented_line_beginning(
13595                        map,
13596                        head,
13597                        action.stop_at_soft_wraps,
13598                        action.stop_at_indent,
13599                    ),
13600                    SelectionGoal::None,
13601                )
13602            });
13603        });
13604    }
13605
13606    pub fn delete_to_beginning_of_line(
13607        &mut self,
13608        action: &DeleteToBeginningOfLine,
13609        window: &mut Window,
13610        cx: &mut Context<Self>,
13611    ) {
13612        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13613        self.transact(window, cx, |this, window, cx| {
13614            this.change_selections(Default::default(), window, cx, |s| {
13615                s.move_with(|_, selection| {
13616                    selection.reversed = true;
13617                });
13618            });
13619
13620            this.select_to_beginning_of_line(
13621                &SelectToBeginningOfLine {
13622                    stop_at_soft_wraps: false,
13623                    stop_at_indent: action.stop_at_indent,
13624                },
13625                window,
13626                cx,
13627            );
13628            this.backspace(&Backspace, window, cx);
13629        });
13630    }
13631
13632    pub fn move_to_end_of_line(
13633        &mut self,
13634        action: &MoveToEndOfLine,
13635        window: &mut Window,
13636        cx: &mut Context<Self>,
13637    ) {
13638        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13639        self.change_selections(Default::default(), window, cx, |s| {
13640            s.move_cursors_with(|map, head, _| {
13641                (
13642                    movement::line_end(map, head, action.stop_at_soft_wraps),
13643                    SelectionGoal::None,
13644                )
13645            });
13646        })
13647    }
13648
13649    pub fn select_to_end_of_line(
13650        &mut self,
13651        action: &SelectToEndOfLine,
13652        window: &mut Window,
13653        cx: &mut Context<Self>,
13654    ) {
13655        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13656        self.change_selections(Default::default(), window, cx, |s| {
13657            s.move_heads_with(|map, head, _| {
13658                (
13659                    movement::line_end(map, head, action.stop_at_soft_wraps),
13660                    SelectionGoal::None,
13661                )
13662            });
13663        })
13664    }
13665
13666    pub fn delete_to_end_of_line(
13667        &mut self,
13668        _: &DeleteToEndOfLine,
13669        window: &mut Window,
13670        cx: &mut Context<Self>,
13671    ) {
13672        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13673        self.transact(window, cx, |this, window, cx| {
13674            this.select_to_end_of_line(
13675                &SelectToEndOfLine {
13676                    stop_at_soft_wraps: false,
13677                },
13678                window,
13679                cx,
13680            );
13681            this.delete(&Delete, window, cx);
13682        });
13683    }
13684
13685    pub fn cut_to_end_of_line(
13686        &mut self,
13687        action: &CutToEndOfLine,
13688        window: &mut Window,
13689        cx: &mut Context<Self>,
13690    ) {
13691        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13692        self.transact(window, cx, |this, window, cx| {
13693            this.select_to_end_of_line(
13694                &SelectToEndOfLine {
13695                    stop_at_soft_wraps: false,
13696                },
13697                window,
13698                cx,
13699            );
13700            if !action.stop_at_newlines {
13701                this.change_selections(Default::default(), window, cx, |s| {
13702                    s.move_with(|_, sel| {
13703                        if sel.is_empty() {
13704                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13705                        }
13706                    });
13707                });
13708            }
13709            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13710            let item = this.cut_common(false, window, cx);
13711            cx.write_to_clipboard(item);
13712        });
13713    }
13714
13715    pub fn move_to_start_of_paragraph(
13716        &mut self,
13717        _: &MoveToStartOfParagraph,
13718        window: &mut Window,
13719        cx: &mut Context<Self>,
13720    ) {
13721        if matches!(self.mode, EditorMode::SingleLine) {
13722            cx.propagate();
13723            return;
13724        }
13725        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13726        self.change_selections(Default::default(), window, cx, |s| {
13727            s.move_with(|map, selection| {
13728                selection.collapse_to(
13729                    movement::start_of_paragraph(map, selection.head(), 1),
13730                    SelectionGoal::None,
13731                )
13732            });
13733        })
13734    }
13735
13736    pub fn move_to_end_of_paragraph(
13737        &mut self,
13738        _: &MoveToEndOfParagraph,
13739        window: &mut Window,
13740        cx: &mut Context<Self>,
13741    ) {
13742        if matches!(self.mode, EditorMode::SingleLine) {
13743            cx.propagate();
13744            return;
13745        }
13746        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13747        self.change_selections(Default::default(), window, cx, |s| {
13748            s.move_with(|map, selection| {
13749                selection.collapse_to(
13750                    movement::end_of_paragraph(map, selection.head(), 1),
13751                    SelectionGoal::None,
13752                )
13753            });
13754        })
13755    }
13756
13757    pub fn select_to_start_of_paragraph(
13758        &mut self,
13759        _: &SelectToStartOfParagraph,
13760        window: &mut Window,
13761        cx: &mut Context<Self>,
13762    ) {
13763        if matches!(self.mode, EditorMode::SingleLine) {
13764            cx.propagate();
13765            return;
13766        }
13767        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13768        self.change_selections(Default::default(), window, cx, |s| {
13769            s.move_heads_with(|map, head, _| {
13770                (
13771                    movement::start_of_paragraph(map, head, 1),
13772                    SelectionGoal::None,
13773                )
13774            });
13775        })
13776    }
13777
13778    pub fn select_to_end_of_paragraph(
13779        &mut self,
13780        _: &SelectToEndOfParagraph,
13781        window: &mut Window,
13782        cx: &mut Context<Self>,
13783    ) {
13784        if matches!(self.mode, EditorMode::SingleLine) {
13785            cx.propagate();
13786            return;
13787        }
13788        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13789        self.change_selections(Default::default(), window, cx, |s| {
13790            s.move_heads_with(|map, head, _| {
13791                (
13792                    movement::end_of_paragraph(map, head, 1),
13793                    SelectionGoal::None,
13794                )
13795            });
13796        })
13797    }
13798
13799    pub fn move_to_start_of_excerpt(
13800        &mut self,
13801        _: &MoveToStartOfExcerpt,
13802        window: &mut Window,
13803        cx: &mut Context<Self>,
13804    ) {
13805        if matches!(self.mode, EditorMode::SingleLine) {
13806            cx.propagate();
13807            return;
13808        }
13809        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13810        self.change_selections(Default::default(), window, cx, |s| {
13811            s.move_with(|map, selection| {
13812                selection.collapse_to(
13813                    movement::start_of_excerpt(
13814                        map,
13815                        selection.head(),
13816                        workspace::searchable::Direction::Prev,
13817                    ),
13818                    SelectionGoal::None,
13819                )
13820            });
13821        })
13822    }
13823
13824    pub fn move_to_start_of_next_excerpt(
13825        &mut self,
13826        _: &MoveToStartOfNextExcerpt,
13827        window: &mut Window,
13828        cx: &mut Context<Self>,
13829    ) {
13830        if matches!(self.mode, EditorMode::SingleLine) {
13831            cx.propagate();
13832            return;
13833        }
13834
13835        self.change_selections(Default::default(), window, cx, |s| {
13836            s.move_with(|map, selection| {
13837                selection.collapse_to(
13838                    movement::start_of_excerpt(
13839                        map,
13840                        selection.head(),
13841                        workspace::searchable::Direction::Next,
13842                    ),
13843                    SelectionGoal::None,
13844                )
13845            });
13846        })
13847    }
13848
13849    pub fn move_to_end_of_excerpt(
13850        &mut self,
13851        _: &MoveToEndOfExcerpt,
13852        window: &mut Window,
13853        cx: &mut Context<Self>,
13854    ) {
13855        if matches!(self.mode, EditorMode::SingleLine) {
13856            cx.propagate();
13857            return;
13858        }
13859        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13860        self.change_selections(Default::default(), window, cx, |s| {
13861            s.move_with(|map, selection| {
13862                selection.collapse_to(
13863                    movement::end_of_excerpt(
13864                        map,
13865                        selection.head(),
13866                        workspace::searchable::Direction::Next,
13867                    ),
13868                    SelectionGoal::None,
13869                )
13870            });
13871        })
13872    }
13873
13874    pub fn move_to_end_of_previous_excerpt(
13875        &mut self,
13876        _: &MoveToEndOfPreviousExcerpt,
13877        window: &mut Window,
13878        cx: &mut Context<Self>,
13879    ) {
13880        if matches!(self.mode, EditorMode::SingleLine) {
13881            cx.propagate();
13882            return;
13883        }
13884        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13885        self.change_selections(Default::default(), window, cx, |s| {
13886            s.move_with(|map, selection| {
13887                selection.collapse_to(
13888                    movement::end_of_excerpt(
13889                        map,
13890                        selection.head(),
13891                        workspace::searchable::Direction::Prev,
13892                    ),
13893                    SelectionGoal::None,
13894                )
13895            });
13896        })
13897    }
13898
13899    pub fn select_to_start_of_excerpt(
13900        &mut self,
13901        _: &SelectToStartOfExcerpt,
13902        window: &mut Window,
13903        cx: &mut Context<Self>,
13904    ) {
13905        if matches!(self.mode, EditorMode::SingleLine) {
13906            cx.propagate();
13907            return;
13908        }
13909        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13910        self.change_selections(Default::default(), window, cx, |s| {
13911            s.move_heads_with(|map, head, _| {
13912                (
13913                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13914                    SelectionGoal::None,
13915                )
13916            });
13917        })
13918    }
13919
13920    pub fn select_to_start_of_next_excerpt(
13921        &mut self,
13922        _: &SelectToStartOfNextExcerpt,
13923        window: &mut Window,
13924        cx: &mut Context<Self>,
13925    ) {
13926        if matches!(self.mode, EditorMode::SingleLine) {
13927            cx.propagate();
13928            return;
13929        }
13930        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13931        self.change_selections(Default::default(), window, cx, |s| {
13932            s.move_heads_with(|map, head, _| {
13933                (
13934                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13935                    SelectionGoal::None,
13936                )
13937            });
13938        })
13939    }
13940
13941    pub fn select_to_end_of_excerpt(
13942        &mut self,
13943        _: &SelectToEndOfExcerpt,
13944        window: &mut Window,
13945        cx: &mut Context<Self>,
13946    ) {
13947        if matches!(self.mode, EditorMode::SingleLine) {
13948            cx.propagate();
13949            return;
13950        }
13951        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13952        self.change_selections(Default::default(), window, cx, |s| {
13953            s.move_heads_with(|map, head, _| {
13954                (
13955                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13956                    SelectionGoal::None,
13957                )
13958            });
13959        })
13960    }
13961
13962    pub fn select_to_end_of_previous_excerpt(
13963        &mut self,
13964        _: &SelectToEndOfPreviousExcerpt,
13965        window: &mut Window,
13966        cx: &mut Context<Self>,
13967    ) {
13968        if matches!(self.mode, EditorMode::SingleLine) {
13969            cx.propagate();
13970            return;
13971        }
13972        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13973        self.change_selections(Default::default(), window, cx, |s| {
13974            s.move_heads_with(|map, head, _| {
13975                (
13976                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13977                    SelectionGoal::None,
13978                )
13979            });
13980        })
13981    }
13982
13983    pub fn move_to_beginning(
13984        &mut self,
13985        _: &MoveToBeginning,
13986        window: &mut Window,
13987        cx: &mut Context<Self>,
13988    ) {
13989        if matches!(self.mode, EditorMode::SingleLine) {
13990            cx.propagate();
13991            return;
13992        }
13993        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13994        self.change_selections(Default::default(), window, cx, |s| {
13995            s.select_ranges(vec![0..0]);
13996        });
13997    }
13998
13999    pub fn select_to_beginning(
14000        &mut self,
14001        _: &SelectToBeginning,
14002        window: &mut Window,
14003        cx: &mut Context<Self>,
14004    ) {
14005        let mut selection = self.selections.last::<Point>(cx);
14006        selection.set_head(Point::zero(), SelectionGoal::None);
14007        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14008        self.change_selections(Default::default(), window, cx, |s| {
14009            s.select(vec![selection]);
14010        });
14011    }
14012
14013    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14014        if matches!(self.mode, EditorMode::SingleLine) {
14015            cx.propagate();
14016            return;
14017        }
14018        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14019        let cursor = self.buffer.read(cx).read(cx).len();
14020        self.change_selections(Default::default(), window, cx, |s| {
14021            s.select_ranges(vec![cursor..cursor])
14022        });
14023    }
14024
14025    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14026        self.nav_history = nav_history;
14027    }
14028
14029    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14030        self.nav_history.as_ref()
14031    }
14032
14033    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14034        self.push_to_nav_history(
14035            self.selections.newest_anchor().head(),
14036            None,
14037            false,
14038            true,
14039            cx,
14040        );
14041    }
14042
14043    fn push_to_nav_history(
14044        &mut self,
14045        cursor_anchor: Anchor,
14046        new_position: Option<Point>,
14047        is_deactivate: bool,
14048        always: bool,
14049        cx: &mut Context<Self>,
14050    ) {
14051        if let Some(nav_history) = self.nav_history.as_mut() {
14052            let buffer = self.buffer.read(cx).read(cx);
14053            let cursor_position = cursor_anchor.to_point(&buffer);
14054            let scroll_state = self.scroll_manager.anchor();
14055            let scroll_top_row = scroll_state.top_row(&buffer);
14056            drop(buffer);
14057
14058            if let Some(new_position) = new_position {
14059                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14060                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14061                    return;
14062                }
14063            }
14064
14065            nav_history.push(
14066                Some(NavigationData {
14067                    cursor_anchor,
14068                    cursor_position,
14069                    scroll_anchor: scroll_state,
14070                    scroll_top_row,
14071                }),
14072                cx,
14073            );
14074            cx.emit(EditorEvent::PushedToNavHistory {
14075                anchor: cursor_anchor,
14076                is_deactivate,
14077            })
14078        }
14079    }
14080
14081    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14082        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14083        let buffer = self.buffer.read(cx).snapshot(cx);
14084        let mut selection = self.selections.first::<usize>(cx);
14085        selection.set_head(buffer.len(), SelectionGoal::None);
14086        self.change_selections(Default::default(), window, cx, |s| {
14087            s.select(vec![selection]);
14088        });
14089    }
14090
14091    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14092        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14093        let end = self.buffer.read(cx).read(cx).len();
14094        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14095            s.select_ranges(vec![0..end]);
14096        });
14097    }
14098
14099    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14100        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14101        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14102        let mut selections = self.selections.all::<Point>(cx);
14103        let max_point = display_map.buffer_snapshot().max_point();
14104        for selection in &mut selections {
14105            let rows = selection.spanned_rows(true, &display_map);
14106            selection.start = Point::new(rows.start.0, 0);
14107            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14108            selection.reversed = false;
14109        }
14110        self.change_selections(Default::default(), window, cx, |s| {
14111            s.select(selections);
14112        });
14113    }
14114
14115    pub fn split_selection_into_lines(
14116        &mut self,
14117        action: &SplitSelectionIntoLines,
14118        window: &mut Window,
14119        cx: &mut Context<Self>,
14120    ) {
14121        let selections = self
14122            .selections
14123            .all::<Point>(cx)
14124            .into_iter()
14125            .map(|selection| selection.start..selection.end)
14126            .collect::<Vec<_>>();
14127        self.unfold_ranges(&selections, true, true, cx);
14128
14129        let mut new_selection_ranges = Vec::new();
14130        {
14131            let buffer = self.buffer.read(cx).read(cx);
14132            for selection in selections {
14133                for row in selection.start.row..selection.end.row {
14134                    let line_start = Point::new(row, 0);
14135                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14136
14137                    if action.keep_selections {
14138                        // Keep the selection range for each line
14139                        let selection_start = if row == selection.start.row {
14140                            selection.start
14141                        } else {
14142                            line_start
14143                        };
14144                        new_selection_ranges.push(selection_start..line_end);
14145                    } else {
14146                        // Collapse to cursor at end of line
14147                        new_selection_ranges.push(line_end..line_end);
14148                    }
14149                }
14150
14151                let is_multiline_selection = selection.start.row != selection.end.row;
14152                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14153                // so this action feels more ergonomic when paired with other selection operations
14154                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14155                if !should_skip_last {
14156                    if action.keep_selections {
14157                        if is_multiline_selection {
14158                            let line_start = Point::new(selection.end.row, 0);
14159                            new_selection_ranges.push(line_start..selection.end);
14160                        } else {
14161                            new_selection_ranges.push(selection.start..selection.end);
14162                        }
14163                    } else {
14164                        new_selection_ranges.push(selection.end..selection.end);
14165                    }
14166                }
14167            }
14168        }
14169        self.change_selections(Default::default(), window, cx, |s| {
14170            s.select_ranges(new_selection_ranges);
14171        });
14172    }
14173
14174    pub fn add_selection_above(
14175        &mut self,
14176        _: &AddSelectionAbove,
14177        window: &mut Window,
14178        cx: &mut Context<Self>,
14179    ) {
14180        self.add_selection(true, window, cx);
14181    }
14182
14183    pub fn add_selection_below(
14184        &mut self,
14185        _: &AddSelectionBelow,
14186        window: &mut Window,
14187        cx: &mut Context<Self>,
14188    ) {
14189        self.add_selection(false, window, cx);
14190    }
14191
14192    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14193        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14194
14195        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14196        let all_selections = self.selections.all::<Point>(cx);
14197        let text_layout_details = self.text_layout_details(window);
14198
14199        let (mut columnar_selections, new_selections_to_columnarize) = {
14200            if let Some(state) = self.add_selections_state.as_ref() {
14201                let columnar_selection_ids: HashSet<_> = state
14202                    .groups
14203                    .iter()
14204                    .flat_map(|group| group.stack.iter())
14205                    .copied()
14206                    .collect();
14207
14208                all_selections
14209                    .into_iter()
14210                    .partition(|s| columnar_selection_ids.contains(&s.id))
14211            } else {
14212                (Vec::new(), all_selections)
14213            }
14214        };
14215
14216        let mut state = self
14217            .add_selections_state
14218            .take()
14219            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14220
14221        for selection in new_selections_to_columnarize {
14222            let range = selection.display_range(&display_map).sorted();
14223            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14224            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14225            let positions = start_x.min(end_x)..start_x.max(end_x);
14226            let mut stack = Vec::new();
14227            for row in range.start.row().0..=range.end.row().0 {
14228                if let Some(selection) = self.selections.build_columnar_selection(
14229                    &display_map,
14230                    DisplayRow(row),
14231                    &positions,
14232                    selection.reversed,
14233                    &text_layout_details,
14234                ) {
14235                    stack.push(selection.id);
14236                    columnar_selections.push(selection);
14237                }
14238            }
14239            if !stack.is_empty() {
14240                if above {
14241                    stack.reverse();
14242                }
14243                state.groups.push(AddSelectionsGroup { above, stack });
14244            }
14245        }
14246
14247        let mut final_selections = Vec::new();
14248        let end_row = if above {
14249            DisplayRow(0)
14250        } else {
14251            display_map.max_point().row()
14252        };
14253
14254        let mut last_added_item_per_group = HashMap::default();
14255        for group in state.groups.iter_mut() {
14256            if let Some(last_id) = group.stack.last() {
14257                last_added_item_per_group.insert(*last_id, group);
14258            }
14259        }
14260
14261        for selection in columnar_selections {
14262            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14263                if above == group.above {
14264                    let range = selection.display_range(&display_map).sorted();
14265                    debug_assert_eq!(range.start.row(), range.end.row());
14266                    let mut row = range.start.row();
14267                    let positions =
14268                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14269                            Pixels::from(start)..Pixels::from(end)
14270                        } else {
14271                            let start_x =
14272                                display_map.x_for_display_point(range.start, &text_layout_details);
14273                            let end_x =
14274                                display_map.x_for_display_point(range.end, &text_layout_details);
14275                            start_x.min(end_x)..start_x.max(end_x)
14276                        };
14277
14278                    let mut maybe_new_selection = None;
14279                    while row != end_row {
14280                        if above {
14281                            row.0 -= 1;
14282                        } else {
14283                            row.0 += 1;
14284                        }
14285                        if let Some(new_selection) = self.selections.build_columnar_selection(
14286                            &display_map,
14287                            row,
14288                            &positions,
14289                            selection.reversed,
14290                            &text_layout_details,
14291                        ) {
14292                            maybe_new_selection = Some(new_selection);
14293                            break;
14294                        }
14295                    }
14296
14297                    if let Some(new_selection) = maybe_new_selection {
14298                        group.stack.push(new_selection.id);
14299                        if above {
14300                            final_selections.push(new_selection);
14301                            final_selections.push(selection);
14302                        } else {
14303                            final_selections.push(selection);
14304                            final_selections.push(new_selection);
14305                        }
14306                    } else {
14307                        final_selections.push(selection);
14308                    }
14309                } else {
14310                    group.stack.pop();
14311                }
14312            } else {
14313                final_selections.push(selection);
14314            }
14315        }
14316
14317        self.change_selections(Default::default(), window, cx, |s| {
14318            s.select(final_selections);
14319        });
14320
14321        let final_selection_ids: HashSet<_> = self
14322            .selections
14323            .all::<Point>(cx)
14324            .iter()
14325            .map(|s| s.id)
14326            .collect();
14327        state.groups.retain_mut(|group| {
14328            // selections might get merged above so we remove invalid items from stacks
14329            group.stack.retain(|id| final_selection_ids.contains(id));
14330
14331            // single selection in stack can be treated as initial state
14332            group.stack.len() > 1
14333        });
14334
14335        if !state.groups.is_empty() {
14336            self.add_selections_state = Some(state);
14337        }
14338    }
14339
14340    fn select_match_ranges(
14341        &mut self,
14342        range: Range<usize>,
14343        reversed: bool,
14344        replace_newest: bool,
14345        auto_scroll: Option<Autoscroll>,
14346        window: &mut Window,
14347        cx: &mut Context<Editor>,
14348    ) {
14349        self.unfold_ranges(
14350            std::slice::from_ref(&range),
14351            false,
14352            auto_scroll.is_some(),
14353            cx,
14354        );
14355        let effects = if let Some(scroll) = auto_scroll {
14356            SelectionEffects::scroll(scroll)
14357        } else {
14358            SelectionEffects::no_scroll()
14359        };
14360        self.change_selections(effects, window, cx, |s| {
14361            if replace_newest {
14362                s.delete(s.newest_anchor().id);
14363            }
14364            if reversed {
14365                s.insert_range(range.end..range.start);
14366            } else {
14367                s.insert_range(range);
14368            }
14369        });
14370    }
14371
14372    pub fn select_next_match_internal(
14373        &mut self,
14374        display_map: &DisplaySnapshot,
14375        replace_newest: bool,
14376        autoscroll: Option<Autoscroll>,
14377        window: &mut Window,
14378        cx: &mut Context<Self>,
14379    ) -> Result<()> {
14380        let buffer = display_map.buffer_snapshot();
14381        let mut selections = self.selections.all::<usize>(cx);
14382        if let Some(mut select_next_state) = self.select_next_state.take() {
14383            let query = &select_next_state.query;
14384            if !select_next_state.done {
14385                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14386                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14387                let mut next_selected_range = None;
14388
14389                let bytes_after_last_selection =
14390                    buffer.bytes_in_range(last_selection.end..buffer.len());
14391                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14392                let query_matches = query
14393                    .stream_find_iter(bytes_after_last_selection)
14394                    .map(|result| (last_selection.end, result))
14395                    .chain(
14396                        query
14397                            .stream_find_iter(bytes_before_first_selection)
14398                            .map(|result| (0, result)),
14399                    );
14400
14401                for (start_offset, query_match) in query_matches {
14402                    let query_match = query_match.unwrap(); // can only fail due to I/O
14403                    let offset_range =
14404                        start_offset + query_match.start()..start_offset + query_match.end();
14405
14406                    if !select_next_state.wordwise
14407                        || (!buffer.is_inside_word(offset_range.start, None)
14408                            && !buffer.is_inside_word(offset_range.end, None))
14409                    {
14410                        // TODO: This is n^2, because we might check all the selections
14411                        if !selections
14412                            .iter()
14413                            .any(|selection| selection.range().overlaps(&offset_range))
14414                        {
14415                            next_selected_range = Some(offset_range);
14416                            break;
14417                        }
14418                    }
14419                }
14420
14421                if let Some(next_selected_range) = next_selected_range {
14422                    self.select_match_ranges(
14423                        next_selected_range,
14424                        last_selection.reversed,
14425                        replace_newest,
14426                        autoscroll,
14427                        window,
14428                        cx,
14429                    );
14430                } else {
14431                    select_next_state.done = true;
14432                }
14433            }
14434
14435            self.select_next_state = Some(select_next_state);
14436        } else {
14437            let mut only_carets = true;
14438            let mut same_text_selected = true;
14439            let mut selected_text = None;
14440
14441            let mut selections_iter = selections.iter().peekable();
14442            while let Some(selection) = selections_iter.next() {
14443                if selection.start != selection.end {
14444                    only_carets = false;
14445                }
14446
14447                if same_text_selected {
14448                    if selected_text.is_none() {
14449                        selected_text =
14450                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14451                    }
14452
14453                    if let Some(next_selection) = selections_iter.peek() {
14454                        if next_selection.range().len() == selection.range().len() {
14455                            let next_selected_text = buffer
14456                                .text_for_range(next_selection.range())
14457                                .collect::<String>();
14458                            if Some(next_selected_text) != selected_text {
14459                                same_text_selected = false;
14460                                selected_text = None;
14461                            }
14462                        } else {
14463                            same_text_selected = false;
14464                            selected_text = None;
14465                        }
14466                    }
14467                }
14468            }
14469
14470            if only_carets {
14471                for selection in &mut selections {
14472                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14473                    selection.start = word_range.start;
14474                    selection.end = word_range.end;
14475                    selection.goal = SelectionGoal::None;
14476                    selection.reversed = false;
14477                    self.select_match_ranges(
14478                        selection.start..selection.end,
14479                        selection.reversed,
14480                        replace_newest,
14481                        autoscroll,
14482                        window,
14483                        cx,
14484                    );
14485                }
14486
14487                if selections.len() == 1 {
14488                    let selection = selections
14489                        .last()
14490                        .expect("ensured that there's only one selection");
14491                    let query = buffer
14492                        .text_for_range(selection.start..selection.end)
14493                        .collect::<String>();
14494                    let is_empty = query.is_empty();
14495                    let select_state = SelectNextState {
14496                        query: AhoCorasick::new(&[query])?,
14497                        wordwise: true,
14498                        done: is_empty,
14499                    };
14500                    self.select_next_state = Some(select_state);
14501                } else {
14502                    self.select_next_state = None;
14503                }
14504            } else if let Some(selected_text) = selected_text {
14505                self.select_next_state = Some(SelectNextState {
14506                    query: AhoCorasick::new(&[selected_text])?,
14507                    wordwise: false,
14508                    done: false,
14509                });
14510                self.select_next_match_internal(
14511                    display_map,
14512                    replace_newest,
14513                    autoscroll,
14514                    window,
14515                    cx,
14516                )?;
14517            }
14518        }
14519        Ok(())
14520    }
14521
14522    pub fn select_all_matches(
14523        &mut self,
14524        _action: &SelectAllMatches,
14525        window: &mut Window,
14526        cx: &mut Context<Self>,
14527    ) -> Result<()> {
14528        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14529
14530        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14531
14532        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14533        let Some(select_next_state) = self.select_next_state.as_mut() else {
14534            return Ok(());
14535        };
14536        if select_next_state.done {
14537            return Ok(());
14538        }
14539
14540        let mut new_selections = Vec::new();
14541
14542        let reversed = self.selections.oldest::<usize>(cx).reversed;
14543        let buffer = display_map.buffer_snapshot();
14544        let query_matches = select_next_state
14545            .query
14546            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14547
14548        for query_match in query_matches.into_iter() {
14549            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14550            let offset_range = if reversed {
14551                query_match.end()..query_match.start()
14552            } else {
14553                query_match.start()..query_match.end()
14554            };
14555
14556            if !select_next_state.wordwise
14557                || (!buffer.is_inside_word(offset_range.start, None)
14558                    && !buffer.is_inside_word(offset_range.end, None))
14559            {
14560                new_selections.push(offset_range.start..offset_range.end);
14561            }
14562        }
14563
14564        select_next_state.done = true;
14565
14566        if new_selections.is_empty() {
14567            log::error!("bug: new_selections is empty in select_all_matches");
14568            return Ok(());
14569        }
14570
14571        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14572        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14573            selections.select_ranges(new_selections)
14574        });
14575
14576        Ok(())
14577    }
14578
14579    pub fn select_next(
14580        &mut self,
14581        action: &SelectNext,
14582        window: &mut Window,
14583        cx: &mut Context<Self>,
14584    ) -> Result<()> {
14585        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14586        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14587        self.select_next_match_internal(
14588            &display_map,
14589            action.replace_newest,
14590            Some(Autoscroll::newest()),
14591            window,
14592            cx,
14593        )?;
14594        Ok(())
14595    }
14596
14597    pub fn select_previous(
14598        &mut self,
14599        action: &SelectPrevious,
14600        window: &mut Window,
14601        cx: &mut Context<Self>,
14602    ) -> Result<()> {
14603        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14604        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14605        let buffer = display_map.buffer_snapshot();
14606        let mut selections = self.selections.all::<usize>(cx);
14607        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14608            let query = &select_prev_state.query;
14609            if !select_prev_state.done {
14610                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14611                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14612                let mut next_selected_range = None;
14613                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14614                let bytes_before_last_selection =
14615                    buffer.reversed_bytes_in_range(0..last_selection.start);
14616                let bytes_after_first_selection =
14617                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14618                let query_matches = query
14619                    .stream_find_iter(bytes_before_last_selection)
14620                    .map(|result| (last_selection.start, result))
14621                    .chain(
14622                        query
14623                            .stream_find_iter(bytes_after_first_selection)
14624                            .map(|result| (buffer.len(), result)),
14625                    );
14626                for (end_offset, query_match) in query_matches {
14627                    let query_match = query_match.unwrap(); // can only fail due to I/O
14628                    let offset_range =
14629                        end_offset - query_match.end()..end_offset - query_match.start();
14630
14631                    if !select_prev_state.wordwise
14632                        || (!buffer.is_inside_word(offset_range.start, None)
14633                            && !buffer.is_inside_word(offset_range.end, None))
14634                    {
14635                        next_selected_range = Some(offset_range);
14636                        break;
14637                    }
14638                }
14639
14640                if let Some(next_selected_range) = next_selected_range {
14641                    self.select_match_ranges(
14642                        next_selected_range,
14643                        last_selection.reversed,
14644                        action.replace_newest,
14645                        Some(Autoscroll::newest()),
14646                        window,
14647                        cx,
14648                    );
14649                } else {
14650                    select_prev_state.done = true;
14651                }
14652            }
14653
14654            self.select_prev_state = Some(select_prev_state);
14655        } else {
14656            let mut only_carets = true;
14657            let mut same_text_selected = true;
14658            let mut selected_text = None;
14659
14660            let mut selections_iter = selections.iter().peekable();
14661            while let Some(selection) = selections_iter.next() {
14662                if selection.start != selection.end {
14663                    only_carets = false;
14664                }
14665
14666                if same_text_selected {
14667                    if selected_text.is_none() {
14668                        selected_text =
14669                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14670                    }
14671
14672                    if let Some(next_selection) = selections_iter.peek() {
14673                        if next_selection.range().len() == selection.range().len() {
14674                            let next_selected_text = buffer
14675                                .text_for_range(next_selection.range())
14676                                .collect::<String>();
14677                            if Some(next_selected_text) != selected_text {
14678                                same_text_selected = false;
14679                                selected_text = None;
14680                            }
14681                        } else {
14682                            same_text_selected = false;
14683                            selected_text = None;
14684                        }
14685                    }
14686                }
14687            }
14688
14689            if only_carets {
14690                for selection in &mut selections {
14691                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14692                    selection.start = word_range.start;
14693                    selection.end = word_range.end;
14694                    selection.goal = SelectionGoal::None;
14695                    selection.reversed = false;
14696                    self.select_match_ranges(
14697                        selection.start..selection.end,
14698                        selection.reversed,
14699                        action.replace_newest,
14700                        Some(Autoscroll::newest()),
14701                        window,
14702                        cx,
14703                    );
14704                }
14705                if selections.len() == 1 {
14706                    let selection = selections
14707                        .last()
14708                        .expect("ensured that there's only one selection");
14709                    let query = buffer
14710                        .text_for_range(selection.start..selection.end)
14711                        .collect::<String>();
14712                    let is_empty = query.is_empty();
14713                    let select_state = SelectNextState {
14714                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14715                        wordwise: true,
14716                        done: is_empty,
14717                    };
14718                    self.select_prev_state = Some(select_state);
14719                } else {
14720                    self.select_prev_state = None;
14721                }
14722            } else if let Some(selected_text) = selected_text {
14723                self.select_prev_state = Some(SelectNextState {
14724                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14725                    wordwise: false,
14726                    done: false,
14727                });
14728                self.select_previous(action, window, cx)?;
14729            }
14730        }
14731        Ok(())
14732    }
14733
14734    pub fn find_next_match(
14735        &mut self,
14736        _: &FindNextMatch,
14737        window: &mut Window,
14738        cx: &mut Context<Self>,
14739    ) -> Result<()> {
14740        let selections = self.selections.disjoint_anchors_arc();
14741        match selections.first() {
14742            Some(first) if selections.len() >= 2 => {
14743                self.change_selections(Default::default(), window, cx, |s| {
14744                    s.select_ranges([first.range()]);
14745                });
14746            }
14747            _ => self.select_next(
14748                &SelectNext {
14749                    replace_newest: true,
14750                },
14751                window,
14752                cx,
14753            )?,
14754        }
14755        Ok(())
14756    }
14757
14758    pub fn find_previous_match(
14759        &mut self,
14760        _: &FindPreviousMatch,
14761        window: &mut Window,
14762        cx: &mut Context<Self>,
14763    ) -> Result<()> {
14764        let selections = self.selections.disjoint_anchors_arc();
14765        match selections.last() {
14766            Some(last) if selections.len() >= 2 => {
14767                self.change_selections(Default::default(), window, cx, |s| {
14768                    s.select_ranges([last.range()]);
14769                });
14770            }
14771            _ => self.select_previous(
14772                &SelectPrevious {
14773                    replace_newest: true,
14774                },
14775                window,
14776                cx,
14777            )?,
14778        }
14779        Ok(())
14780    }
14781
14782    pub fn toggle_comments(
14783        &mut self,
14784        action: &ToggleComments,
14785        window: &mut Window,
14786        cx: &mut Context<Self>,
14787    ) {
14788        if self.read_only(cx) {
14789            return;
14790        }
14791        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14792        let text_layout_details = &self.text_layout_details(window);
14793        self.transact(window, cx, |this, window, cx| {
14794            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14795            let mut edits = Vec::new();
14796            let mut selection_edit_ranges = Vec::new();
14797            let mut last_toggled_row = None;
14798            let snapshot = this.buffer.read(cx).read(cx);
14799            let empty_str: Arc<str> = Arc::default();
14800            let mut suffixes_inserted = Vec::new();
14801            let ignore_indent = action.ignore_indent;
14802
14803            fn comment_prefix_range(
14804                snapshot: &MultiBufferSnapshot,
14805                row: MultiBufferRow,
14806                comment_prefix: &str,
14807                comment_prefix_whitespace: &str,
14808                ignore_indent: bool,
14809            ) -> Range<Point> {
14810                let indent_size = if ignore_indent {
14811                    0
14812                } else {
14813                    snapshot.indent_size_for_line(row).len
14814                };
14815
14816                let start = Point::new(row.0, indent_size);
14817
14818                let mut line_bytes = snapshot
14819                    .bytes_in_range(start..snapshot.max_point())
14820                    .flatten()
14821                    .copied();
14822
14823                // If this line currently begins with the line comment prefix, then record
14824                // the range containing the prefix.
14825                if line_bytes
14826                    .by_ref()
14827                    .take(comment_prefix.len())
14828                    .eq(comment_prefix.bytes())
14829                {
14830                    // Include any whitespace that matches the comment prefix.
14831                    let matching_whitespace_len = line_bytes
14832                        .zip(comment_prefix_whitespace.bytes())
14833                        .take_while(|(a, b)| a == b)
14834                        .count() as u32;
14835                    let end = Point::new(
14836                        start.row,
14837                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14838                    );
14839                    start..end
14840                } else {
14841                    start..start
14842                }
14843            }
14844
14845            fn comment_suffix_range(
14846                snapshot: &MultiBufferSnapshot,
14847                row: MultiBufferRow,
14848                comment_suffix: &str,
14849                comment_suffix_has_leading_space: bool,
14850            ) -> Range<Point> {
14851                let end = Point::new(row.0, snapshot.line_len(row));
14852                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14853
14854                let mut line_end_bytes = snapshot
14855                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14856                    .flatten()
14857                    .copied();
14858
14859                let leading_space_len = if suffix_start_column > 0
14860                    && line_end_bytes.next() == Some(b' ')
14861                    && comment_suffix_has_leading_space
14862                {
14863                    1
14864                } else {
14865                    0
14866                };
14867
14868                // If this line currently begins with the line comment prefix, then record
14869                // the range containing the prefix.
14870                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14871                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14872                    start..end
14873                } else {
14874                    end..end
14875                }
14876            }
14877
14878            // TODO: Handle selections that cross excerpts
14879            for selection in &mut selections {
14880                let start_column = snapshot
14881                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14882                    .len;
14883                let language = if let Some(language) =
14884                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14885                {
14886                    language
14887                } else {
14888                    continue;
14889                };
14890
14891                selection_edit_ranges.clear();
14892
14893                // If multiple selections contain a given row, avoid processing that
14894                // row more than once.
14895                let mut start_row = MultiBufferRow(selection.start.row);
14896                if last_toggled_row == Some(start_row) {
14897                    start_row = start_row.next_row();
14898                }
14899                let end_row =
14900                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14901                        MultiBufferRow(selection.end.row - 1)
14902                    } else {
14903                        MultiBufferRow(selection.end.row)
14904                    };
14905                last_toggled_row = Some(end_row);
14906
14907                if start_row > end_row {
14908                    continue;
14909                }
14910
14911                // If the language has line comments, toggle those.
14912                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14913
14914                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14915                if ignore_indent {
14916                    full_comment_prefixes = full_comment_prefixes
14917                        .into_iter()
14918                        .map(|s| Arc::from(s.trim_end()))
14919                        .collect();
14920                }
14921
14922                if !full_comment_prefixes.is_empty() {
14923                    let first_prefix = full_comment_prefixes
14924                        .first()
14925                        .expect("prefixes is non-empty");
14926                    let prefix_trimmed_lengths = full_comment_prefixes
14927                        .iter()
14928                        .map(|p| p.trim_end_matches(' ').len())
14929                        .collect::<SmallVec<[usize; 4]>>();
14930
14931                    let mut all_selection_lines_are_comments = true;
14932
14933                    for row in start_row.0..=end_row.0 {
14934                        let row = MultiBufferRow(row);
14935                        if start_row < end_row && snapshot.is_line_blank(row) {
14936                            continue;
14937                        }
14938
14939                        let prefix_range = full_comment_prefixes
14940                            .iter()
14941                            .zip(prefix_trimmed_lengths.iter().copied())
14942                            .map(|(prefix, trimmed_prefix_len)| {
14943                                comment_prefix_range(
14944                                    snapshot.deref(),
14945                                    row,
14946                                    &prefix[..trimmed_prefix_len],
14947                                    &prefix[trimmed_prefix_len..],
14948                                    ignore_indent,
14949                                )
14950                            })
14951                            .max_by_key(|range| range.end.column - range.start.column)
14952                            .expect("prefixes is non-empty");
14953
14954                        if prefix_range.is_empty() {
14955                            all_selection_lines_are_comments = false;
14956                        }
14957
14958                        selection_edit_ranges.push(prefix_range);
14959                    }
14960
14961                    if all_selection_lines_are_comments {
14962                        edits.extend(
14963                            selection_edit_ranges
14964                                .iter()
14965                                .cloned()
14966                                .map(|range| (range, empty_str.clone())),
14967                        );
14968                    } else {
14969                        let min_column = selection_edit_ranges
14970                            .iter()
14971                            .map(|range| range.start.column)
14972                            .min()
14973                            .unwrap_or(0);
14974                        edits.extend(selection_edit_ranges.iter().map(|range| {
14975                            let position = Point::new(range.start.row, min_column);
14976                            (position..position, first_prefix.clone())
14977                        }));
14978                    }
14979                } else if let Some(BlockCommentConfig {
14980                    start: full_comment_prefix,
14981                    end: comment_suffix,
14982                    ..
14983                }) = language.block_comment()
14984                {
14985                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14986                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14987                    let prefix_range = comment_prefix_range(
14988                        snapshot.deref(),
14989                        start_row,
14990                        comment_prefix,
14991                        comment_prefix_whitespace,
14992                        ignore_indent,
14993                    );
14994                    let suffix_range = comment_suffix_range(
14995                        snapshot.deref(),
14996                        end_row,
14997                        comment_suffix.trim_start_matches(' '),
14998                        comment_suffix.starts_with(' '),
14999                    );
15000
15001                    if prefix_range.is_empty() || suffix_range.is_empty() {
15002                        edits.push((
15003                            prefix_range.start..prefix_range.start,
15004                            full_comment_prefix.clone(),
15005                        ));
15006                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15007                        suffixes_inserted.push((end_row, comment_suffix.len()));
15008                    } else {
15009                        edits.push((prefix_range, empty_str.clone()));
15010                        edits.push((suffix_range, empty_str.clone()));
15011                    }
15012                } else {
15013                    continue;
15014                }
15015            }
15016
15017            drop(snapshot);
15018            this.buffer.update(cx, |buffer, cx| {
15019                buffer.edit(edits, None, cx);
15020            });
15021
15022            // Adjust selections so that they end before any comment suffixes that
15023            // were inserted.
15024            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15025            let mut selections = this.selections.all::<Point>(cx);
15026            let snapshot = this.buffer.read(cx).read(cx);
15027            for selection in &mut selections {
15028                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15029                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15030                        Ordering::Less => {
15031                            suffixes_inserted.next();
15032                            continue;
15033                        }
15034                        Ordering::Greater => break,
15035                        Ordering::Equal => {
15036                            if selection.end.column == snapshot.line_len(row) {
15037                                if selection.is_empty() {
15038                                    selection.start.column -= suffix_len as u32;
15039                                }
15040                                selection.end.column -= suffix_len as u32;
15041                            }
15042                            break;
15043                        }
15044                    }
15045                }
15046            }
15047
15048            drop(snapshot);
15049            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15050
15051            let selections = this.selections.all::<Point>(cx);
15052            let selections_on_single_row = selections.windows(2).all(|selections| {
15053                selections[0].start.row == selections[1].start.row
15054                    && selections[0].end.row == selections[1].end.row
15055                    && selections[0].start.row == selections[0].end.row
15056            });
15057            let selections_selecting = selections
15058                .iter()
15059                .any(|selection| selection.start != selection.end);
15060            let advance_downwards = action.advance_downwards
15061                && selections_on_single_row
15062                && !selections_selecting
15063                && !matches!(this.mode, EditorMode::SingleLine);
15064
15065            if advance_downwards {
15066                let snapshot = this.buffer.read(cx).snapshot(cx);
15067
15068                this.change_selections(Default::default(), window, cx, |s| {
15069                    s.move_cursors_with(|display_snapshot, display_point, _| {
15070                        let mut point = display_point.to_point(display_snapshot);
15071                        point.row += 1;
15072                        point = snapshot.clip_point(point, Bias::Left);
15073                        let display_point = point.to_display_point(display_snapshot);
15074                        let goal = SelectionGoal::HorizontalPosition(
15075                            display_snapshot
15076                                .x_for_display_point(display_point, text_layout_details)
15077                                .into(),
15078                        );
15079                        (display_point, goal)
15080                    })
15081                });
15082            }
15083        });
15084    }
15085
15086    pub fn select_enclosing_symbol(
15087        &mut self,
15088        _: &SelectEnclosingSymbol,
15089        window: &mut Window,
15090        cx: &mut Context<Self>,
15091    ) {
15092        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15093
15094        let buffer = self.buffer.read(cx).snapshot(cx);
15095        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
15096
15097        fn update_selection(
15098            selection: &Selection<usize>,
15099            buffer_snap: &MultiBufferSnapshot,
15100        ) -> Option<Selection<usize>> {
15101            let cursor = selection.head();
15102            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15103            for symbol in symbols.iter().rev() {
15104                let start = symbol.range.start.to_offset(buffer_snap);
15105                let end = symbol.range.end.to_offset(buffer_snap);
15106                let new_range = start..end;
15107                if start < selection.start || end > selection.end {
15108                    return Some(Selection {
15109                        id: selection.id,
15110                        start: new_range.start,
15111                        end: new_range.end,
15112                        goal: SelectionGoal::None,
15113                        reversed: selection.reversed,
15114                    });
15115                }
15116            }
15117            None
15118        }
15119
15120        let mut selected_larger_symbol = false;
15121        let new_selections = old_selections
15122            .iter()
15123            .map(|selection| match update_selection(selection, &buffer) {
15124                Some(new_selection) => {
15125                    if new_selection.range() != selection.range() {
15126                        selected_larger_symbol = true;
15127                    }
15128                    new_selection
15129                }
15130                None => selection.clone(),
15131            })
15132            .collect::<Vec<_>>();
15133
15134        if selected_larger_symbol {
15135            self.change_selections(Default::default(), window, cx, |s| {
15136                s.select(new_selections);
15137            });
15138        }
15139    }
15140
15141    pub fn select_larger_syntax_node(
15142        &mut self,
15143        _: &SelectLargerSyntaxNode,
15144        window: &mut Window,
15145        cx: &mut Context<Self>,
15146    ) {
15147        let Some(visible_row_count) = self.visible_row_count() else {
15148            return;
15149        };
15150        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15151        if old_selections.is_empty() {
15152            return;
15153        }
15154
15155        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15156
15157        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15158        let buffer = self.buffer.read(cx).snapshot(cx);
15159
15160        let mut selected_larger_node = false;
15161        let mut new_selections = old_selections
15162            .iter()
15163            .map(|selection| {
15164                let old_range = selection.start..selection.end;
15165
15166                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15167                    // manually select word at selection
15168                    if ["string_content", "inline"].contains(&node.kind()) {
15169                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15170                        // ignore if word is already selected
15171                        if !word_range.is_empty() && old_range != word_range {
15172                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15173                            // only select word if start and end point belongs to same word
15174                            if word_range == last_word_range {
15175                                selected_larger_node = true;
15176                                return Selection {
15177                                    id: selection.id,
15178                                    start: word_range.start,
15179                                    end: word_range.end,
15180                                    goal: SelectionGoal::None,
15181                                    reversed: selection.reversed,
15182                                };
15183                            }
15184                        }
15185                    }
15186                }
15187
15188                let mut new_range = old_range.clone();
15189                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15190                    new_range = range;
15191                    if !node.is_named() {
15192                        continue;
15193                    }
15194                    if !display_map.intersects_fold(new_range.start)
15195                        && !display_map.intersects_fold(new_range.end)
15196                    {
15197                        break;
15198                    }
15199                }
15200
15201                selected_larger_node |= new_range != old_range;
15202                Selection {
15203                    id: selection.id,
15204                    start: new_range.start,
15205                    end: new_range.end,
15206                    goal: SelectionGoal::None,
15207                    reversed: selection.reversed,
15208                }
15209            })
15210            .collect::<Vec<_>>();
15211
15212        if !selected_larger_node {
15213            return; // don't put this call in the history
15214        }
15215
15216        // scroll based on transformation done to the last selection created by the user
15217        let (last_old, last_new) = old_selections
15218            .last()
15219            .zip(new_selections.last().cloned())
15220            .expect("old_selections isn't empty");
15221
15222        // revert selection
15223        let is_selection_reversed = {
15224            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15225            new_selections.last_mut().expect("checked above").reversed =
15226                should_newest_selection_be_reversed;
15227            should_newest_selection_be_reversed
15228        };
15229
15230        if selected_larger_node {
15231            self.select_syntax_node_history.disable_clearing = true;
15232            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15233                s.select(new_selections.clone());
15234            });
15235            self.select_syntax_node_history.disable_clearing = false;
15236        }
15237
15238        let start_row = last_new.start.to_display_point(&display_map).row().0;
15239        let end_row = last_new.end.to_display_point(&display_map).row().0;
15240        let selection_height = end_row - start_row + 1;
15241        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15242
15243        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15244        let scroll_behavior = if fits_on_the_screen {
15245            self.request_autoscroll(Autoscroll::fit(), cx);
15246            SelectSyntaxNodeScrollBehavior::FitSelection
15247        } else if is_selection_reversed {
15248            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15249            SelectSyntaxNodeScrollBehavior::CursorTop
15250        } else {
15251            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15252            SelectSyntaxNodeScrollBehavior::CursorBottom
15253        };
15254
15255        self.select_syntax_node_history.push((
15256            old_selections,
15257            scroll_behavior,
15258            is_selection_reversed,
15259        ));
15260    }
15261
15262    pub fn select_smaller_syntax_node(
15263        &mut self,
15264        _: &SelectSmallerSyntaxNode,
15265        window: &mut Window,
15266        cx: &mut Context<Self>,
15267    ) {
15268        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15269
15270        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15271            self.select_syntax_node_history.pop()
15272        {
15273            if let Some(selection) = selections.last_mut() {
15274                selection.reversed = is_selection_reversed;
15275            }
15276
15277            self.select_syntax_node_history.disable_clearing = true;
15278            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15279                s.select(selections.to_vec());
15280            });
15281            self.select_syntax_node_history.disable_clearing = false;
15282
15283            match scroll_behavior {
15284                SelectSyntaxNodeScrollBehavior::CursorTop => {
15285                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15286                }
15287                SelectSyntaxNodeScrollBehavior::FitSelection => {
15288                    self.request_autoscroll(Autoscroll::fit(), cx);
15289                }
15290                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15291                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15292                }
15293            }
15294        }
15295    }
15296
15297    pub fn unwrap_syntax_node(
15298        &mut self,
15299        _: &UnwrapSyntaxNode,
15300        window: &mut Window,
15301        cx: &mut Context<Self>,
15302    ) {
15303        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15304
15305        let buffer = self.buffer.read(cx).snapshot(cx);
15306        let selections = self
15307            .selections
15308            .all::<usize>(cx)
15309            .into_iter()
15310            // subtracting the offset requires sorting
15311            .sorted_by_key(|i| i.start);
15312
15313        let full_edits = selections
15314            .into_iter()
15315            .filter_map(|selection| {
15316                let child = if selection.is_empty()
15317                    && let Some((_, ancestor_range)) =
15318                        buffer.syntax_ancestor(selection.start..selection.end)
15319                {
15320                    ancestor_range
15321                } else {
15322                    selection.range()
15323                };
15324
15325                let mut parent = child.clone();
15326                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15327                    parent = ancestor_range;
15328                    if parent.start < child.start || parent.end > child.end {
15329                        break;
15330                    }
15331                }
15332
15333                if parent == child {
15334                    return None;
15335                }
15336                let text = buffer.text_for_range(child).collect::<String>();
15337                Some((selection.id, parent, text))
15338            })
15339            .collect::<Vec<_>>();
15340        if full_edits.is_empty() {
15341            return;
15342        }
15343
15344        self.transact(window, cx, |this, window, cx| {
15345            this.buffer.update(cx, |buffer, cx| {
15346                buffer.edit(
15347                    full_edits
15348                        .iter()
15349                        .map(|(_, p, t)| (p.clone(), t.clone()))
15350                        .collect::<Vec<_>>(),
15351                    None,
15352                    cx,
15353                );
15354            });
15355            this.change_selections(Default::default(), window, cx, |s| {
15356                let mut offset = 0;
15357                let mut selections = vec![];
15358                for (id, parent, text) in full_edits {
15359                    let start = parent.start - offset;
15360                    offset += parent.len() - text.len();
15361                    selections.push(Selection {
15362                        id,
15363                        start,
15364                        end: start + text.len(),
15365                        reversed: false,
15366                        goal: Default::default(),
15367                    });
15368                }
15369                s.select(selections);
15370            });
15371        });
15372    }
15373
15374    pub fn select_next_syntax_node(
15375        &mut self,
15376        _: &SelectNextSyntaxNode,
15377        window: &mut Window,
15378        cx: &mut Context<Self>,
15379    ) {
15380        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15381        if old_selections.is_empty() {
15382            return;
15383        }
15384
15385        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15386
15387        let buffer = self.buffer.read(cx).snapshot(cx);
15388        let mut selected_sibling = false;
15389
15390        let new_selections = old_selections
15391            .iter()
15392            .map(|selection| {
15393                let old_range = selection.start..selection.end;
15394
15395                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15396                    let new_range = node.byte_range();
15397                    selected_sibling = true;
15398                    Selection {
15399                        id: selection.id,
15400                        start: new_range.start,
15401                        end: new_range.end,
15402                        goal: SelectionGoal::None,
15403                        reversed: selection.reversed,
15404                    }
15405                } else {
15406                    selection.clone()
15407                }
15408            })
15409            .collect::<Vec<_>>();
15410
15411        if selected_sibling {
15412            self.change_selections(
15413                SelectionEffects::scroll(Autoscroll::fit()),
15414                window,
15415                cx,
15416                |s| {
15417                    s.select(new_selections);
15418                },
15419            );
15420        }
15421    }
15422
15423    pub fn select_prev_syntax_node(
15424        &mut self,
15425        _: &SelectPreviousSyntaxNode,
15426        window: &mut Window,
15427        cx: &mut Context<Self>,
15428    ) {
15429        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15430        if old_selections.is_empty() {
15431            return;
15432        }
15433
15434        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15435
15436        let buffer = self.buffer.read(cx).snapshot(cx);
15437        let mut selected_sibling = false;
15438
15439        let new_selections = old_selections
15440            .iter()
15441            .map(|selection| {
15442                let old_range = selection.start..selection.end;
15443
15444                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15445                    let new_range = node.byte_range();
15446                    selected_sibling = true;
15447                    Selection {
15448                        id: selection.id,
15449                        start: new_range.start,
15450                        end: new_range.end,
15451                        goal: SelectionGoal::None,
15452                        reversed: selection.reversed,
15453                    }
15454                } else {
15455                    selection.clone()
15456                }
15457            })
15458            .collect::<Vec<_>>();
15459
15460        if selected_sibling {
15461            self.change_selections(
15462                SelectionEffects::scroll(Autoscroll::fit()),
15463                window,
15464                cx,
15465                |s| {
15466                    s.select(new_selections);
15467                },
15468            );
15469        }
15470    }
15471
15472    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15473        if !EditorSettings::get_global(cx).gutter.runnables {
15474            self.clear_tasks();
15475            return Task::ready(());
15476        }
15477        let project = self.project().map(Entity::downgrade);
15478        let task_sources = self.lsp_task_sources(cx);
15479        let multi_buffer = self.buffer.downgrade();
15480        cx.spawn_in(window, async move |editor, cx| {
15481            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15482            let Some(project) = project.and_then(|p| p.upgrade()) else {
15483                return;
15484            };
15485            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15486                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15487            }) else {
15488                return;
15489            };
15490
15491            let hide_runnables = project
15492                .update(cx, |project, _| project.is_via_collab())
15493                .unwrap_or(true);
15494            if hide_runnables {
15495                return;
15496            }
15497            let new_rows =
15498                cx.background_spawn({
15499                    let snapshot = display_snapshot.clone();
15500                    async move {
15501                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15502                    }
15503                })
15504                    .await;
15505            let Ok(lsp_tasks) =
15506                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15507            else {
15508                return;
15509            };
15510            let lsp_tasks = lsp_tasks.await;
15511
15512            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15513                lsp_tasks
15514                    .into_iter()
15515                    .flat_map(|(kind, tasks)| {
15516                        tasks.into_iter().filter_map(move |(location, task)| {
15517                            Some((kind.clone(), location?, task))
15518                        })
15519                    })
15520                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15521                        let buffer = location.target.buffer;
15522                        let buffer_snapshot = buffer.read(cx).snapshot();
15523                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15524                            |(excerpt_id, snapshot, _)| {
15525                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15526                                    display_snapshot
15527                                        .buffer_snapshot()
15528                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15529                                } else {
15530                                    None
15531                                }
15532                            },
15533                        );
15534                        if let Some(offset) = offset {
15535                            let task_buffer_range =
15536                                location.target.range.to_point(&buffer_snapshot);
15537                            let context_buffer_range =
15538                                task_buffer_range.to_offset(&buffer_snapshot);
15539                            let context_range = BufferOffset(context_buffer_range.start)
15540                                ..BufferOffset(context_buffer_range.end);
15541
15542                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15543                                .or_insert_with(|| RunnableTasks {
15544                                    templates: Vec::new(),
15545                                    offset,
15546                                    column: task_buffer_range.start.column,
15547                                    extra_variables: HashMap::default(),
15548                                    context_range,
15549                                })
15550                                .templates
15551                                .push((kind, task.original_task().clone()));
15552                        }
15553
15554                        acc
15555                    })
15556            }) else {
15557                return;
15558            };
15559
15560            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15561                buffer.language_settings(cx).tasks.prefer_lsp
15562            }) else {
15563                return;
15564            };
15565
15566            let rows = Self::runnable_rows(
15567                project,
15568                display_snapshot,
15569                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15570                new_rows,
15571                cx.clone(),
15572            )
15573            .await;
15574            editor
15575                .update(cx, |editor, _| {
15576                    editor.clear_tasks();
15577                    for (key, mut value) in rows {
15578                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15579                            value.templates.extend(lsp_tasks.templates);
15580                        }
15581
15582                        editor.insert_tasks(key, value);
15583                    }
15584                    for (key, value) in lsp_tasks_by_rows {
15585                        editor.insert_tasks(key, value);
15586                    }
15587                })
15588                .ok();
15589        })
15590    }
15591    fn fetch_runnable_ranges(
15592        snapshot: &DisplaySnapshot,
15593        range: Range<Anchor>,
15594    ) -> Vec<language::RunnableRange> {
15595        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15596    }
15597
15598    fn runnable_rows(
15599        project: Entity<Project>,
15600        snapshot: DisplaySnapshot,
15601        prefer_lsp: bool,
15602        runnable_ranges: Vec<RunnableRange>,
15603        cx: AsyncWindowContext,
15604    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15605        cx.spawn(async move |cx| {
15606            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15607            for mut runnable in runnable_ranges {
15608                let Some(tasks) = cx
15609                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15610                    .ok()
15611                else {
15612                    continue;
15613                };
15614                let mut tasks = tasks.await;
15615
15616                if prefer_lsp {
15617                    tasks.retain(|(task_kind, _)| {
15618                        !matches!(task_kind, TaskSourceKind::Language { .. })
15619                    });
15620                }
15621                if tasks.is_empty() {
15622                    continue;
15623                }
15624
15625                let point = runnable
15626                    .run_range
15627                    .start
15628                    .to_point(&snapshot.buffer_snapshot());
15629                let Some(row) = snapshot
15630                    .buffer_snapshot()
15631                    .buffer_line_for_row(MultiBufferRow(point.row))
15632                    .map(|(_, range)| range.start.row)
15633                else {
15634                    continue;
15635                };
15636
15637                let context_range =
15638                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15639                runnable_rows.push((
15640                    (runnable.buffer_id, row),
15641                    RunnableTasks {
15642                        templates: tasks,
15643                        offset: snapshot
15644                            .buffer_snapshot()
15645                            .anchor_before(runnable.run_range.start),
15646                        context_range,
15647                        column: point.column,
15648                        extra_variables: runnable.extra_captures,
15649                    },
15650                ));
15651            }
15652            runnable_rows
15653        })
15654    }
15655
15656    fn templates_with_tags(
15657        project: &Entity<Project>,
15658        runnable: &mut Runnable,
15659        cx: &mut App,
15660    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15661        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15662            let (worktree_id, file) = project
15663                .buffer_for_id(runnable.buffer, cx)
15664                .and_then(|buffer| buffer.read(cx).file())
15665                .map(|file| (file.worktree_id(cx), file.clone()))
15666                .unzip();
15667
15668            (
15669                project.task_store().read(cx).task_inventory().cloned(),
15670                worktree_id,
15671                file,
15672            )
15673        });
15674
15675        let tags = mem::take(&mut runnable.tags);
15676        let language = runnable.language.clone();
15677        cx.spawn(async move |cx| {
15678            let mut templates_with_tags = Vec::new();
15679            if let Some(inventory) = inventory {
15680                for RunnableTag(tag) in tags {
15681                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15682                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15683                    }) else {
15684                        return templates_with_tags;
15685                    };
15686                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15687                        move |(_, template)| {
15688                            template.tags.iter().any(|source_tag| source_tag == &tag)
15689                        },
15690                    ));
15691                }
15692            }
15693            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15694
15695            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15696                // Strongest source wins; if we have worktree tag binding, prefer that to
15697                // global and language bindings;
15698                // if we have a global binding, prefer that to language binding.
15699                let first_mismatch = templates_with_tags
15700                    .iter()
15701                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15702                if let Some(index) = first_mismatch {
15703                    templates_with_tags.truncate(index);
15704                }
15705            }
15706
15707            templates_with_tags
15708        })
15709    }
15710
15711    pub fn move_to_enclosing_bracket(
15712        &mut self,
15713        _: &MoveToEnclosingBracket,
15714        window: &mut Window,
15715        cx: &mut Context<Self>,
15716    ) {
15717        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15718        self.change_selections(Default::default(), window, cx, |s| {
15719            s.move_offsets_with(|snapshot, selection| {
15720                let Some(enclosing_bracket_ranges) =
15721                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15722                else {
15723                    return;
15724                };
15725
15726                let mut best_length = usize::MAX;
15727                let mut best_inside = false;
15728                let mut best_in_bracket_range = false;
15729                let mut best_destination = None;
15730                for (open, close) in enclosing_bracket_ranges {
15731                    let close = close.to_inclusive();
15732                    let length = close.end() - open.start;
15733                    let inside = selection.start >= open.end && selection.end <= *close.start();
15734                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15735                        || close.contains(&selection.head());
15736
15737                    // If best is next to a bracket and current isn't, skip
15738                    if !in_bracket_range && best_in_bracket_range {
15739                        continue;
15740                    }
15741
15742                    // Prefer smaller lengths unless best is inside and current isn't
15743                    if length > best_length && (best_inside || !inside) {
15744                        continue;
15745                    }
15746
15747                    best_length = length;
15748                    best_inside = inside;
15749                    best_in_bracket_range = in_bracket_range;
15750                    best_destination = Some(
15751                        if close.contains(&selection.start) && close.contains(&selection.end) {
15752                            if inside { open.end } else { open.start }
15753                        } else if inside {
15754                            *close.start()
15755                        } else {
15756                            *close.end()
15757                        },
15758                    );
15759                }
15760
15761                if let Some(destination) = best_destination {
15762                    selection.collapse_to(destination, SelectionGoal::None);
15763                }
15764            })
15765        });
15766    }
15767
15768    pub fn undo_selection(
15769        &mut self,
15770        _: &UndoSelection,
15771        window: &mut Window,
15772        cx: &mut Context<Self>,
15773    ) {
15774        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15775        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15776            self.selection_history.mode = SelectionHistoryMode::Undoing;
15777            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15778                this.end_selection(window, cx);
15779                this.change_selections(
15780                    SelectionEffects::scroll(Autoscroll::newest()),
15781                    window,
15782                    cx,
15783                    |s| s.select_anchors(entry.selections.to_vec()),
15784                );
15785            });
15786            self.selection_history.mode = SelectionHistoryMode::Normal;
15787
15788            self.select_next_state = entry.select_next_state;
15789            self.select_prev_state = entry.select_prev_state;
15790            self.add_selections_state = entry.add_selections_state;
15791        }
15792    }
15793
15794    pub fn redo_selection(
15795        &mut self,
15796        _: &RedoSelection,
15797        window: &mut Window,
15798        cx: &mut Context<Self>,
15799    ) {
15800        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15801        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15802            self.selection_history.mode = SelectionHistoryMode::Redoing;
15803            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15804                this.end_selection(window, cx);
15805                this.change_selections(
15806                    SelectionEffects::scroll(Autoscroll::newest()),
15807                    window,
15808                    cx,
15809                    |s| s.select_anchors(entry.selections.to_vec()),
15810                );
15811            });
15812            self.selection_history.mode = SelectionHistoryMode::Normal;
15813
15814            self.select_next_state = entry.select_next_state;
15815            self.select_prev_state = entry.select_prev_state;
15816            self.add_selections_state = entry.add_selections_state;
15817        }
15818    }
15819
15820    pub fn expand_excerpts(
15821        &mut self,
15822        action: &ExpandExcerpts,
15823        _: &mut Window,
15824        cx: &mut Context<Self>,
15825    ) {
15826        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15827    }
15828
15829    pub fn expand_excerpts_down(
15830        &mut self,
15831        action: &ExpandExcerptsDown,
15832        _: &mut Window,
15833        cx: &mut Context<Self>,
15834    ) {
15835        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15836    }
15837
15838    pub fn expand_excerpts_up(
15839        &mut self,
15840        action: &ExpandExcerptsUp,
15841        _: &mut Window,
15842        cx: &mut Context<Self>,
15843    ) {
15844        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15845    }
15846
15847    pub fn expand_excerpts_for_direction(
15848        &mut self,
15849        lines: u32,
15850        direction: ExpandExcerptDirection,
15851
15852        cx: &mut Context<Self>,
15853    ) {
15854        let selections = self.selections.disjoint_anchors_arc();
15855
15856        let lines = if lines == 0 {
15857            EditorSettings::get_global(cx).expand_excerpt_lines
15858        } else {
15859            lines
15860        };
15861
15862        self.buffer.update(cx, |buffer, cx| {
15863            let snapshot = buffer.snapshot(cx);
15864            let mut excerpt_ids = selections
15865                .iter()
15866                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15867                .collect::<Vec<_>>();
15868            excerpt_ids.sort();
15869            excerpt_ids.dedup();
15870            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15871        })
15872    }
15873
15874    pub fn expand_excerpt(
15875        &mut self,
15876        excerpt: ExcerptId,
15877        direction: ExpandExcerptDirection,
15878        window: &mut Window,
15879        cx: &mut Context<Self>,
15880    ) {
15881        let current_scroll_position = self.scroll_position(cx);
15882        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15883        let mut should_scroll_up = false;
15884
15885        if direction == ExpandExcerptDirection::Down {
15886            let multi_buffer = self.buffer.read(cx);
15887            let snapshot = multi_buffer.snapshot(cx);
15888            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15889                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15890                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15891            {
15892                let buffer_snapshot = buffer.read(cx).snapshot();
15893                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15894                let last_row = buffer_snapshot.max_point().row;
15895                let lines_below = last_row.saturating_sub(excerpt_end_row);
15896                should_scroll_up = lines_below >= lines_to_expand;
15897            }
15898        }
15899
15900        self.buffer.update(cx, |buffer, cx| {
15901            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15902        });
15903
15904        if should_scroll_up {
15905            let new_scroll_position =
15906                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
15907            self.set_scroll_position(new_scroll_position, window, cx);
15908        }
15909    }
15910
15911    pub fn go_to_singleton_buffer_point(
15912        &mut self,
15913        point: Point,
15914        window: &mut Window,
15915        cx: &mut Context<Self>,
15916    ) {
15917        self.go_to_singleton_buffer_range(point..point, window, cx);
15918    }
15919
15920    pub fn go_to_singleton_buffer_range(
15921        &mut self,
15922        range: Range<Point>,
15923        window: &mut Window,
15924        cx: &mut Context<Self>,
15925    ) {
15926        let multibuffer = self.buffer().read(cx);
15927        let Some(buffer) = multibuffer.as_singleton() else {
15928            return;
15929        };
15930        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15931            return;
15932        };
15933        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15934            return;
15935        };
15936        self.change_selections(
15937            SelectionEffects::default().nav_history(true),
15938            window,
15939            cx,
15940            |s| s.select_anchor_ranges([start..end]),
15941        );
15942    }
15943
15944    pub fn go_to_diagnostic(
15945        &mut self,
15946        action: &GoToDiagnostic,
15947        window: &mut Window,
15948        cx: &mut Context<Self>,
15949    ) {
15950        if !self.diagnostics_enabled() {
15951            return;
15952        }
15953        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15954        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15955    }
15956
15957    pub fn go_to_prev_diagnostic(
15958        &mut self,
15959        action: &GoToPreviousDiagnostic,
15960        window: &mut Window,
15961        cx: &mut Context<Self>,
15962    ) {
15963        if !self.diagnostics_enabled() {
15964            return;
15965        }
15966        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15967        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15968    }
15969
15970    pub fn go_to_diagnostic_impl(
15971        &mut self,
15972        direction: Direction,
15973        severity: GoToDiagnosticSeverityFilter,
15974        window: &mut Window,
15975        cx: &mut Context<Self>,
15976    ) {
15977        let buffer = self.buffer.read(cx).snapshot(cx);
15978        let selection = self.selections.newest::<usize>(cx);
15979
15980        let mut active_group_id = None;
15981        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15982            && active_group.active_range.start.to_offset(&buffer) == selection.start
15983        {
15984            active_group_id = Some(active_group.group_id);
15985        }
15986
15987        fn filtered<'a>(
15988            snapshot: EditorSnapshot,
15989            severity: GoToDiagnosticSeverityFilter,
15990            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
15991        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
15992            diagnostics
15993                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15994                .filter(|entry| entry.range.start != entry.range.end)
15995                .filter(|entry| !entry.diagnostic.is_unnecessary)
15996                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15997        }
15998
15999        let snapshot = self.snapshot(window, cx);
16000        let before = filtered(
16001            snapshot.clone(),
16002            severity,
16003            buffer
16004                .diagnostics_in_range(0..selection.start)
16005                .filter(|entry| entry.range.start <= selection.start),
16006        );
16007        let after = filtered(
16008            snapshot,
16009            severity,
16010            buffer
16011                .diagnostics_in_range(selection.start..buffer.len())
16012                .filter(|entry| entry.range.start >= selection.start),
16013        );
16014
16015        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16016        if direction == Direction::Prev {
16017            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16018            {
16019                for diagnostic in prev_diagnostics.into_iter().rev() {
16020                    if diagnostic.range.start != selection.start
16021                        || active_group_id
16022                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16023                    {
16024                        found = Some(diagnostic);
16025                        break 'outer;
16026                    }
16027                }
16028            }
16029        } else {
16030            for diagnostic in after.chain(before) {
16031                if diagnostic.range.start != selection.start
16032                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16033                {
16034                    found = Some(diagnostic);
16035                    break;
16036                }
16037            }
16038        }
16039        let Some(next_diagnostic) = found else {
16040            return;
16041        };
16042
16043        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16044        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16045            return;
16046        };
16047        self.change_selections(Default::default(), window, cx, |s| {
16048            s.select_ranges(vec![
16049                next_diagnostic.range.start..next_diagnostic.range.start,
16050            ])
16051        });
16052        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16053        self.refresh_edit_prediction(false, true, window, cx);
16054    }
16055
16056    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16057        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16058        let snapshot = self.snapshot(window, cx);
16059        let selection = self.selections.newest::<Point>(cx);
16060        self.go_to_hunk_before_or_after_position(
16061            &snapshot,
16062            selection.head(),
16063            Direction::Next,
16064            window,
16065            cx,
16066        );
16067    }
16068
16069    pub fn go_to_hunk_before_or_after_position(
16070        &mut self,
16071        snapshot: &EditorSnapshot,
16072        position: Point,
16073        direction: Direction,
16074        window: &mut Window,
16075        cx: &mut Context<Editor>,
16076    ) {
16077        let row = if direction == Direction::Next {
16078            self.hunk_after_position(snapshot, position)
16079                .map(|hunk| hunk.row_range.start)
16080        } else {
16081            self.hunk_before_position(snapshot, position)
16082        };
16083
16084        if let Some(row) = row {
16085            let destination = Point::new(row.0, 0);
16086            let autoscroll = Autoscroll::center();
16087
16088            self.unfold_ranges(&[destination..destination], false, false, cx);
16089            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16090                s.select_ranges([destination..destination]);
16091            });
16092        }
16093    }
16094
16095    fn hunk_after_position(
16096        &mut self,
16097        snapshot: &EditorSnapshot,
16098        position: Point,
16099    ) -> Option<MultiBufferDiffHunk> {
16100        snapshot
16101            .buffer_snapshot()
16102            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16103            .find(|hunk| hunk.row_range.start.0 > position.row)
16104            .or_else(|| {
16105                snapshot
16106                    .buffer_snapshot()
16107                    .diff_hunks_in_range(Point::zero()..position)
16108                    .find(|hunk| hunk.row_range.end.0 < position.row)
16109            })
16110    }
16111
16112    fn go_to_prev_hunk(
16113        &mut self,
16114        _: &GoToPreviousHunk,
16115        window: &mut Window,
16116        cx: &mut Context<Self>,
16117    ) {
16118        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16119        let snapshot = self.snapshot(window, cx);
16120        let selection = self.selections.newest::<Point>(cx);
16121        self.go_to_hunk_before_or_after_position(
16122            &snapshot,
16123            selection.head(),
16124            Direction::Prev,
16125            window,
16126            cx,
16127        );
16128    }
16129
16130    fn hunk_before_position(
16131        &mut self,
16132        snapshot: &EditorSnapshot,
16133        position: Point,
16134    ) -> Option<MultiBufferRow> {
16135        snapshot
16136            .buffer_snapshot()
16137            .diff_hunk_before(position)
16138            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16139    }
16140
16141    fn go_to_next_change(
16142        &mut self,
16143        _: &GoToNextChange,
16144        window: &mut Window,
16145        cx: &mut Context<Self>,
16146    ) {
16147        if let Some(selections) = self
16148            .change_list
16149            .next_change(1, Direction::Next)
16150            .map(|s| s.to_vec())
16151        {
16152            self.change_selections(Default::default(), window, cx, |s| {
16153                let map = s.display_map();
16154                s.select_display_ranges(selections.iter().map(|a| {
16155                    let point = a.to_display_point(&map);
16156                    point..point
16157                }))
16158            })
16159        }
16160    }
16161
16162    fn go_to_previous_change(
16163        &mut self,
16164        _: &GoToPreviousChange,
16165        window: &mut Window,
16166        cx: &mut Context<Self>,
16167    ) {
16168        if let Some(selections) = self
16169            .change_list
16170            .next_change(1, Direction::Prev)
16171            .map(|s| s.to_vec())
16172        {
16173            self.change_selections(Default::default(), window, cx, |s| {
16174                let map = s.display_map();
16175                s.select_display_ranges(selections.iter().map(|a| {
16176                    let point = a.to_display_point(&map);
16177                    point..point
16178                }))
16179            })
16180        }
16181    }
16182
16183    pub fn go_to_next_document_highlight(
16184        &mut self,
16185        _: &GoToNextDocumentHighlight,
16186        window: &mut Window,
16187        cx: &mut Context<Self>,
16188    ) {
16189        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16190    }
16191
16192    pub fn go_to_prev_document_highlight(
16193        &mut self,
16194        _: &GoToPreviousDocumentHighlight,
16195        window: &mut Window,
16196        cx: &mut Context<Self>,
16197    ) {
16198        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16199    }
16200
16201    pub fn go_to_document_highlight_before_or_after_position(
16202        &mut self,
16203        direction: Direction,
16204        window: &mut Window,
16205        cx: &mut Context<Editor>,
16206    ) {
16207        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16208        let snapshot = self.snapshot(window, cx);
16209        let buffer = &snapshot.buffer_snapshot();
16210        let position = self.selections.newest::<Point>(cx).head();
16211        let anchor_position = buffer.anchor_after(position);
16212
16213        // Get all document highlights (both read and write)
16214        let mut all_highlights = Vec::new();
16215
16216        if let Some((_, read_highlights)) = self
16217            .background_highlights
16218            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16219        {
16220            all_highlights.extend(read_highlights.iter());
16221        }
16222
16223        if let Some((_, write_highlights)) = self
16224            .background_highlights
16225            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16226        {
16227            all_highlights.extend(write_highlights.iter());
16228        }
16229
16230        if all_highlights.is_empty() {
16231            return;
16232        }
16233
16234        // Sort highlights by position
16235        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16236
16237        let target_highlight = match direction {
16238            Direction::Next => {
16239                // Find the first highlight after the current position
16240                all_highlights
16241                    .iter()
16242                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16243            }
16244            Direction::Prev => {
16245                // Find the last highlight before the current position
16246                all_highlights
16247                    .iter()
16248                    .rev()
16249                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16250            }
16251        };
16252
16253        if let Some(highlight) = target_highlight {
16254            let destination = highlight.start.to_point(buffer);
16255            let autoscroll = Autoscroll::center();
16256
16257            self.unfold_ranges(&[destination..destination], false, false, cx);
16258            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16259                s.select_ranges([destination..destination]);
16260            });
16261        }
16262    }
16263
16264    fn go_to_line<T: 'static>(
16265        &mut self,
16266        position: Anchor,
16267        highlight_color: Option<Hsla>,
16268        window: &mut Window,
16269        cx: &mut Context<Self>,
16270    ) {
16271        let snapshot = self.snapshot(window, cx).display_snapshot;
16272        let position = position.to_point(&snapshot.buffer_snapshot());
16273        let start = snapshot
16274            .buffer_snapshot()
16275            .clip_point(Point::new(position.row, 0), Bias::Left);
16276        let end = start + Point::new(1, 0);
16277        let start = snapshot.buffer_snapshot().anchor_before(start);
16278        let end = snapshot.buffer_snapshot().anchor_before(end);
16279
16280        self.highlight_rows::<T>(
16281            start..end,
16282            highlight_color
16283                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16284            Default::default(),
16285            cx,
16286        );
16287
16288        if self.buffer.read(cx).is_singleton() {
16289            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16290        }
16291    }
16292
16293    pub fn go_to_definition(
16294        &mut self,
16295        _: &GoToDefinition,
16296        window: &mut Window,
16297        cx: &mut Context<Self>,
16298    ) -> Task<Result<Navigated>> {
16299        let definition =
16300            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16301        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16302        cx.spawn_in(window, async move |editor, cx| {
16303            if definition.await? == Navigated::Yes {
16304                return Ok(Navigated::Yes);
16305            }
16306            match fallback_strategy {
16307                GoToDefinitionFallback::None => Ok(Navigated::No),
16308                GoToDefinitionFallback::FindAllReferences => {
16309                    match editor.update_in(cx, |editor, window, cx| {
16310                        editor.find_all_references(&FindAllReferences, window, cx)
16311                    })? {
16312                        Some(references) => references.await,
16313                        None => Ok(Navigated::No),
16314                    }
16315                }
16316            }
16317        })
16318    }
16319
16320    pub fn go_to_declaration(
16321        &mut self,
16322        _: &GoToDeclaration,
16323        window: &mut Window,
16324        cx: &mut Context<Self>,
16325    ) -> Task<Result<Navigated>> {
16326        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16327    }
16328
16329    pub fn go_to_declaration_split(
16330        &mut self,
16331        _: &GoToDeclaration,
16332        window: &mut Window,
16333        cx: &mut Context<Self>,
16334    ) -> Task<Result<Navigated>> {
16335        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16336    }
16337
16338    pub fn go_to_implementation(
16339        &mut self,
16340        _: &GoToImplementation,
16341        window: &mut Window,
16342        cx: &mut Context<Self>,
16343    ) -> Task<Result<Navigated>> {
16344        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16345    }
16346
16347    pub fn go_to_implementation_split(
16348        &mut self,
16349        _: &GoToImplementationSplit,
16350        window: &mut Window,
16351        cx: &mut Context<Self>,
16352    ) -> Task<Result<Navigated>> {
16353        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16354    }
16355
16356    pub fn go_to_type_definition(
16357        &mut self,
16358        _: &GoToTypeDefinition,
16359        window: &mut Window,
16360        cx: &mut Context<Self>,
16361    ) -> Task<Result<Navigated>> {
16362        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16363    }
16364
16365    pub fn go_to_definition_split(
16366        &mut self,
16367        _: &GoToDefinitionSplit,
16368        window: &mut Window,
16369        cx: &mut Context<Self>,
16370    ) -> Task<Result<Navigated>> {
16371        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16372    }
16373
16374    pub fn go_to_type_definition_split(
16375        &mut self,
16376        _: &GoToTypeDefinitionSplit,
16377        window: &mut Window,
16378        cx: &mut Context<Self>,
16379    ) -> Task<Result<Navigated>> {
16380        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16381    }
16382
16383    fn go_to_definition_of_kind(
16384        &mut self,
16385        kind: GotoDefinitionKind,
16386        split: bool,
16387        window: &mut Window,
16388        cx: &mut Context<Self>,
16389    ) -> Task<Result<Navigated>> {
16390        let Some(provider) = self.semantics_provider.clone() else {
16391            return Task::ready(Ok(Navigated::No));
16392        };
16393        let head = self.selections.newest::<usize>(cx).head();
16394        let buffer = self.buffer.read(cx);
16395        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16396            return Task::ready(Ok(Navigated::No));
16397        };
16398        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16399            return Task::ready(Ok(Navigated::No));
16400        };
16401
16402        cx.spawn_in(window, async move |editor, cx| {
16403            let Some(definitions) = definitions.await? else {
16404                return Ok(Navigated::No);
16405            };
16406            let navigated = editor
16407                .update_in(cx, |editor, window, cx| {
16408                    editor.navigate_to_hover_links(
16409                        Some(kind),
16410                        definitions
16411                            .into_iter()
16412                            .filter(|location| {
16413                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16414                            })
16415                            .map(HoverLink::Text)
16416                            .collect::<Vec<_>>(),
16417                        split,
16418                        window,
16419                        cx,
16420                    )
16421                })?
16422                .await?;
16423            anyhow::Ok(navigated)
16424        })
16425    }
16426
16427    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16428        let selection = self.selections.newest_anchor();
16429        let head = selection.head();
16430        let tail = selection.tail();
16431
16432        let Some((buffer, start_position)) =
16433            self.buffer.read(cx).text_anchor_for_position(head, cx)
16434        else {
16435            return;
16436        };
16437
16438        let end_position = if head != tail {
16439            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16440                return;
16441            };
16442            Some(pos)
16443        } else {
16444            None
16445        };
16446
16447        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16448            let url = if let Some(end_pos) = end_position {
16449                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16450            } else {
16451                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16452            };
16453
16454            if let Some(url) = url {
16455                cx.update(|window, cx| {
16456                    if parse_zed_link(&url, cx).is_some() {
16457                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16458                    } else {
16459                        cx.open_url(&url);
16460                    }
16461                })?;
16462            }
16463
16464            anyhow::Ok(())
16465        });
16466
16467        url_finder.detach();
16468    }
16469
16470    pub fn open_selected_filename(
16471        &mut self,
16472        _: &OpenSelectedFilename,
16473        window: &mut Window,
16474        cx: &mut Context<Self>,
16475    ) {
16476        let Some(workspace) = self.workspace() else {
16477            return;
16478        };
16479
16480        let position = self.selections.newest_anchor().head();
16481
16482        let Some((buffer, buffer_position)) =
16483            self.buffer.read(cx).text_anchor_for_position(position, cx)
16484        else {
16485            return;
16486        };
16487
16488        let project = self.project.clone();
16489
16490        cx.spawn_in(window, async move |_, cx| {
16491            let result = find_file(&buffer, project, buffer_position, cx).await;
16492
16493            if let Some((_, path)) = result {
16494                workspace
16495                    .update_in(cx, |workspace, window, cx| {
16496                        workspace.open_resolved_path(path, window, cx)
16497                    })?
16498                    .await?;
16499            }
16500            anyhow::Ok(())
16501        })
16502        .detach();
16503    }
16504
16505    pub(crate) fn navigate_to_hover_links(
16506        &mut self,
16507        kind: Option<GotoDefinitionKind>,
16508        definitions: Vec<HoverLink>,
16509        split: bool,
16510        window: &mut Window,
16511        cx: &mut Context<Editor>,
16512    ) -> Task<Result<Navigated>> {
16513        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16514        let mut first_url_or_file = None;
16515        let definitions: Vec<_> = definitions
16516            .into_iter()
16517            .filter_map(|def| match def {
16518                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16519                HoverLink::InlayHint(lsp_location, server_id) => {
16520                    let computation =
16521                        self.compute_target_location(lsp_location, server_id, window, cx);
16522                    Some(cx.background_spawn(computation))
16523                }
16524                HoverLink::Url(url) => {
16525                    first_url_or_file = Some(Either::Left(url));
16526                    None
16527                }
16528                HoverLink::File(path) => {
16529                    first_url_or_file = Some(Either::Right(path));
16530                    None
16531                }
16532            })
16533            .collect();
16534
16535        let workspace = self.workspace();
16536
16537        cx.spawn_in(window, async move |editor, cx| {
16538            let locations: Vec<Location> = future::join_all(definitions)
16539                .await
16540                .into_iter()
16541                .filter_map(|location| location.transpose())
16542                .collect::<Result<_>>()
16543                .context("location tasks")?;
16544            let mut locations = cx.update(|_, cx| {
16545                locations
16546                    .into_iter()
16547                    .map(|location| {
16548                        let buffer = location.buffer.read(cx);
16549                        (location.buffer, location.range.to_point(buffer))
16550                    })
16551                    .into_group_map()
16552            })?;
16553            let mut num_locations = 0;
16554            for ranges in locations.values_mut() {
16555                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16556                ranges.dedup();
16557                num_locations += ranges.len();
16558            }
16559
16560            if num_locations > 1 {
16561                let Some(workspace) = workspace else {
16562                    return Ok(Navigated::No);
16563                };
16564
16565                let tab_kind = match kind {
16566                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16567                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16568                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16569                    Some(GotoDefinitionKind::Type) => "Types",
16570                };
16571                let title = editor
16572                    .update_in(cx, |_, _, cx| {
16573                        let target = locations
16574                            .iter()
16575                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16576                            .map(|(buffer, location)| {
16577                                buffer
16578                                    .read(cx)
16579                                    .text_for_range(location.clone())
16580                                    .collect::<String>()
16581                            })
16582                            .filter(|text| !text.contains('\n'))
16583                            .unique()
16584                            .take(3)
16585                            .join(", ");
16586                        if target.is_empty() {
16587                            tab_kind.to_owned()
16588                        } else {
16589                            format!("{tab_kind} for {target}")
16590                        }
16591                    })
16592                    .context("buffer title")?;
16593
16594                let opened = workspace
16595                    .update_in(cx, |workspace, window, cx| {
16596                        Self::open_locations_in_multibuffer(
16597                            workspace,
16598                            locations,
16599                            title,
16600                            split,
16601                            MultibufferSelectionMode::First,
16602                            window,
16603                            cx,
16604                        )
16605                    })
16606                    .is_ok();
16607
16608                anyhow::Ok(Navigated::from_bool(opened))
16609            } else if num_locations == 0 {
16610                // If there is one url or file, open it directly
16611                match first_url_or_file {
16612                    Some(Either::Left(url)) => {
16613                        cx.update(|_, cx| cx.open_url(&url))?;
16614                        Ok(Navigated::Yes)
16615                    }
16616                    Some(Either::Right(path)) => {
16617                        let Some(workspace) = workspace else {
16618                            return Ok(Navigated::No);
16619                        };
16620
16621                        workspace
16622                            .update_in(cx, |workspace, window, cx| {
16623                                workspace.open_resolved_path(path, window, cx)
16624                            })?
16625                            .await?;
16626                        Ok(Navigated::Yes)
16627                    }
16628                    None => Ok(Navigated::No),
16629                }
16630            } else {
16631                let Some(workspace) = workspace else {
16632                    return Ok(Navigated::No);
16633                };
16634
16635                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16636                let target_range = target_ranges.first().unwrap().clone();
16637
16638                editor.update_in(cx, |editor, window, cx| {
16639                    let range = target_range.to_point(target_buffer.read(cx));
16640                    let range = editor.range_for_match(&range);
16641                    let range = collapse_multiline_range(range);
16642
16643                    if !split
16644                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16645                    {
16646                        editor.go_to_singleton_buffer_range(range, window, cx);
16647                    } else {
16648                        let pane = workspace.read(cx).active_pane().clone();
16649                        window.defer(cx, move |window, cx| {
16650                            let target_editor: Entity<Self> =
16651                                workspace.update(cx, |workspace, cx| {
16652                                    let pane = if split {
16653                                        workspace.adjacent_pane(window, cx)
16654                                    } else {
16655                                        workspace.active_pane().clone()
16656                                    };
16657
16658                                    workspace.open_project_item(
16659                                        pane,
16660                                        target_buffer.clone(),
16661                                        true,
16662                                        true,
16663                                        window,
16664                                        cx,
16665                                    )
16666                                });
16667                            target_editor.update(cx, |target_editor, cx| {
16668                                // When selecting a definition in a different buffer, disable the nav history
16669                                // to avoid creating a history entry at the previous cursor location.
16670                                pane.update(cx, |pane, _| pane.disable_history());
16671                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16672                                pane.update(cx, |pane, _| pane.enable_history());
16673                            });
16674                        });
16675                    }
16676                    Navigated::Yes
16677                })
16678            }
16679        })
16680    }
16681
16682    fn compute_target_location(
16683        &self,
16684        lsp_location: lsp::Location,
16685        server_id: LanguageServerId,
16686        window: &mut Window,
16687        cx: &mut Context<Self>,
16688    ) -> Task<anyhow::Result<Option<Location>>> {
16689        let Some(project) = self.project.clone() else {
16690            return Task::ready(Ok(None));
16691        };
16692
16693        cx.spawn_in(window, async move |editor, cx| {
16694            let location_task = editor.update(cx, |_, cx| {
16695                project.update(cx, |project, cx| {
16696                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16697                })
16698            })?;
16699            let location = Some({
16700                let target_buffer_handle = location_task.await.context("open local buffer")?;
16701                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16702                    let target_start = target_buffer
16703                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16704                    let target_end = target_buffer
16705                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16706                    target_buffer.anchor_after(target_start)
16707                        ..target_buffer.anchor_before(target_end)
16708                })?;
16709                Location {
16710                    buffer: target_buffer_handle,
16711                    range,
16712                }
16713            });
16714            Ok(location)
16715        })
16716    }
16717
16718    pub fn find_all_references(
16719        &mut self,
16720        _: &FindAllReferences,
16721        window: &mut Window,
16722        cx: &mut Context<Self>,
16723    ) -> Option<Task<Result<Navigated>>> {
16724        let selection = self.selections.newest::<usize>(cx);
16725        let multi_buffer = self.buffer.read(cx);
16726        let head = selection.head();
16727
16728        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16729        let head_anchor = multi_buffer_snapshot.anchor_at(
16730            head,
16731            if head < selection.tail() {
16732                Bias::Right
16733            } else {
16734                Bias::Left
16735            },
16736        );
16737
16738        match self
16739            .find_all_references_task_sources
16740            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16741        {
16742            Ok(_) => {
16743                log::info!(
16744                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16745                );
16746                return None;
16747            }
16748            Err(i) => {
16749                self.find_all_references_task_sources.insert(i, head_anchor);
16750            }
16751        }
16752
16753        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16754        let workspace = self.workspace()?;
16755        let project = workspace.read(cx).project().clone();
16756        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16757        Some(cx.spawn_in(window, async move |editor, cx| {
16758            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16759                if let Ok(i) = editor
16760                    .find_all_references_task_sources
16761                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16762                {
16763                    editor.find_all_references_task_sources.remove(i);
16764                }
16765            });
16766
16767            let Some(locations) = references.await? else {
16768                return anyhow::Ok(Navigated::No);
16769            };
16770            let mut locations = cx.update(|_, cx| {
16771                locations
16772                    .into_iter()
16773                    .map(|location| {
16774                        let buffer = location.buffer.read(cx);
16775                        (location.buffer, location.range.to_point(buffer))
16776                    })
16777                    .into_group_map()
16778            })?;
16779            if locations.is_empty() {
16780                return anyhow::Ok(Navigated::No);
16781            }
16782            for ranges in locations.values_mut() {
16783                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16784                ranges.dedup();
16785            }
16786
16787            workspace.update_in(cx, |workspace, window, cx| {
16788                let target = locations
16789                    .iter()
16790                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16791                    .map(|(buffer, location)| {
16792                        buffer
16793                            .read(cx)
16794                            .text_for_range(location.clone())
16795                            .collect::<String>()
16796                    })
16797                    .filter(|text| !text.contains('\n'))
16798                    .unique()
16799                    .take(3)
16800                    .join(", ");
16801                let title = if target.is_empty() {
16802                    "References".to_owned()
16803                } else {
16804                    format!("References to {target}")
16805                };
16806                Self::open_locations_in_multibuffer(
16807                    workspace,
16808                    locations,
16809                    title,
16810                    false,
16811                    MultibufferSelectionMode::First,
16812                    window,
16813                    cx,
16814                );
16815                Navigated::Yes
16816            })
16817        }))
16818    }
16819
16820    /// Opens a multibuffer with the given project locations in it
16821    pub fn open_locations_in_multibuffer(
16822        workspace: &mut Workspace,
16823        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16824        title: String,
16825        split: bool,
16826        multibuffer_selection_mode: MultibufferSelectionMode,
16827        window: &mut Window,
16828        cx: &mut Context<Workspace>,
16829    ) {
16830        if locations.is_empty() {
16831            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16832            return;
16833        }
16834
16835        let capability = workspace.project().read(cx).capability();
16836        let mut ranges = <Vec<Range<Anchor>>>::new();
16837
16838        // a key to find existing multibuffer editors with the same set of locations
16839        // to prevent us from opening more and more multibuffer tabs for searches and the like
16840        let mut key = (title.clone(), vec![]);
16841        let excerpt_buffer = cx.new(|cx| {
16842            let key = &mut key.1;
16843            let mut multibuffer = MultiBuffer::new(capability);
16844            for (buffer, mut ranges_for_buffer) in locations {
16845                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16846                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16847                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16848                    PathKey::for_buffer(&buffer, cx),
16849                    buffer.clone(),
16850                    ranges_for_buffer,
16851                    multibuffer_context_lines(cx),
16852                    cx,
16853                );
16854                ranges.extend(new_ranges)
16855            }
16856
16857            multibuffer.with_title(title)
16858        });
16859        let existing = workspace.active_pane().update(cx, |pane, cx| {
16860            pane.items()
16861                .filter_map(|item| item.downcast::<Editor>())
16862                .find(|editor| {
16863                    editor
16864                        .read(cx)
16865                        .lookup_key
16866                        .as_ref()
16867                        .and_then(|it| {
16868                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16869                        })
16870                        .is_some_and(|it| *it == key)
16871                })
16872        });
16873        let editor = existing.unwrap_or_else(|| {
16874            cx.new(|cx| {
16875                let mut editor = Editor::for_multibuffer(
16876                    excerpt_buffer,
16877                    Some(workspace.project().clone()),
16878                    window,
16879                    cx,
16880                );
16881                editor.lookup_key = Some(Box::new(key));
16882                editor
16883            })
16884        });
16885        editor.update(cx, |editor, cx| {
16886            match multibuffer_selection_mode {
16887                MultibufferSelectionMode::First => {
16888                    if let Some(first_range) = ranges.first() {
16889                        editor.change_selections(
16890                            SelectionEffects::no_scroll(),
16891                            window,
16892                            cx,
16893                            |selections| {
16894                                selections.clear_disjoint();
16895                                selections
16896                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16897                            },
16898                        );
16899                    }
16900                    editor.highlight_background::<Self>(
16901                        &ranges,
16902                        |theme| theme.colors().editor_highlighted_line_background,
16903                        cx,
16904                    );
16905                }
16906                MultibufferSelectionMode::All => {
16907                    editor.change_selections(
16908                        SelectionEffects::no_scroll(),
16909                        window,
16910                        cx,
16911                        |selections| {
16912                            selections.clear_disjoint();
16913                            selections.select_anchor_ranges(ranges);
16914                        },
16915                    );
16916                }
16917            }
16918            editor.register_buffers_with_language_servers(cx);
16919        });
16920
16921        let item = Box::new(editor);
16922        let item_id = item.item_id();
16923
16924        if split {
16925            let pane = workspace.adjacent_pane(window, cx);
16926            workspace.add_item(pane, item, None, true, true, window, cx);
16927        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16928            let (preview_item_id, preview_item_idx) =
16929                workspace.active_pane().read_with(cx, |pane, _| {
16930                    (pane.preview_item_id(), pane.preview_item_idx())
16931                });
16932
16933            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16934
16935            if let Some(preview_item_id) = preview_item_id {
16936                workspace.active_pane().update(cx, |pane, cx| {
16937                    pane.remove_item(preview_item_id, false, false, window, cx);
16938                });
16939            }
16940        } else {
16941            workspace.add_item_to_active_pane(item, None, true, window, cx);
16942        }
16943        workspace.active_pane().update(cx, |pane, cx| {
16944            pane.set_preview_item_id(Some(item_id), cx);
16945        });
16946    }
16947
16948    pub fn rename(
16949        &mut self,
16950        _: &Rename,
16951        window: &mut Window,
16952        cx: &mut Context<Self>,
16953    ) -> Option<Task<Result<()>>> {
16954        use language::ToOffset as _;
16955
16956        let provider = self.semantics_provider.clone()?;
16957        let selection = self.selections.newest_anchor().clone();
16958        let (cursor_buffer, cursor_buffer_position) = self
16959            .buffer
16960            .read(cx)
16961            .text_anchor_for_position(selection.head(), cx)?;
16962        let (tail_buffer, cursor_buffer_position_end) = self
16963            .buffer
16964            .read(cx)
16965            .text_anchor_for_position(selection.tail(), cx)?;
16966        if tail_buffer != cursor_buffer {
16967            return None;
16968        }
16969
16970        let snapshot = cursor_buffer.read(cx).snapshot();
16971        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16972        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16973        let prepare_rename = provider
16974            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16975            .unwrap_or_else(|| Task::ready(Ok(None)));
16976        drop(snapshot);
16977
16978        Some(cx.spawn_in(window, async move |this, cx| {
16979            let rename_range = if let Some(range) = prepare_rename.await? {
16980                Some(range)
16981            } else {
16982                this.update(cx, |this, cx| {
16983                    let buffer = this.buffer.read(cx).snapshot(cx);
16984                    let mut buffer_highlights = this
16985                        .document_highlights_for_position(selection.head(), &buffer)
16986                        .filter(|highlight| {
16987                            highlight.start.excerpt_id == selection.head().excerpt_id
16988                                && highlight.end.excerpt_id == selection.head().excerpt_id
16989                        });
16990                    buffer_highlights
16991                        .next()
16992                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16993                })?
16994            };
16995            if let Some(rename_range) = rename_range {
16996                this.update_in(cx, |this, window, cx| {
16997                    let snapshot = cursor_buffer.read(cx).snapshot();
16998                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16999                    let cursor_offset_in_rename_range =
17000                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17001                    let cursor_offset_in_rename_range_end =
17002                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17003
17004                    this.take_rename(false, window, cx);
17005                    let buffer = this.buffer.read(cx).read(cx);
17006                    let cursor_offset = selection.head().to_offset(&buffer);
17007                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17008                    let rename_end = rename_start + rename_buffer_range.len();
17009                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17010                    let mut old_highlight_id = None;
17011                    let old_name: Arc<str> = buffer
17012                        .chunks(rename_start..rename_end, true)
17013                        .map(|chunk| {
17014                            if old_highlight_id.is_none() {
17015                                old_highlight_id = chunk.syntax_highlight_id;
17016                            }
17017                            chunk.text
17018                        })
17019                        .collect::<String>()
17020                        .into();
17021
17022                    drop(buffer);
17023
17024                    // Position the selection in the rename editor so that it matches the current selection.
17025                    this.show_local_selections = false;
17026                    let rename_editor = cx.new(|cx| {
17027                        let mut editor = Editor::single_line(window, cx);
17028                        editor.buffer.update(cx, |buffer, cx| {
17029                            buffer.edit([(0..0, old_name.clone())], None, cx)
17030                        });
17031                        let rename_selection_range = match cursor_offset_in_rename_range
17032                            .cmp(&cursor_offset_in_rename_range_end)
17033                        {
17034                            Ordering::Equal => {
17035                                editor.select_all(&SelectAll, window, cx);
17036                                return editor;
17037                            }
17038                            Ordering::Less => {
17039                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17040                            }
17041                            Ordering::Greater => {
17042                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17043                            }
17044                        };
17045                        if rename_selection_range.end > old_name.len() {
17046                            editor.select_all(&SelectAll, window, cx);
17047                        } else {
17048                            editor.change_selections(Default::default(), window, cx, |s| {
17049                                s.select_ranges([rename_selection_range]);
17050                            });
17051                        }
17052                        editor
17053                    });
17054                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17055                        if e == &EditorEvent::Focused {
17056                            cx.emit(EditorEvent::FocusedIn)
17057                        }
17058                    })
17059                    .detach();
17060
17061                    let write_highlights =
17062                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17063                    let read_highlights =
17064                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17065                    let ranges = write_highlights
17066                        .iter()
17067                        .flat_map(|(_, ranges)| ranges.iter())
17068                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17069                        .cloned()
17070                        .collect();
17071
17072                    this.highlight_text::<Rename>(
17073                        ranges,
17074                        HighlightStyle {
17075                            fade_out: Some(0.6),
17076                            ..Default::default()
17077                        },
17078                        cx,
17079                    );
17080                    let rename_focus_handle = rename_editor.focus_handle(cx);
17081                    window.focus(&rename_focus_handle);
17082                    let block_id = this.insert_blocks(
17083                        [BlockProperties {
17084                            style: BlockStyle::Flex,
17085                            placement: BlockPlacement::Below(range.start),
17086                            height: Some(1),
17087                            render: Arc::new({
17088                                let rename_editor = rename_editor.clone();
17089                                move |cx: &mut BlockContext| {
17090                                    let mut text_style = cx.editor_style.text.clone();
17091                                    if let Some(highlight_style) = old_highlight_id
17092                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17093                                    {
17094                                        text_style = text_style.highlight(highlight_style);
17095                                    }
17096                                    div()
17097                                        .block_mouse_except_scroll()
17098                                        .pl(cx.anchor_x)
17099                                        .child(EditorElement::new(
17100                                            &rename_editor,
17101                                            EditorStyle {
17102                                                background: cx.theme().system().transparent,
17103                                                local_player: cx.editor_style.local_player,
17104                                                text: text_style,
17105                                                scrollbar_width: cx.editor_style.scrollbar_width,
17106                                                syntax: cx.editor_style.syntax.clone(),
17107                                                status: cx.editor_style.status.clone(),
17108                                                inlay_hints_style: HighlightStyle {
17109                                                    font_weight: Some(FontWeight::BOLD),
17110                                                    ..make_inlay_hints_style(cx.app)
17111                                                },
17112                                                edit_prediction_styles: make_suggestion_styles(
17113                                                    cx.app,
17114                                                ),
17115                                                ..EditorStyle::default()
17116                                            },
17117                                        ))
17118                                        .into_any_element()
17119                                }
17120                            }),
17121                            priority: 0,
17122                        }],
17123                        Some(Autoscroll::fit()),
17124                        cx,
17125                    )[0];
17126                    this.pending_rename = Some(RenameState {
17127                        range,
17128                        old_name,
17129                        editor: rename_editor,
17130                        block_id,
17131                    });
17132                })?;
17133            }
17134
17135            Ok(())
17136        }))
17137    }
17138
17139    pub fn confirm_rename(
17140        &mut self,
17141        _: &ConfirmRename,
17142        window: &mut Window,
17143        cx: &mut Context<Self>,
17144    ) -> Option<Task<Result<()>>> {
17145        let rename = self.take_rename(false, window, cx)?;
17146        let workspace = self.workspace()?.downgrade();
17147        let (buffer, start) = self
17148            .buffer
17149            .read(cx)
17150            .text_anchor_for_position(rename.range.start, cx)?;
17151        let (end_buffer, _) = self
17152            .buffer
17153            .read(cx)
17154            .text_anchor_for_position(rename.range.end, cx)?;
17155        if buffer != end_buffer {
17156            return None;
17157        }
17158
17159        let old_name = rename.old_name;
17160        let new_name = rename.editor.read(cx).text(cx);
17161
17162        let rename = self.semantics_provider.as_ref()?.perform_rename(
17163            &buffer,
17164            start,
17165            new_name.clone(),
17166            cx,
17167        )?;
17168
17169        Some(cx.spawn_in(window, async move |editor, cx| {
17170            let project_transaction = rename.await?;
17171            Self::open_project_transaction(
17172                &editor,
17173                workspace,
17174                project_transaction,
17175                format!("Rename: {}{}", old_name, new_name),
17176                cx,
17177            )
17178            .await?;
17179
17180            editor.update(cx, |editor, cx| {
17181                editor.refresh_document_highlights(cx);
17182            })?;
17183            Ok(())
17184        }))
17185    }
17186
17187    fn take_rename(
17188        &mut self,
17189        moving_cursor: bool,
17190        window: &mut Window,
17191        cx: &mut Context<Self>,
17192    ) -> Option<RenameState> {
17193        let rename = self.pending_rename.take()?;
17194        if rename.editor.focus_handle(cx).is_focused(window) {
17195            window.focus(&self.focus_handle);
17196        }
17197
17198        self.remove_blocks(
17199            [rename.block_id].into_iter().collect(),
17200            Some(Autoscroll::fit()),
17201            cx,
17202        );
17203        self.clear_highlights::<Rename>(cx);
17204        self.show_local_selections = true;
17205
17206        if moving_cursor {
17207            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17208                editor.selections.newest::<usize>(cx).head()
17209            });
17210
17211            // Update the selection to match the position of the selection inside
17212            // the rename editor.
17213            let snapshot = self.buffer.read(cx).read(cx);
17214            let rename_range = rename.range.to_offset(&snapshot);
17215            let cursor_in_editor = snapshot
17216                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17217                .min(rename_range.end);
17218            drop(snapshot);
17219
17220            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17221                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17222            });
17223        } else {
17224            self.refresh_document_highlights(cx);
17225        }
17226
17227        Some(rename)
17228    }
17229
17230    pub fn pending_rename(&self) -> Option<&RenameState> {
17231        self.pending_rename.as_ref()
17232    }
17233
17234    fn format(
17235        &mut self,
17236        _: &Format,
17237        window: &mut Window,
17238        cx: &mut Context<Self>,
17239    ) -> Option<Task<Result<()>>> {
17240        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17241
17242        let project = match &self.project {
17243            Some(project) => project.clone(),
17244            None => return None,
17245        };
17246
17247        Some(self.perform_format(
17248            project,
17249            FormatTrigger::Manual,
17250            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17251            window,
17252            cx,
17253        ))
17254    }
17255
17256    fn format_selections(
17257        &mut self,
17258        _: &FormatSelections,
17259        window: &mut Window,
17260        cx: &mut Context<Self>,
17261    ) -> Option<Task<Result<()>>> {
17262        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17263
17264        let project = match &self.project {
17265            Some(project) => project.clone(),
17266            None => return None,
17267        };
17268
17269        let ranges = self
17270            .selections
17271            .all_adjusted(cx)
17272            .into_iter()
17273            .map(|selection| selection.range())
17274            .collect_vec();
17275
17276        Some(self.perform_format(
17277            project,
17278            FormatTrigger::Manual,
17279            FormatTarget::Ranges(ranges),
17280            window,
17281            cx,
17282        ))
17283    }
17284
17285    fn perform_format(
17286        &mut self,
17287        project: Entity<Project>,
17288        trigger: FormatTrigger,
17289        target: FormatTarget,
17290        window: &mut Window,
17291        cx: &mut Context<Self>,
17292    ) -> Task<Result<()>> {
17293        let buffer = self.buffer.clone();
17294        let (buffers, target) = match target {
17295            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17296            FormatTarget::Ranges(selection_ranges) => {
17297                let multi_buffer = buffer.read(cx);
17298                let snapshot = multi_buffer.read(cx);
17299                let mut buffers = HashSet::default();
17300                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17301                    BTreeMap::new();
17302                for selection_range in selection_ranges {
17303                    for (buffer, buffer_range, _) in
17304                        snapshot.range_to_buffer_ranges(selection_range)
17305                    {
17306                        let buffer_id = buffer.remote_id();
17307                        let start = buffer.anchor_before(buffer_range.start);
17308                        let end = buffer.anchor_after(buffer_range.end);
17309                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17310                        buffer_id_to_ranges
17311                            .entry(buffer_id)
17312                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17313                            .or_insert_with(|| vec![start..end]);
17314                    }
17315                }
17316                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17317            }
17318        };
17319
17320        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17321        let selections_prev = transaction_id_prev
17322            .and_then(|transaction_id_prev| {
17323                // default to selections as they were after the last edit, if we have them,
17324                // instead of how they are now.
17325                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17326                // will take you back to where you made the last edit, instead of staying where you scrolled
17327                self.selection_history
17328                    .transaction(transaction_id_prev)
17329                    .map(|t| t.0.clone())
17330            })
17331            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17332
17333        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17334        let format = project.update(cx, |project, cx| {
17335            project.format(buffers, target, true, trigger, cx)
17336        });
17337
17338        cx.spawn_in(window, async move |editor, cx| {
17339            let transaction = futures::select_biased! {
17340                transaction = format.log_err().fuse() => transaction,
17341                () = timeout => {
17342                    log::warn!("timed out waiting for formatting");
17343                    None
17344                }
17345            };
17346
17347            buffer
17348                .update(cx, |buffer, cx| {
17349                    if let Some(transaction) = transaction
17350                        && !buffer.is_singleton()
17351                    {
17352                        buffer.push_transaction(&transaction.0, cx);
17353                    }
17354                    cx.notify();
17355                })
17356                .ok();
17357
17358            if let Some(transaction_id_now) =
17359                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17360            {
17361                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17362                if has_new_transaction {
17363                    _ = editor.update(cx, |editor, _| {
17364                        editor
17365                            .selection_history
17366                            .insert_transaction(transaction_id_now, selections_prev);
17367                    });
17368                }
17369            }
17370
17371            Ok(())
17372        })
17373    }
17374
17375    fn organize_imports(
17376        &mut self,
17377        _: &OrganizeImports,
17378        window: &mut Window,
17379        cx: &mut Context<Self>,
17380    ) -> Option<Task<Result<()>>> {
17381        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17382        let project = match &self.project {
17383            Some(project) => project.clone(),
17384            None => return None,
17385        };
17386        Some(self.perform_code_action_kind(
17387            project,
17388            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17389            window,
17390            cx,
17391        ))
17392    }
17393
17394    fn perform_code_action_kind(
17395        &mut self,
17396        project: Entity<Project>,
17397        kind: CodeActionKind,
17398        window: &mut Window,
17399        cx: &mut Context<Self>,
17400    ) -> Task<Result<()>> {
17401        let buffer = self.buffer.clone();
17402        let buffers = buffer.read(cx).all_buffers();
17403        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17404        let apply_action = project.update(cx, |project, cx| {
17405            project.apply_code_action_kind(buffers, kind, true, cx)
17406        });
17407        cx.spawn_in(window, async move |_, cx| {
17408            let transaction = futures::select_biased! {
17409                () = timeout => {
17410                    log::warn!("timed out waiting for executing code action");
17411                    None
17412                }
17413                transaction = apply_action.log_err().fuse() => transaction,
17414            };
17415            buffer
17416                .update(cx, |buffer, cx| {
17417                    // check if we need this
17418                    if let Some(transaction) = transaction
17419                        && !buffer.is_singleton()
17420                    {
17421                        buffer.push_transaction(&transaction.0, cx);
17422                    }
17423                    cx.notify();
17424                })
17425                .ok();
17426            Ok(())
17427        })
17428    }
17429
17430    pub fn restart_language_server(
17431        &mut self,
17432        _: &RestartLanguageServer,
17433        _: &mut Window,
17434        cx: &mut Context<Self>,
17435    ) {
17436        if let Some(project) = self.project.clone() {
17437            self.buffer.update(cx, |multi_buffer, cx| {
17438                project.update(cx, |project, cx| {
17439                    project.restart_language_servers_for_buffers(
17440                        multi_buffer.all_buffers().into_iter().collect(),
17441                        HashSet::default(),
17442                        cx,
17443                    );
17444                });
17445            })
17446        }
17447    }
17448
17449    pub fn stop_language_server(
17450        &mut self,
17451        _: &StopLanguageServer,
17452        _: &mut Window,
17453        cx: &mut Context<Self>,
17454    ) {
17455        if let Some(project) = self.project.clone() {
17456            self.buffer.update(cx, |multi_buffer, cx| {
17457                project.update(cx, |project, cx| {
17458                    project.stop_language_servers_for_buffers(
17459                        multi_buffer.all_buffers().into_iter().collect(),
17460                        HashSet::default(),
17461                        cx,
17462                    );
17463                    cx.emit(project::Event::RefreshInlayHints);
17464                });
17465            });
17466        }
17467    }
17468
17469    fn cancel_language_server_work(
17470        workspace: &mut Workspace,
17471        _: &actions::CancelLanguageServerWork,
17472        _: &mut Window,
17473        cx: &mut Context<Workspace>,
17474    ) {
17475        let project = workspace.project();
17476        let buffers = workspace
17477            .active_item(cx)
17478            .and_then(|item| item.act_as::<Editor>(cx))
17479            .map_or(HashSet::default(), |editor| {
17480                editor.read(cx).buffer.read(cx).all_buffers()
17481            });
17482        project.update(cx, |project, cx| {
17483            project.cancel_language_server_work_for_buffers(buffers, cx);
17484        });
17485    }
17486
17487    fn show_character_palette(
17488        &mut self,
17489        _: &ShowCharacterPalette,
17490        window: &mut Window,
17491        _: &mut Context<Self>,
17492    ) {
17493        window.show_character_palette();
17494    }
17495
17496    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17497        if !self.diagnostics_enabled() {
17498            return;
17499        }
17500
17501        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17502            let buffer = self.buffer.read(cx).snapshot(cx);
17503            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17504            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17505            let is_valid = buffer
17506                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17507                .any(|entry| {
17508                    entry.diagnostic.is_primary
17509                        && !entry.range.is_empty()
17510                        && entry.range.start == primary_range_start
17511                        && entry.diagnostic.message == active_diagnostics.active_message
17512                });
17513
17514            if !is_valid {
17515                self.dismiss_diagnostics(cx);
17516            }
17517        }
17518    }
17519
17520    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17521        match &self.active_diagnostics {
17522            ActiveDiagnostic::Group(group) => Some(group),
17523            _ => None,
17524        }
17525    }
17526
17527    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17528        if !self.diagnostics_enabled() {
17529            return;
17530        }
17531        self.dismiss_diagnostics(cx);
17532        self.active_diagnostics = ActiveDiagnostic::All;
17533    }
17534
17535    fn activate_diagnostics(
17536        &mut self,
17537        buffer_id: BufferId,
17538        diagnostic: DiagnosticEntryRef<'_, usize>,
17539        window: &mut Window,
17540        cx: &mut Context<Self>,
17541    ) {
17542        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17543            return;
17544        }
17545        self.dismiss_diagnostics(cx);
17546        let snapshot = self.snapshot(window, cx);
17547        let buffer = self.buffer.read(cx).snapshot(cx);
17548        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17549            return;
17550        };
17551
17552        let diagnostic_group = buffer
17553            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17554            .collect::<Vec<_>>();
17555
17556        let blocks =
17557            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17558
17559        let blocks = self.display_map.update(cx, |display_map, cx| {
17560            display_map.insert_blocks(blocks, cx).into_iter().collect()
17561        });
17562        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17563            active_range: buffer.anchor_before(diagnostic.range.start)
17564                ..buffer.anchor_after(diagnostic.range.end),
17565            active_message: diagnostic.diagnostic.message.clone(),
17566            group_id: diagnostic.diagnostic.group_id,
17567            blocks,
17568        });
17569        cx.notify();
17570    }
17571
17572    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17573        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17574            return;
17575        };
17576
17577        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17578        if let ActiveDiagnostic::Group(group) = prev {
17579            self.display_map.update(cx, |display_map, cx| {
17580                display_map.remove_blocks(group.blocks, cx);
17581            });
17582            cx.notify();
17583        }
17584    }
17585
17586    /// Disable inline diagnostics rendering for this editor.
17587    pub fn disable_inline_diagnostics(&mut self) {
17588        self.inline_diagnostics_enabled = false;
17589        self.inline_diagnostics_update = Task::ready(());
17590        self.inline_diagnostics.clear();
17591    }
17592
17593    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17594        self.diagnostics_enabled = false;
17595        self.dismiss_diagnostics(cx);
17596        self.inline_diagnostics_update = Task::ready(());
17597        self.inline_diagnostics.clear();
17598    }
17599
17600    pub fn disable_word_completions(&mut self) {
17601        self.word_completions_enabled = false;
17602    }
17603
17604    pub fn diagnostics_enabled(&self) -> bool {
17605        self.diagnostics_enabled && self.mode.is_full()
17606    }
17607
17608    pub fn inline_diagnostics_enabled(&self) -> bool {
17609        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17610    }
17611
17612    pub fn show_inline_diagnostics(&self) -> bool {
17613        self.show_inline_diagnostics
17614    }
17615
17616    pub fn toggle_inline_diagnostics(
17617        &mut self,
17618        _: &ToggleInlineDiagnostics,
17619        window: &mut Window,
17620        cx: &mut Context<Editor>,
17621    ) {
17622        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17623        self.refresh_inline_diagnostics(false, window, cx);
17624    }
17625
17626    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17627        self.diagnostics_max_severity = severity;
17628        self.display_map.update(cx, |display_map, _| {
17629            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17630        });
17631    }
17632
17633    pub fn toggle_diagnostics(
17634        &mut self,
17635        _: &ToggleDiagnostics,
17636        window: &mut Window,
17637        cx: &mut Context<Editor>,
17638    ) {
17639        if !self.diagnostics_enabled() {
17640            return;
17641        }
17642
17643        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17644            EditorSettings::get_global(cx)
17645                .diagnostics_max_severity
17646                .filter(|severity| severity != &DiagnosticSeverity::Off)
17647                .unwrap_or(DiagnosticSeverity::Hint)
17648        } else {
17649            DiagnosticSeverity::Off
17650        };
17651        self.set_max_diagnostics_severity(new_severity, cx);
17652        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17653            self.active_diagnostics = ActiveDiagnostic::None;
17654            self.inline_diagnostics_update = Task::ready(());
17655            self.inline_diagnostics.clear();
17656        } else {
17657            self.refresh_inline_diagnostics(false, window, cx);
17658        }
17659
17660        cx.notify();
17661    }
17662
17663    pub fn toggle_minimap(
17664        &mut self,
17665        _: &ToggleMinimap,
17666        window: &mut Window,
17667        cx: &mut Context<Editor>,
17668    ) {
17669        if self.supports_minimap(cx) {
17670            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17671        }
17672    }
17673
17674    fn refresh_inline_diagnostics(
17675        &mut self,
17676        debounce: bool,
17677        window: &mut Window,
17678        cx: &mut Context<Self>,
17679    ) {
17680        let max_severity = ProjectSettings::get_global(cx)
17681            .diagnostics
17682            .inline
17683            .max_severity
17684            .unwrap_or(self.diagnostics_max_severity);
17685
17686        if !self.inline_diagnostics_enabled()
17687            || !self.show_inline_diagnostics
17688            || max_severity == DiagnosticSeverity::Off
17689        {
17690            self.inline_diagnostics_update = Task::ready(());
17691            self.inline_diagnostics.clear();
17692            return;
17693        }
17694
17695        let debounce_ms = ProjectSettings::get_global(cx)
17696            .diagnostics
17697            .inline
17698            .update_debounce_ms;
17699        let debounce = if debounce && debounce_ms > 0 {
17700            Some(Duration::from_millis(debounce_ms))
17701        } else {
17702            None
17703        };
17704        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17705            if let Some(debounce) = debounce {
17706                cx.background_executor().timer(debounce).await;
17707            }
17708            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17709                editor
17710                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17711                    .ok()
17712            }) else {
17713                return;
17714            };
17715
17716            let new_inline_diagnostics = cx
17717                .background_spawn(async move {
17718                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17719                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17720                        let message = diagnostic_entry
17721                            .diagnostic
17722                            .message
17723                            .split_once('\n')
17724                            .map(|(line, _)| line)
17725                            .map(SharedString::new)
17726                            .unwrap_or_else(|| {
17727                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17728                            });
17729                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17730                        let (Ok(i) | Err(i)) = inline_diagnostics
17731                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17732                        inline_diagnostics.insert(
17733                            i,
17734                            (
17735                                start_anchor,
17736                                InlineDiagnostic {
17737                                    message,
17738                                    group_id: diagnostic_entry.diagnostic.group_id,
17739                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17740                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17741                                    severity: diagnostic_entry.diagnostic.severity,
17742                                },
17743                            ),
17744                        );
17745                    }
17746                    inline_diagnostics
17747                })
17748                .await;
17749
17750            editor
17751                .update(cx, |editor, cx| {
17752                    editor.inline_diagnostics = new_inline_diagnostics;
17753                    cx.notify();
17754                })
17755                .ok();
17756        });
17757    }
17758
17759    fn pull_diagnostics(
17760        &mut self,
17761        buffer_id: Option<BufferId>,
17762        window: &Window,
17763        cx: &mut Context<Self>,
17764    ) -> Option<()> {
17765        if !self.mode().is_full() {
17766            return None;
17767        }
17768        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17769            .diagnostics
17770            .lsp_pull_diagnostics;
17771        if !pull_diagnostics_settings.enabled {
17772            return None;
17773        }
17774        let project = self.project()?.downgrade();
17775        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17776        let mut buffers = self.buffer.read(cx).all_buffers();
17777        if let Some(buffer_id) = buffer_id {
17778            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17779        }
17780
17781        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17782            cx.background_executor().timer(debounce).await;
17783
17784            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17785                buffers
17786                    .into_iter()
17787                    .filter_map(|buffer| {
17788                        project
17789                            .update(cx, |project, cx| {
17790                                project.lsp_store().update(cx, |lsp_store, cx| {
17791                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17792                                })
17793                            })
17794                            .ok()
17795                    })
17796                    .collect::<FuturesUnordered<_>>()
17797            }) else {
17798                return;
17799            };
17800
17801            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17802                match pull_task {
17803                    Ok(()) => {
17804                        if editor
17805                            .update_in(cx, |editor, window, cx| {
17806                                editor.update_diagnostics_state(window, cx);
17807                            })
17808                            .is_err()
17809                        {
17810                            return;
17811                        }
17812                    }
17813                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17814                }
17815            }
17816        });
17817
17818        Some(())
17819    }
17820
17821    pub fn set_selections_from_remote(
17822        &mut self,
17823        selections: Vec<Selection<Anchor>>,
17824        pending_selection: Option<Selection<Anchor>>,
17825        window: &mut Window,
17826        cx: &mut Context<Self>,
17827    ) {
17828        let old_cursor_position = self.selections.newest_anchor().head();
17829        self.selections.change_with(cx, |s| {
17830            s.select_anchors(selections);
17831            if let Some(pending_selection) = pending_selection {
17832                s.set_pending(pending_selection, SelectMode::Character);
17833            } else {
17834                s.clear_pending();
17835            }
17836        });
17837        self.selections_did_change(
17838            false,
17839            &old_cursor_position,
17840            SelectionEffects::default(),
17841            window,
17842            cx,
17843        );
17844    }
17845
17846    pub fn transact(
17847        &mut self,
17848        window: &mut Window,
17849        cx: &mut Context<Self>,
17850        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17851    ) -> Option<TransactionId> {
17852        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17853            this.start_transaction_at(Instant::now(), window, cx);
17854            update(this, window, cx);
17855            this.end_transaction_at(Instant::now(), cx)
17856        })
17857    }
17858
17859    pub fn start_transaction_at(
17860        &mut self,
17861        now: Instant,
17862        window: &mut Window,
17863        cx: &mut Context<Self>,
17864    ) -> Option<TransactionId> {
17865        self.end_selection(window, cx);
17866        if let Some(tx_id) = self
17867            .buffer
17868            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17869        {
17870            self.selection_history
17871                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17872            cx.emit(EditorEvent::TransactionBegun {
17873                transaction_id: tx_id,
17874            });
17875            Some(tx_id)
17876        } else {
17877            None
17878        }
17879    }
17880
17881    pub fn end_transaction_at(
17882        &mut self,
17883        now: Instant,
17884        cx: &mut Context<Self>,
17885    ) -> Option<TransactionId> {
17886        if let Some(transaction_id) = self
17887            .buffer
17888            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17889        {
17890            if let Some((_, end_selections)) =
17891                self.selection_history.transaction_mut(transaction_id)
17892            {
17893                *end_selections = Some(self.selections.disjoint_anchors_arc());
17894            } else {
17895                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17896            }
17897
17898            cx.emit(EditorEvent::Edited { transaction_id });
17899            Some(transaction_id)
17900        } else {
17901            None
17902        }
17903    }
17904
17905    pub fn modify_transaction_selection_history(
17906        &mut self,
17907        transaction_id: TransactionId,
17908        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17909    ) -> bool {
17910        self.selection_history
17911            .transaction_mut(transaction_id)
17912            .map(modify)
17913            .is_some()
17914    }
17915
17916    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17917        if self.selection_mark_mode {
17918            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17919                s.move_with(|_, sel| {
17920                    sel.collapse_to(sel.head(), SelectionGoal::None);
17921                });
17922            })
17923        }
17924        self.selection_mark_mode = true;
17925        cx.notify();
17926    }
17927
17928    pub fn swap_selection_ends(
17929        &mut self,
17930        _: &actions::SwapSelectionEnds,
17931        window: &mut Window,
17932        cx: &mut Context<Self>,
17933    ) {
17934        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17935            s.move_with(|_, sel| {
17936                if sel.start != sel.end {
17937                    sel.reversed = !sel.reversed
17938                }
17939            });
17940        });
17941        self.request_autoscroll(Autoscroll::newest(), cx);
17942        cx.notify();
17943    }
17944
17945    pub fn toggle_focus(
17946        workspace: &mut Workspace,
17947        _: &actions::ToggleFocus,
17948        window: &mut Window,
17949        cx: &mut Context<Workspace>,
17950    ) {
17951        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17952            return;
17953        };
17954        workspace.activate_item(&item, true, true, window, cx);
17955    }
17956
17957    pub fn toggle_fold(
17958        &mut self,
17959        _: &actions::ToggleFold,
17960        window: &mut Window,
17961        cx: &mut Context<Self>,
17962    ) {
17963        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
17964            let selection = self.selections.newest::<Point>(cx);
17965
17966            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17967            let range = if selection.is_empty() {
17968                let point = selection.head().to_display_point(&display_map);
17969                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17970                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17971                    .to_point(&display_map);
17972                start..end
17973            } else {
17974                selection.range()
17975            };
17976            if display_map.folds_in_range(range).next().is_some() {
17977                self.unfold_lines(&Default::default(), window, cx)
17978            } else {
17979                self.fold(&Default::default(), window, cx)
17980            }
17981        } else {
17982            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17983            let buffer_ids: HashSet<_> = self
17984                .selections
17985                .disjoint_anchor_ranges()
17986                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17987                .collect();
17988
17989            let should_unfold = buffer_ids
17990                .iter()
17991                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17992
17993            for buffer_id in buffer_ids {
17994                if should_unfold {
17995                    self.unfold_buffer(buffer_id, cx);
17996                } else {
17997                    self.fold_buffer(buffer_id, cx);
17998                }
17999            }
18000        }
18001    }
18002
18003    pub fn toggle_fold_recursive(
18004        &mut self,
18005        _: &actions::ToggleFoldRecursive,
18006        window: &mut Window,
18007        cx: &mut Context<Self>,
18008    ) {
18009        let selection = self.selections.newest::<Point>(cx);
18010
18011        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18012        let range = if selection.is_empty() {
18013            let point = selection.head().to_display_point(&display_map);
18014            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18015            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18016                .to_point(&display_map);
18017            start..end
18018        } else {
18019            selection.range()
18020        };
18021        if display_map.folds_in_range(range).next().is_some() {
18022            self.unfold_recursive(&Default::default(), window, cx)
18023        } else {
18024            self.fold_recursive(&Default::default(), window, cx)
18025        }
18026    }
18027
18028    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18029        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18030            let mut to_fold = Vec::new();
18031            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18032            let selections = self.selections.all_adjusted(cx);
18033
18034            for selection in selections {
18035                let range = selection.range().sorted();
18036                let buffer_start_row = range.start.row;
18037
18038                if range.start.row != range.end.row {
18039                    let mut found = false;
18040                    let mut row = range.start.row;
18041                    while row <= range.end.row {
18042                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18043                        {
18044                            found = true;
18045                            row = crease.range().end.row + 1;
18046                            to_fold.push(crease);
18047                        } else {
18048                            row += 1
18049                        }
18050                    }
18051                    if found {
18052                        continue;
18053                    }
18054                }
18055
18056                for row in (0..=range.start.row).rev() {
18057                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18058                        && crease.range().end.row >= buffer_start_row
18059                    {
18060                        to_fold.push(crease);
18061                        if row <= range.start.row {
18062                            break;
18063                        }
18064                    }
18065                }
18066            }
18067
18068            self.fold_creases(to_fold, true, window, cx);
18069        } else {
18070            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18071            let buffer_ids = self
18072                .selections
18073                .disjoint_anchor_ranges()
18074                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18075                .collect::<HashSet<_>>();
18076            for buffer_id in buffer_ids {
18077                self.fold_buffer(buffer_id, cx);
18078            }
18079        }
18080    }
18081
18082    pub fn toggle_fold_all(
18083        &mut self,
18084        _: &actions::ToggleFoldAll,
18085        window: &mut Window,
18086        cx: &mut Context<Self>,
18087    ) {
18088        if self.buffer.read(cx).is_singleton() {
18089            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18090            let has_folds = display_map
18091                .folds_in_range(0..display_map.buffer_snapshot().len())
18092                .next()
18093                .is_some();
18094
18095            if has_folds {
18096                self.unfold_all(&actions::UnfoldAll, window, cx);
18097            } else {
18098                self.fold_all(&actions::FoldAll, window, cx);
18099            }
18100        } else {
18101            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18102            let should_unfold = buffer_ids
18103                .iter()
18104                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18105
18106            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18107                editor
18108                    .update_in(cx, |editor, _, cx| {
18109                        for buffer_id in buffer_ids {
18110                            if should_unfold {
18111                                editor.unfold_buffer(buffer_id, cx);
18112                            } else {
18113                                editor.fold_buffer(buffer_id, cx);
18114                            }
18115                        }
18116                    })
18117                    .ok();
18118            });
18119        }
18120    }
18121
18122    fn fold_at_level(
18123        &mut self,
18124        fold_at: &FoldAtLevel,
18125        window: &mut Window,
18126        cx: &mut Context<Self>,
18127    ) {
18128        if !self.buffer.read(cx).is_singleton() {
18129            return;
18130        }
18131
18132        let fold_at_level = fold_at.0;
18133        let snapshot = self.buffer.read(cx).snapshot(cx);
18134        let mut to_fold = Vec::new();
18135        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18136
18137        let row_ranges_to_keep: Vec<Range<u32>> = self
18138            .selections
18139            .all::<Point>(cx)
18140            .into_iter()
18141            .map(|sel| sel.start.row..sel.end.row)
18142            .collect();
18143
18144        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18145            while start_row < end_row {
18146                match self
18147                    .snapshot(window, cx)
18148                    .crease_for_buffer_row(MultiBufferRow(start_row))
18149                {
18150                    Some(crease) => {
18151                        let nested_start_row = crease.range().start.row + 1;
18152                        let nested_end_row = crease.range().end.row;
18153
18154                        if current_level < fold_at_level {
18155                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18156                        } else if current_level == fold_at_level {
18157                            // Fold iff there is no selection completely contained within the fold region
18158                            if !row_ranges_to_keep.iter().any(|selection| {
18159                                selection.end >= nested_start_row
18160                                    && selection.start <= nested_end_row
18161                            }) {
18162                                to_fold.push(crease);
18163                            }
18164                        }
18165
18166                        start_row = nested_end_row + 1;
18167                    }
18168                    None => start_row += 1,
18169                }
18170            }
18171        }
18172
18173        self.fold_creases(to_fold, true, window, cx);
18174    }
18175
18176    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18177        if self.buffer.read(cx).is_singleton() {
18178            let mut fold_ranges = Vec::new();
18179            let snapshot = self.buffer.read(cx).snapshot(cx);
18180
18181            for row in 0..snapshot.max_row().0 {
18182                if let Some(foldable_range) = self
18183                    .snapshot(window, cx)
18184                    .crease_for_buffer_row(MultiBufferRow(row))
18185                {
18186                    fold_ranges.push(foldable_range);
18187                }
18188            }
18189
18190            self.fold_creases(fold_ranges, true, window, cx);
18191        } else {
18192            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18193                editor
18194                    .update_in(cx, |editor, _, cx| {
18195                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18196                            editor.fold_buffer(buffer_id, cx);
18197                        }
18198                    })
18199                    .ok();
18200            });
18201        }
18202    }
18203
18204    pub fn fold_function_bodies(
18205        &mut self,
18206        _: &actions::FoldFunctionBodies,
18207        window: &mut Window,
18208        cx: &mut Context<Self>,
18209    ) {
18210        let snapshot = self.buffer.read(cx).snapshot(cx);
18211
18212        let ranges = snapshot
18213            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18214            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18215            .collect::<Vec<_>>();
18216
18217        let creases = ranges
18218            .into_iter()
18219            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18220            .collect();
18221
18222        self.fold_creases(creases, true, window, cx);
18223    }
18224
18225    pub fn fold_recursive(
18226        &mut self,
18227        _: &actions::FoldRecursive,
18228        window: &mut Window,
18229        cx: &mut Context<Self>,
18230    ) {
18231        let mut to_fold = Vec::new();
18232        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18233        let selections = self.selections.all_adjusted(cx);
18234
18235        for selection in selections {
18236            let range = selection.range().sorted();
18237            let buffer_start_row = range.start.row;
18238
18239            if range.start.row != range.end.row {
18240                let mut found = false;
18241                for row in range.start.row..=range.end.row {
18242                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18243                        found = true;
18244                        to_fold.push(crease);
18245                    }
18246                }
18247                if found {
18248                    continue;
18249                }
18250            }
18251
18252            for row in (0..=range.start.row).rev() {
18253                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18254                    if crease.range().end.row >= buffer_start_row {
18255                        to_fold.push(crease);
18256                    } else {
18257                        break;
18258                    }
18259                }
18260            }
18261        }
18262
18263        self.fold_creases(to_fold, true, window, cx);
18264    }
18265
18266    pub fn fold_at(
18267        &mut self,
18268        buffer_row: MultiBufferRow,
18269        window: &mut Window,
18270        cx: &mut Context<Self>,
18271    ) {
18272        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18273
18274        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18275            let autoscroll = self
18276                .selections
18277                .all::<Point>(cx)
18278                .iter()
18279                .any(|selection| crease.range().overlaps(&selection.range()));
18280
18281            self.fold_creases(vec![crease], autoscroll, window, cx);
18282        }
18283    }
18284
18285    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18286        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18287            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18288            let buffer = display_map.buffer_snapshot();
18289            let selections = self.selections.all::<Point>(cx);
18290            let ranges = selections
18291                .iter()
18292                .map(|s| {
18293                    let range = s.display_range(&display_map).sorted();
18294                    let mut start = range.start.to_point(&display_map);
18295                    let mut end = range.end.to_point(&display_map);
18296                    start.column = 0;
18297                    end.column = buffer.line_len(MultiBufferRow(end.row));
18298                    start..end
18299                })
18300                .collect::<Vec<_>>();
18301
18302            self.unfold_ranges(&ranges, true, true, cx);
18303        } else {
18304            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18305            let buffer_ids = self
18306                .selections
18307                .disjoint_anchor_ranges()
18308                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18309                .collect::<HashSet<_>>();
18310            for buffer_id in buffer_ids {
18311                self.unfold_buffer(buffer_id, cx);
18312            }
18313        }
18314    }
18315
18316    pub fn unfold_recursive(
18317        &mut self,
18318        _: &UnfoldRecursive,
18319        _window: &mut Window,
18320        cx: &mut Context<Self>,
18321    ) {
18322        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18323        let selections = self.selections.all::<Point>(cx);
18324        let ranges = selections
18325            .iter()
18326            .map(|s| {
18327                let mut range = s.display_range(&display_map).sorted();
18328                *range.start.column_mut() = 0;
18329                *range.end.column_mut() = display_map.line_len(range.end.row());
18330                let start = range.start.to_point(&display_map);
18331                let end = range.end.to_point(&display_map);
18332                start..end
18333            })
18334            .collect::<Vec<_>>();
18335
18336        self.unfold_ranges(&ranges, true, true, cx);
18337    }
18338
18339    pub fn unfold_at(
18340        &mut self,
18341        buffer_row: MultiBufferRow,
18342        _window: &mut Window,
18343        cx: &mut Context<Self>,
18344    ) {
18345        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18346
18347        let intersection_range = Point::new(buffer_row.0, 0)
18348            ..Point::new(
18349                buffer_row.0,
18350                display_map.buffer_snapshot().line_len(buffer_row),
18351            );
18352
18353        let autoscroll = self
18354            .selections
18355            .all::<Point>(cx)
18356            .iter()
18357            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18358
18359        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18360    }
18361
18362    pub fn unfold_all(
18363        &mut self,
18364        _: &actions::UnfoldAll,
18365        _window: &mut Window,
18366        cx: &mut Context<Self>,
18367    ) {
18368        if self.buffer.read(cx).is_singleton() {
18369            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18370            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18371        } else {
18372            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18373                editor
18374                    .update(cx, |editor, cx| {
18375                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18376                            editor.unfold_buffer(buffer_id, cx);
18377                        }
18378                    })
18379                    .ok();
18380            });
18381        }
18382    }
18383
18384    pub fn fold_selected_ranges(
18385        &mut self,
18386        _: &FoldSelectedRanges,
18387        window: &mut Window,
18388        cx: &mut Context<Self>,
18389    ) {
18390        let selections = self.selections.all_adjusted(cx);
18391        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18392        let ranges = selections
18393            .into_iter()
18394            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18395            .collect::<Vec<_>>();
18396        self.fold_creases(ranges, true, window, cx);
18397    }
18398
18399    pub fn fold_ranges<T: ToOffset + Clone>(
18400        &mut self,
18401        ranges: Vec<Range<T>>,
18402        auto_scroll: bool,
18403        window: &mut Window,
18404        cx: &mut Context<Self>,
18405    ) {
18406        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18407        let ranges = ranges
18408            .into_iter()
18409            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18410            .collect::<Vec<_>>();
18411        self.fold_creases(ranges, auto_scroll, window, cx);
18412    }
18413
18414    pub fn fold_creases<T: ToOffset + Clone>(
18415        &mut self,
18416        creases: Vec<Crease<T>>,
18417        auto_scroll: bool,
18418        _window: &mut Window,
18419        cx: &mut Context<Self>,
18420    ) {
18421        if creases.is_empty() {
18422            return;
18423        }
18424
18425        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18426
18427        if auto_scroll {
18428            self.request_autoscroll(Autoscroll::fit(), cx);
18429        }
18430
18431        cx.notify();
18432
18433        self.scrollbar_marker_state.dirty = true;
18434        self.folds_did_change(cx);
18435    }
18436
18437    /// Removes any folds whose ranges intersect any of the given ranges.
18438    pub fn unfold_ranges<T: ToOffset + Clone>(
18439        &mut self,
18440        ranges: &[Range<T>],
18441        inclusive: bool,
18442        auto_scroll: bool,
18443        cx: &mut Context<Self>,
18444    ) {
18445        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18446            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18447        });
18448        self.folds_did_change(cx);
18449    }
18450
18451    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18452        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18453            return;
18454        }
18455        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18456        self.display_map.update(cx, |display_map, cx| {
18457            display_map.fold_buffers([buffer_id], cx)
18458        });
18459        cx.emit(EditorEvent::BufferFoldToggled {
18460            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18461            folded: true,
18462        });
18463        cx.notify();
18464    }
18465
18466    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18467        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18468            return;
18469        }
18470        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18471        self.display_map.update(cx, |display_map, cx| {
18472            display_map.unfold_buffers([buffer_id], cx);
18473        });
18474        cx.emit(EditorEvent::BufferFoldToggled {
18475            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18476            folded: false,
18477        });
18478        cx.notify();
18479    }
18480
18481    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18482        self.display_map.read(cx).is_buffer_folded(buffer)
18483    }
18484
18485    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18486        self.display_map.read(cx).folded_buffers()
18487    }
18488
18489    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18490        self.display_map.update(cx, |display_map, cx| {
18491            display_map.disable_header_for_buffer(buffer_id, cx);
18492        });
18493        cx.notify();
18494    }
18495
18496    /// Removes any folds with the given ranges.
18497    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18498        &mut self,
18499        ranges: &[Range<T>],
18500        type_id: TypeId,
18501        auto_scroll: bool,
18502        cx: &mut Context<Self>,
18503    ) {
18504        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18505            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18506        });
18507        self.folds_did_change(cx);
18508    }
18509
18510    fn remove_folds_with<T: ToOffset + Clone>(
18511        &mut self,
18512        ranges: &[Range<T>],
18513        auto_scroll: bool,
18514        cx: &mut Context<Self>,
18515        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18516    ) {
18517        if ranges.is_empty() {
18518            return;
18519        }
18520
18521        let mut buffers_affected = HashSet::default();
18522        let multi_buffer = self.buffer().read(cx);
18523        for range in ranges {
18524            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18525                buffers_affected.insert(buffer.read(cx).remote_id());
18526            };
18527        }
18528
18529        self.display_map.update(cx, update);
18530
18531        if auto_scroll {
18532            self.request_autoscroll(Autoscroll::fit(), cx);
18533        }
18534
18535        cx.notify();
18536        self.scrollbar_marker_state.dirty = true;
18537        self.active_indent_guides_state.dirty = true;
18538    }
18539
18540    pub fn update_renderer_widths(
18541        &mut self,
18542        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18543        cx: &mut Context<Self>,
18544    ) -> bool {
18545        self.display_map
18546            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18547    }
18548
18549    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18550        self.display_map.read(cx).fold_placeholder.clone()
18551    }
18552
18553    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18554        self.buffer.update(cx, |buffer, cx| {
18555            buffer.set_all_diff_hunks_expanded(cx);
18556        });
18557    }
18558
18559    pub fn expand_all_diff_hunks(
18560        &mut self,
18561        _: &ExpandAllDiffHunks,
18562        _window: &mut Window,
18563        cx: &mut Context<Self>,
18564    ) {
18565        self.buffer.update(cx, |buffer, cx| {
18566            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18567        });
18568    }
18569
18570    pub fn toggle_selected_diff_hunks(
18571        &mut self,
18572        _: &ToggleSelectedDiffHunks,
18573        _window: &mut Window,
18574        cx: &mut Context<Self>,
18575    ) {
18576        let ranges: Vec<_> = self
18577            .selections
18578            .disjoint_anchors()
18579            .iter()
18580            .map(|s| s.range())
18581            .collect();
18582        self.toggle_diff_hunks_in_ranges(ranges, cx);
18583    }
18584
18585    pub fn diff_hunks_in_ranges<'a>(
18586        &'a self,
18587        ranges: &'a [Range<Anchor>],
18588        buffer: &'a MultiBufferSnapshot,
18589    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18590        ranges.iter().flat_map(move |range| {
18591            let end_excerpt_id = range.end.excerpt_id;
18592            let range = range.to_point(buffer);
18593            let mut peek_end = range.end;
18594            if range.end.row < buffer.max_row().0 {
18595                peek_end = Point::new(range.end.row + 1, 0);
18596            }
18597            buffer
18598                .diff_hunks_in_range(range.start..peek_end)
18599                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18600        })
18601    }
18602
18603    pub fn has_stageable_diff_hunks_in_ranges(
18604        &self,
18605        ranges: &[Range<Anchor>],
18606        snapshot: &MultiBufferSnapshot,
18607    ) -> bool {
18608        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18609        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18610    }
18611
18612    pub fn toggle_staged_selected_diff_hunks(
18613        &mut self,
18614        _: &::git::ToggleStaged,
18615        _: &mut Window,
18616        cx: &mut Context<Self>,
18617    ) {
18618        let snapshot = self.buffer.read(cx).snapshot(cx);
18619        let ranges: Vec<_> = self
18620            .selections
18621            .disjoint_anchors()
18622            .iter()
18623            .map(|s| s.range())
18624            .collect();
18625        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18626        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18627    }
18628
18629    pub fn set_render_diff_hunk_controls(
18630        &mut self,
18631        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18632        cx: &mut Context<Self>,
18633    ) {
18634        self.render_diff_hunk_controls = render_diff_hunk_controls;
18635        cx.notify();
18636    }
18637
18638    pub fn stage_and_next(
18639        &mut self,
18640        _: &::git::StageAndNext,
18641        window: &mut Window,
18642        cx: &mut Context<Self>,
18643    ) {
18644        self.do_stage_or_unstage_and_next(true, window, cx);
18645    }
18646
18647    pub fn unstage_and_next(
18648        &mut self,
18649        _: &::git::UnstageAndNext,
18650        window: &mut Window,
18651        cx: &mut Context<Self>,
18652    ) {
18653        self.do_stage_or_unstage_and_next(false, window, cx);
18654    }
18655
18656    pub fn stage_or_unstage_diff_hunks(
18657        &mut self,
18658        stage: bool,
18659        ranges: Vec<Range<Anchor>>,
18660        cx: &mut Context<Self>,
18661    ) {
18662        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18663        cx.spawn(async move |this, cx| {
18664            task.await?;
18665            this.update(cx, |this, cx| {
18666                let snapshot = this.buffer.read(cx).snapshot(cx);
18667                let chunk_by = this
18668                    .diff_hunks_in_ranges(&ranges, &snapshot)
18669                    .chunk_by(|hunk| hunk.buffer_id);
18670                for (buffer_id, hunks) in &chunk_by {
18671                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18672                }
18673            })
18674        })
18675        .detach_and_log_err(cx);
18676    }
18677
18678    fn save_buffers_for_ranges_if_needed(
18679        &mut self,
18680        ranges: &[Range<Anchor>],
18681        cx: &mut Context<Editor>,
18682    ) -> Task<Result<()>> {
18683        let multibuffer = self.buffer.read(cx);
18684        let snapshot = multibuffer.read(cx);
18685        let buffer_ids: HashSet<_> = ranges
18686            .iter()
18687            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18688            .collect();
18689        drop(snapshot);
18690
18691        let mut buffers = HashSet::default();
18692        for buffer_id in buffer_ids {
18693            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18694                let buffer = buffer_entity.read(cx);
18695                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18696                {
18697                    buffers.insert(buffer_entity);
18698                }
18699            }
18700        }
18701
18702        if let Some(project) = &self.project {
18703            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18704        } else {
18705            Task::ready(Ok(()))
18706        }
18707    }
18708
18709    fn do_stage_or_unstage_and_next(
18710        &mut self,
18711        stage: bool,
18712        window: &mut Window,
18713        cx: &mut Context<Self>,
18714    ) {
18715        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18716
18717        if ranges.iter().any(|range| range.start != range.end) {
18718            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18719            return;
18720        }
18721
18722        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18723        let snapshot = self.snapshot(window, cx);
18724        let position = self.selections.newest::<Point>(cx).head();
18725        let mut row = snapshot
18726            .buffer_snapshot()
18727            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18728            .find(|hunk| hunk.row_range.start.0 > position.row)
18729            .map(|hunk| hunk.row_range.start);
18730
18731        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18732        // Outside of the project diff editor, wrap around to the beginning.
18733        if !all_diff_hunks_expanded {
18734            row = row.or_else(|| {
18735                snapshot
18736                    .buffer_snapshot()
18737                    .diff_hunks_in_range(Point::zero()..position)
18738                    .find(|hunk| hunk.row_range.end.0 < position.row)
18739                    .map(|hunk| hunk.row_range.start)
18740            });
18741        }
18742
18743        if let Some(row) = row {
18744            let destination = Point::new(row.0, 0);
18745            let autoscroll = Autoscroll::center();
18746
18747            self.unfold_ranges(&[destination..destination], false, false, cx);
18748            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18749                s.select_ranges([destination..destination]);
18750            });
18751        }
18752    }
18753
18754    fn do_stage_or_unstage(
18755        &self,
18756        stage: bool,
18757        buffer_id: BufferId,
18758        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18759        cx: &mut App,
18760    ) -> Option<()> {
18761        let project = self.project()?;
18762        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18763        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18764        let buffer_snapshot = buffer.read(cx).snapshot();
18765        let file_exists = buffer_snapshot
18766            .file()
18767            .is_some_and(|file| file.disk_state().exists());
18768        diff.update(cx, |diff, cx| {
18769            diff.stage_or_unstage_hunks(
18770                stage,
18771                &hunks
18772                    .map(|hunk| buffer_diff::DiffHunk {
18773                        buffer_range: hunk.buffer_range,
18774                        diff_base_byte_range: hunk.diff_base_byte_range,
18775                        secondary_status: hunk.secondary_status,
18776                        range: Point::zero()..Point::zero(), // unused
18777                    })
18778                    .collect::<Vec<_>>(),
18779                &buffer_snapshot,
18780                file_exists,
18781                cx,
18782            )
18783        });
18784        None
18785    }
18786
18787    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18788        let ranges: Vec<_> = self
18789            .selections
18790            .disjoint_anchors()
18791            .iter()
18792            .map(|s| s.range())
18793            .collect();
18794        self.buffer
18795            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18796    }
18797
18798    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18799        self.buffer.update(cx, |buffer, cx| {
18800            let ranges = vec![Anchor::min()..Anchor::max()];
18801            if !buffer.all_diff_hunks_expanded()
18802                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18803            {
18804                buffer.collapse_diff_hunks(ranges, cx);
18805                true
18806            } else {
18807                false
18808            }
18809        })
18810    }
18811
18812    fn toggle_diff_hunks_in_ranges(
18813        &mut self,
18814        ranges: Vec<Range<Anchor>>,
18815        cx: &mut Context<Editor>,
18816    ) {
18817        self.buffer.update(cx, |buffer, cx| {
18818            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18819            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18820        })
18821    }
18822
18823    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18824        self.buffer.update(cx, |buffer, cx| {
18825            let snapshot = buffer.snapshot(cx);
18826            let excerpt_id = range.end.excerpt_id;
18827            let point_range = range.to_point(&snapshot);
18828            let expand = !buffer.single_hunk_is_expanded(range, cx);
18829            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18830        })
18831    }
18832
18833    pub(crate) fn apply_all_diff_hunks(
18834        &mut self,
18835        _: &ApplyAllDiffHunks,
18836        window: &mut Window,
18837        cx: &mut Context<Self>,
18838    ) {
18839        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18840
18841        let buffers = self.buffer.read(cx).all_buffers();
18842        for branch_buffer in buffers {
18843            branch_buffer.update(cx, |branch_buffer, cx| {
18844                branch_buffer.merge_into_base(Vec::new(), cx);
18845            });
18846        }
18847
18848        if let Some(project) = self.project.clone() {
18849            self.save(
18850                SaveOptions {
18851                    format: true,
18852                    autosave: false,
18853                },
18854                project,
18855                window,
18856                cx,
18857            )
18858            .detach_and_log_err(cx);
18859        }
18860    }
18861
18862    pub(crate) fn apply_selected_diff_hunks(
18863        &mut self,
18864        _: &ApplyDiffHunk,
18865        window: &mut Window,
18866        cx: &mut Context<Self>,
18867    ) {
18868        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18869        let snapshot = self.snapshot(window, cx);
18870        let hunks = snapshot.hunks_for_ranges(
18871            self.selections
18872                .all(cx)
18873                .into_iter()
18874                .map(|selection| selection.range()),
18875        );
18876        let mut ranges_by_buffer = HashMap::default();
18877        self.transact(window, cx, |editor, _window, cx| {
18878            for hunk in hunks {
18879                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18880                    ranges_by_buffer
18881                        .entry(buffer.clone())
18882                        .or_insert_with(Vec::new)
18883                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18884                }
18885            }
18886
18887            for (buffer, ranges) in ranges_by_buffer {
18888                buffer.update(cx, |buffer, cx| {
18889                    buffer.merge_into_base(ranges, cx);
18890                });
18891            }
18892        });
18893
18894        if let Some(project) = self.project.clone() {
18895            self.save(
18896                SaveOptions {
18897                    format: true,
18898                    autosave: false,
18899                },
18900                project,
18901                window,
18902                cx,
18903            )
18904            .detach_and_log_err(cx);
18905        }
18906    }
18907
18908    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18909        if hovered != self.gutter_hovered {
18910            self.gutter_hovered = hovered;
18911            cx.notify();
18912        }
18913    }
18914
18915    pub fn insert_blocks(
18916        &mut self,
18917        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18918        autoscroll: Option<Autoscroll>,
18919        cx: &mut Context<Self>,
18920    ) -> Vec<CustomBlockId> {
18921        let blocks = self
18922            .display_map
18923            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18924        if let Some(autoscroll) = autoscroll {
18925            self.request_autoscroll(autoscroll, cx);
18926        }
18927        cx.notify();
18928        blocks
18929    }
18930
18931    pub fn resize_blocks(
18932        &mut self,
18933        heights: HashMap<CustomBlockId, u32>,
18934        autoscroll: Option<Autoscroll>,
18935        cx: &mut Context<Self>,
18936    ) {
18937        self.display_map
18938            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18939        if let Some(autoscroll) = autoscroll {
18940            self.request_autoscroll(autoscroll, cx);
18941        }
18942        cx.notify();
18943    }
18944
18945    pub fn replace_blocks(
18946        &mut self,
18947        renderers: HashMap<CustomBlockId, RenderBlock>,
18948        autoscroll: Option<Autoscroll>,
18949        cx: &mut Context<Self>,
18950    ) {
18951        self.display_map
18952            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18953        if let Some(autoscroll) = autoscroll {
18954            self.request_autoscroll(autoscroll, cx);
18955        }
18956        cx.notify();
18957    }
18958
18959    pub fn remove_blocks(
18960        &mut self,
18961        block_ids: HashSet<CustomBlockId>,
18962        autoscroll: Option<Autoscroll>,
18963        cx: &mut Context<Self>,
18964    ) {
18965        self.display_map.update(cx, |display_map, cx| {
18966            display_map.remove_blocks(block_ids, cx)
18967        });
18968        if let Some(autoscroll) = autoscroll {
18969            self.request_autoscroll(autoscroll, cx);
18970        }
18971        cx.notify();
18972    }
18973
18974    pub fn row_for_block(
18975        &self,
18976        block_id: CustomBlockId,
18977        cx: &mut Context<Self>,
18978    ) -> Option<DisplayRow> {
18979        self.display_map
18980            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18981    }
18982
18983    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18984        self.focused_block = Some(focused_block);
18985    }
18986
18987    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18988        self.focused_block.take()
18989    }
18990
18991    pub fn insert_creases(
18992        &mut self,
18993        creases: impl IntoIterator<Item = Crease<Anchor>>,
18994        cx: &mut Context<Self>,
18995    ) -> Vec<CreaseId> {
18996        self.display_map
18997            .update(cx, |map, cx| map.insert_creases(creases, cx))
18998    }
18999
19000    pub fn remove_creases(
19001        &mut self,
19002        ids: impl IntoIterator<Item = CreaseId>,
19003        cx: &mut Context<Self>,
19004    ) -> Vec<(CreaseId, Range<Anchor>)> {
19005        self.display_map
19006            .update(cx, |map, cx| map.remove_creases(ids, cx))
19007    }
19008
19009    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19010        self.display_map
19011            .update(cx, |map, cx| map.snapshot(cx))
19012            .longest_row()
19013    }
19014
19015    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19016        self.display_map
19017            .update(cx, |map, cx| map.snapshot(cx))
19018            .max_point()
19019    }
19020
19021    pub fn text(&self, cx: &App) -> String {
19022        self.buffer.read(cx).read(cx).text()
19023    }
19024
19025    pub fn is_empty(&self, cx: &App) -> bool {
19026        self.buffer.read(cx).read(cx).is_empty()
19027    }
19028
19029    pub fn text_option(&self, cx: &App) -> Option<String> {
19030        let text = self.text(cx);
19031        let text = text.trim();
19032
19033        if text.is_empty() {
19034            return None;
19035        }
19036
19037        Some(text.to_string())
19038    }
19039
19040    pub fn set_text(
19041        &mut self,
19042        text: impl Into<Arc<str>>,
19043        window: &mut Window,
19044        cx: &mut Context<Self>,
19045    ) {
19046        self.transact(window, cx, |this, _, cx| {
19047            this.buffer
19048                .read(cx)
19049                .as_singleton()
19050                .expect("you can only call set_text on editors for singleton buffers")
19051                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19052        });
19053    }
19054
19055    pub fn display_text(&self, cx: &mut App) -> String {
19056        self.display_map
19057            .update(cx, |map, cx| map.snapshot(cx))
19058            .text()
19059    }
19060
19061    fn create_minimap(
19062        &self,
19063        minimap_settings: MinimapSettings,
19064        window: &mut Window,
19065        cx: &mut Context<Self>,
19066    ) -> Option<Entity<Self>> {
19067        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19068            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19069    }
19070
19071    fn initialize_new_minimap(
19072        &self,
19073        minimap_settings: MinimapSettings,
19074        window: &mut Window,
19075        cx: &mut Context<Self>,
19076    ) -> Entity<Self> {
19077        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19078
19079        let mut minimap = Editor::new_internal(
19080            EditorMode::Minimap {
19081                parent: cx.weak_entity(),
19082            },
19083            self.buffer.clone(),
19084            None,
19085            Some(self.display_map.clone()),
19086            window,
19087            cx,
19088        );
19089        minimap.scroll_manager.clone_state(&self.scroll_manager);
19090        minimap.set_text_style_refinement(TextStyleRefinement {
19091            font_size: Some(MINIMAP_FONT_SIZE),
19092            font_weight: Some(MINIMAP_FONT_WEIGHT),
19093            ..Default::default()
19094        });
19095        minimap.update_minimap_configuration(minimap_settings, cx);
19096        cx.new(|_| minimap)
19097    }
19098
19099    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19100        let current_line_highlight = minimap_settings
19101            .current_line_highlight
19102            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19103        self.set_current_line_highlight(Some(current_line_highlight));
19104    }
19105
19106    pub fn minimap(&self) -> Option<&Entity<Self>> {
19107        self.minimap
19108            .as_ref()
19109            .filter(|_| self.minimap_visibility.visible())
19110    }
19111
19112    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19113        let mut wrap_guides = smallvec![];
19114
19115        if self.show_wrap_guides == Some(false) {
19116            return wrap_guides;
19117        }
19118
19119        let settings = self.buffer.read(cx).language_settings(cx);
19120        if settings.show_wrap_guides {
19121            match self.soft_wrap_mode(cx) {
19122                SoftWrap::Column(soft_wrap) => {
19123                    wrap_guides.push((soft_wrap as usize, true));
19124                }
19125                SoftWrap::Bounded(soft_wrap) => {
19126                    wrap_guides.push((soft_wrap as usize, true));
19127                }
19128                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19129            }
19130            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19131        }
19132
19133        wrap_guides
19134    }
19135
19136    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19137        let settings = self.buffer.read(cx).language_settings(cx);
19138        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19139        match mode {
19140            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19141                SoftWrap::None
19142            }
19143            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19144            language_settings::SoftWrap::PreferredLineLength => {
19145                SoftWrap::Column(settings.preferred_line_length)
19146            }
19147            language_settings::SoftWrap::Bounded => {
19148                SoftWrap::Bounded(settings.preferred_line_length)
19149            }
19150        }
19151    }
19152
19153    pub fn set_soft_wrap_mode(
19154        &mut self,
19155        mode: language_settings::SoftWrap,
19156
19157        cx: &mut Context<Self>,
19158    ) {
19159        self.soft_wrap_mode_override = Some(mode);
19160        cx.notify();
19161    }
19162
19163    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19164        self.hard_wrap = hard_wrap;
19165        cx.notify();
19166    }
19167
19168    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19169        self.text_style_refinement = Some(style);
19170    }
19171
19172    /// called by the Element so we know what style we were most recently rendered with.
19173    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19174        // We intentionally do not inform the display map about the minimap style
19175        // so that wrapping is not recalculated and stays consistent for the editor
19176        // and its linked minimap.
19177        if !self.mode.is_minimap() {
19178            let font = style.text.font();
19179            let font_size = style.text.font_size.to_pixels(window.rem_size());
19180            let display_map = self
19181                .placeholder_display_map
19182                .as_ref()
19183                .filter(|_| self.is_empty(cx))
19184                .unwrap_or(&self.display_map);
19185
19186            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19187        }
19188        self.style = Some(style);
19189    }
19190
19191    pub fn style(&self) -> Option<&EditorStyle> {
19192        self.style.as_ref()
19193    }
19194
19195    // Called by the element. This method is not designed to be called outside of the editor
19196    // element's layout code because it does not notify when rewrapping is computed synchronously.
19197    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19198        if self.is_empty(cx) {
19199            self.placeholder_display_map
19200                .as_ref()
19201                .map_or(false, |display_map| {
19202                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19203                })
19204        } else {
19205            self.display_map
19206                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19207        }
19208    }
19209
19210    pub fn set_soft_wrap(&mut self) {
19211        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19212    }
19213
19214    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19215        if self.soft_wrap_mode_override.is_some() {
19216            self.soft_wrap_mode_override.take();
19217        } else {
19218            let soft_wrap = match self.soft_wrap_mode(cx) {
19219                SoftWrap::GitDiff => return,
19220                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19221                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19222                    language_settings::SoftWrap::None
19223                }
19224            };
19225            self.soft_wrap_mode_override = Some(soft_wrap);
19226        }
19227        cx.notify();
19228    }
19229
19230    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19231        let Some(workspace) = self.workspace() else {
19232            return;
19233        };
19234        let fs = workspace.read(cx).app_state().fs.clone();
19235        let current_show = TabBarSettings::get_global(cx).show;
19236        update_settings_file(fs, cx, move |setting, _| {
19237            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19238        });
19239    }
19240
19241    pub fn toggle_indent_guides(
19242        &mut self,
19243        _: &ToggleIndentGuides,
19244        _: &mut Window,
19245        cx: &mut Context<Self>,
19246    ) {
19247        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19248            self.buffer
19249                .read(cx)
19250                .language_settings(cx)
19251                .indent_guides
19252                .enabled
19253        });
19254        self.show_indent_guides = Some(!currently_enabled);
19255        cx.notify();
19256    }
19257
19258    fn should_show_indent_guides(&self) -> Option<bool> {
19259        self.show_indent_guides
19260    }
19261
19262    pub fn toggle_line_numbers(
19263        &mut self,
19264        _: &ToggleLineNumbers,
19265        _: &mut Window,
19266        cx: &mut Context<Self>,
19267    ) {
19268        let mut editor_settings = EditorSettings::get_global(cx).clone();
19269        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19270        EditorSettings::override_global(editor_settings, cx);
19271    }
19272
19273    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19274        if let Some(show_line_numbers) = self.show_line_numbers {
19275            return show_line_numbers;
19276        }
19277        EditorSettings::get_global(cx).gutter.line_numbers
19278    }
19279
19280    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19281        self.use_relative_line_numbers
19282            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19283    }
19284
19285    pub fn toggle_relative_line_numbers(
19286        &mut self,
19287        _: &ToggleRelativeLineNumbers,
19288        _: &mut Window,
19289        cx: &mut Context<Self>,
19290    ) {
19291        let is_relative = self.should_use_relative_line_numbers(cx);
19292        self.set_relative_line_number(Some(!is_relative), cx)
19293    }
19294
19295    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19296        self.use_relative_line_numbers = is_relative;
19297        cx.notify();
19298    }
19299
19300    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19301        self.show_gutter = show_gutter;
19302        cx.notify();
19303    }
19304
19305    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19306        self.show_scrollbars = ScrollbarAxes {
19307            horizontal: show,
19308            vertical: show,
19309        };
19310        cx.notify();
19311    }
19312
19313    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19314        self.show_scrollbars.vertical = show;
19315        cx.notify();
19316    }
19317
19318    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19319        self.show_scrollbars.horizontal = show;
19320        cx.notify();
19321    }
19322
19323    pub fn set_minimap_visibility(
19324        &mut self,
19325        minimap_visibility: MinimapVisibility,
19326        window: &mut Window,
19327        cx: &mut Context<Self>,
19328    ) {
19329        if self.minimap_visibility != minimap_visibility {
19330            if minimap_visibility.visible() && self.minimap.is_none() {
19331                let minimap_settings = EditorSettings::get_global(cx).minimap;
19332                self.minimap =
19333                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19334            }
19335            self.minimap_visibility = minimap_visibility;
19336            cx.notify();
19337        }
19338    }
19339
19340    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19341        self.set_show_scrollbars(false, cx);
19342        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19343    }
19344
19345    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19346        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19347    }
19348
19349    /// Normally the text in full mode and auto height editors is padded on the
19350    /// left side by roughly half a character width for improved hit testing.
19351    ///
19352    /// Use this method to disable this for cases where this is not wanted (e.g.
19353    /// if you want to align the editor text with some other text above or below)
19354    /// or if you want to add this padding to single-line editors.
19355    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19356        self.offset_content = offset_content;
19357        cx.notify();
19358    }
19359
19360    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19361        self.show_line_numbers = Some(show_line_numbers);
19362        cx.notify();
19363    }
19364
19365    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19366        self.disable_expand_excerpt_buttons = true;
19367        cx.notify();
19368    }
19369
19370    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19371        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19372        cx.notify();
19373    }
19374
19375    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19376        self.show_code_actions = Some(show_code_actions);
19377        cx.notify();
19378    }
19379
19380    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19381        self.show_runnables = Some(show_runnables);
19382        cx.notify();
19383    }
19384
19385    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19386        self.show_breakpoints = Some(show_breakpoints);
19387        cx.notify();
19388    }
19389
19390    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19391        if self.display_map.read(cx).masked != masked {
19392            self.display_map.update(cx, |map, _| map.masked = masked);
19393        }
19394        cx.notify()
19395    }
19396
19397    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19398        self.show_wrap_guides = Some(show_wrap_guides);
19399        cx.notify();
19400    }
19401
19402    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19403        self.show_indent_guides = Some(show_indent_guides);
19404        cx.notify();
19405    }
19406
19407    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19408        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19409            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19410                && let Some(dir) = file.abs_path(cx).parent()
19411            {
19412                return Some(dir.to_owned());
19413            }
19414        }
19415
19416        None
19417    }
19418
19419    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19420        self.active_excerpt(cx)?
19421            .1
19422            .read(cx)
19423            .file()
19424            .and_then(|f| f.as_local())
19425    }
19426
19427    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19428        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19429            let buffer = buffer.read(cx);
19430            if let Some(project_path) = buffer.project_path(cx) {
19431                let project = self.project()?.read(cx);
19432                project.absolute_path(&project_path, cx)
19433            } else {
19434                buffer
19435                    .file()
19436                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19437            }
19438        })
19439    }
19440
19441    pub fn reveal_in_finder(
19442        &mut self,
19443        _: &RevealInFileManager,
19444        _window: &mut Window,
19445        cx: &mut Context<Self>,
19446    ) {
19447        if let Some(target) = self.target_file(cx) {
19448            cx.reveal_path(&target.abs_path(cx));
19449        }
19450    }
19451
19452    pub fn copy_path(
19453        &mut self,
19454        _: &zed_actions::workspace::CopyPath,
19455        _window: &mut Window,
19456        cx: &mut Context<Self>,
19457    ) {
19458        if let Some(path) = self.target_file_abs_path(cx)
19459            && let Some(path) = path.to_str()
19460        {
19461            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19462        } else {
19463            cx.propagate();
19464        }
19465    }
19466
19467    pub fn copy_relative_path(
19468        &mut self,
19469        _: &zed_actions::workspace::CopyRelativePath,
19470        _window: &mut Window,
19471        cx: &mut Context<Self>,
19472    ) {
19473        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19474            let project = self.project()?.read(cx);
19475            let path = buffer.read(cx).file()?.path();
19476            let path = path.display(project.path_style(cx));
19477            Some(path)
19478        }) {
19479            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19480        } else {
19481            cx.propagate();
19482        }
19483    }
19484
19485    /// Returns the project path for the editor's buffer, if any buffer is
19486    /// opened in the editor.
19487    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19488        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19489            buffer.read(cx).project_path(cx)
19490        } else {
19491            None
19492        }
19493    }
19494
19495    // Returns true if the editor handled a go-to-line request
19496    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19497        maybe!({
19498            let breakpoint_store = self.breakpoint_store.as_ref()?;
19499
19500            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19501            else {
19502                self.clear_row_highlights::<ActiveDebugLine>();
19503                return None;
19504            };
19505
19506            let position = active_stack_frame.position;
19507            let buffer_id = position.buffer_id?;
19508            let snapshot = self
19509                .project
19510                .as_ref()?
19511                .read(cx)
19512                .buffer_for_id(buffer_id, cx)?
19513                .read(cx)
19514                .snapshot();
19515
19516            let mut handled = false;
19517            for (id, ExcerptRange { context, .. }) in
19518                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19519            {
19520                if context.start.cmp(&position, &snapshot).is_ge()
19521                    || context.end.cmp(&position, &snapshot).is_lt()
19522                {
19523                    continue;
19524                }
19525                let snapshot = self.buffer.read(cx).snapshot(cx);
19526                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19527
19528                handled = true;
19529                self.clear_row_highlights::<ActiveDebugLine>();
19530
19531                self.go_to_line::<ActiveDebugLine>(
19532                    multibuffer_anchor,
19533                    Some(cx.theme().colors().editor_debugger_active_line_background),
19534                    window,
19535                    cx,
19536                );
19537
19538                cx.notify();
19539            }
19540
19541            handled.then_some(())
19542        })
19543        .is_some()
19544    }
19545
19546    pub fn copy_file_name_without_extension(
19547        &mut self,
19548        _: &CopyFileNameWithoutExtension,
19549        _: &mut Window,
19550        cx: &mut Context<Self>,
19551    ) {
19552        if let Some(file) = self.target_file(cx)
19553            && let Some(file_stem) = file.path().file_stem()
19554        {
19555            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19556        }
19557    }
19558
19559    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19560        if let Some(file) = self.target_file(cx)
19561            && let Some(name) = file.path().file_name()
19562        {
19563            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19564        }
19565    }
19566
19567    pub fn toggle_git_blame(
19568        &mut self,
19569        _: &::git::Blame,
19570        window: &mut Window,
19571        cx: &mut Context<Self>,
19572    ) {
19573        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19574
19575        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19576            self.start_git_blame(true, window, cx);
19577        }
19578
19579        cx.notify();
19580    }
19581
19582    pub fn toggle_git_blame_inline(
19583        &mut self,
19584        _: &ToggleGitBlameInline,
19585        window: &mut Window,
19586        cx: &mut Context<Self>,
19587    ) {
19588        self.toggle_git_blame_inline_internal(true, window, cx);
19589        cx.notify();
19590    }
19591
19592    pub fn open_git_blame_commit(
19593        &mut self,
19594        _: &OpenGitBlameCommit,
19595        window: &mut Window,
19596        cx: &mut Context<Self>,
19597    ) {
19598        self.open_git_blame_commit_internal(window, cx);
19599    }
19600
19601    fn open_git_blame_commit_internal(
19602        &mut self,
19603        window: &mut Window,
19604        cx: &mut Context<Self>,
19605    ) -> Option<()> {
19606        let blame = self.blame.as_ref()?;
19607        let snapshot = self.snapshot(window, cx);
19608        let cursor = self.selections.newest::<Point>(cx).head();
19609        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19610        let (_, blame_entry) = blame
19611            .update(cx, |blame, cx| {
19612                blame
19613                    .blame_for_rows(
19614                        &[RowInfo {
19615                            buffer_id: Some(buffer.remote_id()),
19616                            buffer_row: Some(point.row),
19617                            ..Default::default()
19618                        }],
19619                        cx,
19620                    )
19621                    .next()
19622            })
19623            .flatten()?;
19624        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19625        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19626        let workspace = self.workspace()?.downgrade();
19627        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19628        None
19629    }
19630
19631    pub fn git_blame_inline_enabled(&self) -> bool {
19632        self.git_blame_inline_enabled
19633    }
19634
19635    pub fn toggle_selection_menu(
19636        &mut self,
19637        _: &ToggleSelectionMenu,
19638        _: &mut Window,
19639        cx: &mut Context<Self>,
19640    ) {
19641        self.show_selection_menu = self
19642            .show_selection_menu
19643            .map(|show_selections_menu| !show_selections_menu)
19644            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19645
19646        cx.notify();
19647    }
19648
19649    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19650        self.show_selection_menu
19651            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19652    }
19653
19654    fn start_git_blame(
19655        &mut self,
19656        user_triggered: bool,
19657        window: &mut Window,
19658        cx: &mut Context<Self>,
19659    ) {
19660        if let Some(project) = self.project() {
19661            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19662                && buffer.read(cx).file().is_none()
19663            {
19664                return;
19665            }
19666
19667            let focused = self.focus_handle(cx).contains_focused(window, cx);
19668
19669            let project = project.clone();
19670            let blame = cx
19671                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19672            self.blame_subscription =
19673                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19674            self.blame = Some(blame);
19675        }
19676    }
19677
19678    fn toggle_git_blame_inline_internal(
19679        &mut self,
19680        user_triggered: bool,
19681        window: &mut Window,
19682        cx: &mut Context<Self>,
19683    ) {
19684        if self.git_blame_inline_enabled {
19685            self.git_blame_inline_enabled = false;
19686            self.show_git_blame_inline = false;
19687            self.show_git_blame_inline_delay_task.take();
19688        } else {
19689            self.git_blame_inline_enabled = true;
19690            self.start_git_blame_inline(user_triggered, window, cx);
19691        }
19692
19693        cx.notify();
19694    }
19695
19696    fn start_git_blame_inline(
19697        &mut self,
19698        user_triggered: bool,
19699        window: &mut Window,
19700        cx: &mut Context<Self>,
19701    ) {
19702        self.start_git_blame(user_triggered, window, cx);
19703
19704        if ProjectSettings::get_global(cx)
19705            .git
19706            .inline_blame_delay()
19707            .is_some()
19708        {
19709            self.start_inline_blame_timer(window, cx);
19710        } else {
19711            self.show_git_blame_inline = true
19712        }
19713    }
19714
19715    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19716        self.blame.as_ref()
19717    }
19718
19719    pub fn show_git_blame_gutter(&self) -> bool {
19720        self.show_git_blame_gutter
19721    }
19722
19723    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19724        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19725    }
19726
19727    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19728        self.show_git_blame_inline
19729            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19730            && !self.newest_selection_head_on_empty_line(cx)
19731            && self.has_blame_entries(cx)
19732    }
19733
19734    fn has_blame_entries(&self, cx: &App) -> bool {
19735        self.blame()
19736            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19737    }
19738
19739    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19740        let cursor_anchor = self.selections.newest_anchor().head();
19741
19742        let snapshot = self.buffer.read(cx).snapshot(cx);
19743        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19744
19745        snapshot.line_len(buffer_row) == 0
19746    }
19747
19748    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19749        let buffer_and_selection = maybe!({
19750            let selection = self.selections.newest::<Point>(cx);
19751            let selection_range = selection.range();
19752
19753            let multi_buffer = self.buffer().read(cx);
19754            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19755            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19756
19757            let (buffer, range, _) = if selection.reversed {
19758                buffer_ranges.first()
19759            } else {
19760                buffer_ranges.last()
19761            }?;
19762
19763            let selection = text::ToPoint::to_point(&range.start, buffer).row
19764                ..text::ToPoint::to_point(&range.end, buffer).row;
19765            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19766        });
19767
19768        let Some((buffer, selection)) = buffer_and_selection else {
19769            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19770        };
19771
19772        let Some(project) = self.project() else {
19773            return Task::ready(Err(anyhow!("editor does not have project")));
19774        };
19775
19776        project.update(cx, |project, cx| {
19777            project.get_permalink_to_line(&buffer, selection, cx)
19778        })
19779    }
19780
19781    pub fn copy_permalink_to_line(
19782        &mut self,
19783        _: &CopyPermalinkToLine,
19784        window: &mut Window,
19785        cx: &mut Context<Self>,
19786    ) {
19787        let permalink_task = self.get_permalink_to_line(cx);
19788        let workspace = self.workspace();
19789
19790        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19791            Ok(permalink) => {
19792                cx.update(|_, cx| {
19793                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19794                })
19795                .ok();
19796            }
19797            Err(err) => {
19798                let message = format!("Failed to copy permalink: {err}");
19799
19800                anyhow::Result::<()>::Err(err).log_err();
19801
19802                if let Some(workspace) = workspace {
19803                    workspace
19804                        .update_in(cx, |workspace, _, cx| {
19805                            struct CopyPermalinkToLine;
19806
19807                            workspace.show_toast(
19808                                Toast::new(
19809                                    NotificationId::unique::<CopyPermalinkToLine>(),
19810                                    message,
19811                                ),
19812                                cx,
19813                            )
19814                        })
19815                        .ok();
19816                }
19817            }
19818        })
19819        .detach();
19820    }
19821
19822    pub fn copy_file_location(
19823        &mut self,
19824        _: &CopyFileLocation,
19825        _: &mut Window,
19826        cx: &mut Context<Self>,
19827    ) {
19828        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19829        if let Some(file) = self.target_file(cx) {
19830            let path = file.path().display(file.path_style(cx));
19831            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19832        }
19833    }
19834
19835    pub fn open_permalink_to_line(
19836        &mut self,
19837        _: &OpenPermalinkToLine,
19838        window: &mut Window,
19839        cx: &mut Context<Self>,
19840    ) {
19841        let permalink_task = self.get_permalink_to_line(cx);
19842        let workspace = self.workspace();
19843
19844        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19845            Ok(permalink) => {
19846                cx.update(|_, cx| {
19847                    cx.open_url(permalink.as_ref());
19848                })
19849                .ok();
19850            }
19851            Err(err) => {
19852                let message = format!("Failed to open permalink: {err}");
19853
19854                anyhow::Result::<()>::Err(err).log_err();
19855
19856                if let Some(workspace) = workspace {
19857                    workspace
19858                        .update(cx, |workspace, cx| {
19859                            struct OpenPermalinkToLine;
19860
19861                            workspace.show_toast(
19862                                Toast::new(
19863                                    NotificationId::unique::<OpenPermalinkToLine>(),
19864                                    message,
19865                                ),
19866                                cx,
19867                            )
19868                        })
19869                        .ok();
19870                }
19871            }
19872        })
19873        .detach();
19874    }
19875
19876    pub fn insert_uuid_v4(
19877        &mut self,
19878        _: &InsertUuidV4,
19879        window: &mut Window,
19880        cx: &mut Context<Self>,
19881    ) {
19882        self.insert_uuid(UuidVersion::V4, window, cx);
19883    }
19884
19885    pub fn insert_uuid_v7(
19886        &mut self,
19887        _: &InsertUuidV7,
19888        window: &mut Window,
19889        cx: &mut Context<Self>,
19890    ) {
19891        self.insert_uuid(UuidVersion::V7, window, cx);
19892    }
19893
19894    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19895        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19896        self.transact(window, cx, |this, window, cx| {
19897            let edits = this
19898                .selections
19899                .all::<Point>(cx)
19900                .into_iter()
19901                .map(|selection| {
19902                    let uuid = match version {
19903                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19904                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19905                    };
19906
19907                    (selection.range(), uuid.to_string())
19908                });
19909            this.edit(edits, cx);
19910            this.refresh_edit_prediction(true, false, window, cx);
19911        });
19912    }
19913
19914    pub fn open_selections_in_multibuffer(
19915        &mut self,
19916        _: &OpenSelectionsInMultibuffer,
19917        window: &mut Window,
19918        cx: &mut Context<Self>,
19919    ) {
19920        let multibuffer = self.buffer.read(cx);
19921
19922        let Some(buffer) = multibuffer.as_singleton() else {
19923            return;
19924        };
19925
19926        let Some(workspace) = self.workspace() else {
19927            return;
19928        };
19929
19930        let title = multibuffer.title(cx).to_string();
19931
19932        let locations = self
19933            .selections
19934            .all_anchors(cx)
19935            .iter()
19936            .map(|selection| {
19937                (
19938                    buffer.clone(),
19939                    (selection.start.text_anchor..selection.end.text_anchor)
19940                        .to_point(buffer.read(cx)),
19941                )
19942            })
19943            .into_group_map();
19944
19945        cx.spawn_in(window, async move |_, cx| {
19946            workspace.update_in(cx, |workspace, window, cx| {
19947                Self::open_locations_in_multibuffer(
19948                    workspace,
19949                    locations,
19950                    format!("Selections for '{title}'"),
19951                    false,
19952                    MultibufferSelectionMode::All,
19953                    window,
19954                    cx,
19955                );
19956            })
19957        })
19958        .detach();
19959    }
19960
19961    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19962    /// last highlight added will be used.
19963    ///
19964    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19965    pub fn highlight_rows<T: 'static>(
19966        &mut self,
19967        range: Range<Anchor>,
19968        color: Hsla,
19969        options: RowHighlightOptions,
19970        cx: &mut Context<Self>,
19971    ) {
19972        let snapshot = self.buffer().read(cx).snapshot(cx);
19973        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19974        let ix = row_highlights.binary_search_by(|highlight| {
19975            Ordering::Equal
19976                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19977                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19978        });
19979
19980        if let Err(mut ix) = ix {
19981            let index = post_inc(&mut self.highlight_order);
19982
19983            // If this range intersects with the preceding highlight, then merge it with
19984            // the preceding highlight. Otherwise insert a new highlight.
19985            let mut merged = false;
19986            if ix > 0 {
19987                let prev_highlight = &mut row_highlights[ix - 1];
19988                if prev_highlight
19989                    .range
19990                    .end
19991                    .cmp(&range.start, &snapshot)
19992                    .is_ge()
19993                {
19994                    ix -= 1;
19995                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19996                        prev_highlight.range.end = range.end;
19997                    }
19998                    merged = true;
19999                    prev_highlight.index = index;
20000                    prev_highlight.color = color;
20001                    prev_highlight.options = options;
20002                }
20003            }
20004
20005            if !merged {
20006                row_highlights.insert(
20007                    ix,
20008                    RowHighlight {
20009                        range,
20010                        index,
20011                        color,
20012                        options,
20013                        type_id: TypeId::of::<T>(),
20014                    },
20015                );
20016            }
20017
20018            // If any of the following highlights intersect with this one, merge them.
20019            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20020                let highlight = &row_highlights[ix];
20021                if next_highlight
20022                    .range
20023                    .start
20024                    .cmp(&highlight.range.end, &snapshot)
20025                    .is_le()
20026                {
20027                    if next_highlight
20028                        .range
20029                        .end
20030                        .cmp(&highlight.range.end, &snapshot)
20031                        .is_gt()
20032                    {
20033                        row_highlights[ix].range.end = next_highlight.range.end;
20034                    }
20035                    row_highlights.remove(ix + 1);
20036                } else {
20037                    break;
20038                }
20039            }
20040        }
20041    }
20042
20043    /// Remove any highlighted row ranges of the given type that intersect the
20044    /// given ranges.
20045    pub fn remove_highlighted_rows<T: 'static>(
20046        &mut self,
20047        ranges_to_remove: Vec<Range<Anchor>>,
20048        cx: &mut Context<Self>,
20049    ) {
20050        let snapshot = self.buffer().read(cx).snapshot(cx);
20051        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20052        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20053        row_highlights.retain(|highlight| {
20054            while let Some(range_to_remove) = ranges_to_remove.peek() {
20055                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20056                    Ordering::Less | Ordering::Equal => {
20057                        ranges_to_remove.next();
20058                    }
20059                    Ordering::Greater => {
20060                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20061                            Ordering::Less | Ordering::Equal => {
20062                                return false;
20063                            }
20064                            Ordering::Greater => break,
20065                        }
20066                    }
20067                }
20068            }
20069
20070            true
20071        })
20072    }
20073
20074    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20075    pub fn clear_row_highlights<T: 'static>(&mut self) {
20076        self.highlighted_rows.remove(&TypeId::of::<T>());
20077    }
20078
20079    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20080    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20081        self.highlighted_rows
20082            .get(&TypeId::of::<T>())
20083            .map_or(&[] as &[_], |vec| vec.as_slice())
20084            .iter()
20085            .map(|highlight| (highlight.range.clone(), highlight.color))
20086    }
20087
20088    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20089    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20090    /// Allows to ignore certain kinds of highlights.
20091    pub fn highlighted_display_rows(
20092        &self,
20093        window: &mut Window,
20094        cx: &mut App,
20095    ) -> BTreeMap<DisplayRow, LineHighlight> {
20096        let snapshot = self.snapshot(window, cx);
20097        let mut used_highlight_orders = HashMap::default();
20098        self.highlighted_rows
20099            .iter()
20100            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20101            .fold(
20102                BTreeMap::<DisplayRow, LineHighlight>::new(),
20103                |mut unique_rows, highlight| {
20104                    let start = highlight.range.start.to_display_point(&snapshot);
20105                    let end = highlight.range.end.to_display_point(&snapshot);
20106                    let start_row = start.row().0;
20107                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20108                        && end.column() == 0
20109                    {
20110                        end.row().0.saturating_sub(1)
20111                    } else {
20112                        end.row().0
20113                    };
20114                    for row in start_row..=end_row {
20115                        let used_index =
20116                            used_highlight_orders.entry(row).or_insert(highlight.index);
20117                        if highlight.index >= *used_index {
20118                            *used_index = highlight.index;
20119                            unique_rows.insert(
20120                                DisplayRow(row),
20121                                LineHighlight {
20122                                    include_gutter: highlight.options.include_gutter,
20123                                    border: None,
20124                                    background: highlight.color.into(),
20125                                    type_id: Some(highlight.type_id),
20126                                },
20127                            );
20128                        }
20129                    }
20130                    unique_rows
20131                },
20132            )
20133    }
20134
20135    pub fn highlighted_display_row_for_autoscroll(
20136        &self,
20137        snapshot: &DisplaySnapshot,
20138    ) -> Option<DisplayRow> {
20139        self.highlighted_rows
20140            .values()
20141            .flat_map(|highlighted_rows| highlighted_rows.iter())
20142            .filter_map(|highlight| {
20143                if highlight.options.autoscroll {
20144                    Some(highlight.range.start.to_display_point(snapshot).row())
20145                } else {
20146                    None
20147                }
20148            })
20149            .min()
20150    }
20151
20152    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20153        self.highlight_background::<SearchWithinRange>(
20154            ranges,
20155            |colors| colors.colors().editor_document_highlight_read_background,
20156            cx,
20157        )
20158    }
20159
20160    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20161        self.breadcrumb_header = Some(new_header);
20162    }
20163
20164    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20165        self.clear_background_highlights::<SearchWithinRange>(cx);
20166    }
20167
20168    pub fn highlight_background<T: 'static>(
20169        &mut self,
20170        ranges: &[Range<Anchor>],
20171        color_fetcher: fn(&Theme) -> Hsla,
20172        cx: &mut Context<Self>,
20173    ) {
20174        self.background_highlights.insert(
20175            HighlightKey::Type(TypeId::of::<T>()),
20176            (color_fetcher, Arc::from(ranges)),
20177        );
20178        self.scrollbar_marker_state.dirty = true;
20179        cx.notify();
20180    }
20181
20182    pub fn highlight_background_key<T: 'static>(
20183        &mut self,
20184        key: usize,
20185        ranges: &[Range<Anchor>],
20186        color_fetcher: fn(&Theme) -> Hsla,
20187        cx: &mut Context<Self>,
20188    ) {
20189        self.background_highlights.insert(
20190            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20191            (color_fetcher, Arc::from(ranges)),
20192        );
20193        self.scrollbar_marker_state.dirty = true;
20194        cx.notify();
20195    }
20196
20197    pub fn clear_background_highlights<T: 'static>(
20198        &mut self,
20199        cx: &mut Context<Self>,
20200    ) -> Option<BackgroundHighlight> {
20201        let text_highlights = self
20202            .background_highlights
20203            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20204        if !text_highlights.1.is_empty() {
20205            self.scrollbar_marker_state.dirty = true;
20206            cx.notify();
20207        }
20208        Some(text_highlights)
20209    }
20210
20211    pub fn highlight_gutter<T: 'static>(
20212        &mut self,
20213        ranges: impl Into<Vec<Range<Anchor>>>,
20214        color_fetcher: fn(&App) -> Hsla,
20215        cx: &mut Context<Self>,
20216    ) {
20217        self.gutter_highlights
20218            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20219        cx.notify();
20220    }
20221
20222    pub fn clear_gutter_highlights<T: 'static>(
20223        &mut self,
20224        cx: &mut Context<Self>,
20225    ) -> Option<GutterHighlight> {
20226        cx.notify();
20227        self.gutter_highlights.remove(&TypeId::of::<T>())
20228    }
20229
20230    pub fn insert_gutter_highlight<T: 'static>(
20231        &mut self,
20232        range: Range<Anchor>,
20233        color_fetcher: fn(&App) -> Hsla,
20234        cx: &mut Context<Self>,
20235    ) {
20236        let snapshot = self.buffer().read(cx).snapshot(cx);
20237        let mut highlights = self
20238            .gutter_highlights
20239            .remove(&TypeId::of::<T>())
20240            .map(|(_, highlights)| highlights)
20241            .unwrap_or_default();
20242        let ix = highlights.binary_search_by(|highlight| {
20243            Ordering::Equal
20244                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20245                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20246        });
20247        if let Err(ix) = ix {
20248            highlights.insert(ix, range);
20249        }
20250        self.gutter_highlights
20251            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20252    }
20253
20254    pub fn remove_gutter_highlights<T: 'static>(
20255        &mut self,
20256        ranges_to_remove: Vec<Range<Anchor>>,
20257        cx: &mut Context<Self>,
20258    ) {
20259        let snapshot = self.buffer().read(cx).snapshot(cx);
20260        let Some((color_fetcher, mut gutter_highlights)) =
20261            self.gutter_highlights.remove(&TypeId::of::<T>())
20262        else {
20263            return;
20264        };
20265        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20266        gutter_highlights.retain(|highlight| {
20267            while let Some(range_to_remove) = ranges_to_remove.peek() {
20268                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20269                    Ordering::Less | Ordering::Equal => {
20270                        ranges_to_remove.next();
20271                    }
20272                    Ordering::Greater => {
20273                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20274                            Ordering::Less | Ordering::Equal => {
20275                                return false;
20276                            }
20277                            Ordering::Greater => break,
20278                        }
20279                    }
20280                }
20281            }
20282
20283            true
20284        });
20285        self.gutter_highlights
20286            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20287    }
20288
20289    #[cfg(feature = "test-support")]
20290    pub fn all_text_highlights(
20291        &self,
20292        window: &mut Window,
20293        cx: &mut Context<Self>,
20294    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20295        let snapshot = self.snapshot(window, cx);
20296        self.display_map.update(cx, |display_map, _| {
20297            display_map
20298                .all_text_highlights()
20299                .map(|highlight| {
20300                    let (style, ranges) = highlight.as_ref();
20301                    (
20302                        *style,
20303                        ranges
20304                            .iter()
20305                            .map(|range| range.clone().to_display_points(&snapshot))
20306                            .collect(),
20307                    )
20308                })
20309                .collect()
20310        })
20311    }
20312
20313    #[cfg(feature = "test-support")]
20314    pub fn all_text_background_highlights(
20315        &self,
20316        window: &mut Window,
20317        cx: &mut Context<Self>,
20318    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20319        let snapshot = self.snapshot(window, cx);
20320        let buffer = &snapshot.buffer_snapshot();
20321        let start = buffer.anchor_before(0);
20322        let end = buffer.anchor_after(buffer.len());
20323        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20324    }
20325
20326    #[cfg(any(test, feature = "test-support"))]
20327    pub fn sorted_background_highlights_in_range(
20328        &self,
20329        search_range: Range<Anchor>,
20330        display_snapshot: &DisplaySnapshot,
20331        theme: &Theme,
20332    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20333        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20334        res.sort_by(|a, b| {
20335            a.0.start
20336                .cmp(&b.0.start)
20337                .then_with(|| a.0.end.cmp(&b.0.end))
20338                .then_with(|| a.1.cmp(&b.1))
20339        });
20340        res
20341    }
20342
20343    #[cfg(feature = "test-support")]
20344    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20345        let snapshot = self.buffer().read(cx).snapshot(cx);
20346
20347        let highlights = self
20348            .background_highlights
20349            .get(&HighlightKey::Type(TypeId::of::<
20350                items::BufferSearchHighlights,
20351            >()));
20352
20353        if let Some((_color, ranges)) = highlights {
20354            ranges
20355                .iter()
20356                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20357                .collect_vec()
20358        } else {
20359            vec![]
20360        }
20361    }
20362
20363    fn document_highlights_for_position<'a>(
20364        &'a self,
20365        position: Anchor,
20366        buffer: &'a MultiBufferSnapshot,
20367    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20368        let read_highlights = self
20369            .background_highlights
20370            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20371            .map(|h| &h.1);
20372        let write_highlights = self
20373            .background_highlights
20374            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20375            .map(|h| &h.1);
20376        let left_position = position.bias_left(buffer);
20377        let right_position = position.bias_right(buffer);
20378        read_highlights
20379            .into_iter()
20380            .chain(write_highlights)
20381            .flat_map(move |ranges| {
20382                let start_ix = match ranges.binary_search_by(|probe| {
20383                    let cmp = probe.end.cmp(&left_position, buffer);
20384                    if cmp.is_ge() {
20385                        Ordering::Greater
20386                    } else {
20387                        Ordering::Less
20388                    }
20389                }) {
20390                    Ok(i) | Err(i) => i,
20391                };
20392
20393                ranges[start_ix..]
20394                    .iter()
20395                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20396            })
20397    }
20398
20399    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20400        self.background_highlights
20401            .get(&HighlightKey::Type(TypeId::of::<T>()))
20402            .is_some_and(|(_, highlights)| !highlights.is_empty())
20403    }
20404
20405    /// Returns all background highlights for a given range.
20406    ///
20407    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20408    pub fn background_highlights_in_range(
20409        &self,
20410        search_range: Range<Anchor>,
20411        display_snapshot: &DisplaySnapshot,
20412        theme: &Theme,
20413    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20414        let mut results = Vec::new();
20415        for (color_fetcher, ranges) in self.background_highlights.values() {
20416            let color = color_fetcher(theme);
20417            let start_ix = match ranges.binary_search_by(|probe| {
20418                let cmp = probe
20419                    .end
20420                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20421                if cmp.is_gt() {
20422                    Ordering::Greater
20423                } else {
20424                    Ordering::Less
20425                }
20426            }) {
20427                Ok(i) | Err(i) => i,
20428            };
20429            for range in &ranges[start_ix..] {
20430                if range
20431                    .start
20432                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20433                    .is_ge()
20434                {
20435                    break;
20436                }
20437
20438                let start = range.start.to_display_point(display_snapshot);
20439                let end = range.end.to_display_point(display_snapshot);
20440                results.push((start..end, color))
20441            }
20442        }
20443        results
20444    }
20445
20446    pub fn gutter_highlights_in_range(
20447        &self,
20448        search_range: Range<Anchor>,
20449        display_snapshot: &DisplaySnapshot,
20450        cx: &App,
20451    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20452        let mut results = Vec::new();
20453        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20454            let color = color_fetcher(cx);
20455            let start_ix = match ranges.binary_search_by(|probe| {
20456                let cmp = probe
20457                    .end
20458                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20459                if cmp.is_gt() {
20460                    Ordering::Greater
20461                } else {
20462                    Ordering::Less
20463                }
20464            }) {
20465                Ok(i) | Err(i) => i,
20466            };
20467            for range in &ranges[start_ix..] {
20468                if range
20469                    .start
20470                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20471                    .is_ge()
20472                {
20473                    break;
20474                }
20475
20476                let start = range.start.to_display_point(display_snapshot);
20477                let end = range.end.to_display_point(display_snapshot);
20478                results.push((start..end, color))
20479            }
20480        }
20481        results
20482    }
20483
20484    /// Get the text ranges corresponding to the redaction query
20485    pub fn redacted_ranges(
20486        &self,
20487        search_range: Range<Anchor>,
20488        display_snapshot: &DisplaySnapshot,
20489        cx: &App,
20490    ) -> Vec<Range<DisplayPoint>> {
20491        display_snapshot
20492            .buffer_snapshot()
20493            .redacted_ranges(search_range, |file| {
20494                if let Some(file) = file {
20495                    file.is_private()
20496                        && EditorSettings::get(
20497                            Some(SettingsLocation {
20498                                worktree_id: file.worktree_id(cx),
20499                                path: file.path().as_ref(),
20500                            }),
20501                            cx,
20502                        )
20503                        .redact_private_values
20504                } else {
20505                    false
20506                }
20507            })
20508            .map(|range| {
20509                range.start.to_display_point(display_snapshot)
20510                    ..range.end.to_display_point(display_snapshot)
20511            })
20512            .collect()
20513    }
20514
20515    pub fn highlight_text_key<T: 'static>(
20516        &mut self,
20517        key: usize,
20518        ranges: Vec<Range<Anchor>>,
20519        style: HighlightStyle,
20520        cx: &mut Context<Self>,
20521    ) {
20522        self.display_map.update(cx, |map, _| {
20523            map.highlight_text(
20524                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20525                ranges,
20526                style,
20527            );
20528        });
20529        cx.notify();
20530    }
20531
20532    pub fn highlight_text<T: 'static>(
20533        &mut self,
20534        ranges: Vec<Range<Anchor>>,
20535        style: HighlightStyle,
20536        cx: &mut Context<Self>,
20537    ) {
20538        self.display_map.update(cx, |map, _| {
20539            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20540        });
20541        cx.notify();
20542    }
20543
20544    pub(crate) fn highlight_inlays<T: 'static>(
20545        &mut self,
20546        highlights: Vec<InlayHighlight>,
20547        style: HighlightStyle,
20548        cx: &mut Context<Self>,
20549    ) {
20550        self.display_map.update(cx, |map, _| {
20551            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20552        });
20553        cx.notify();
20554    }
20555
20556    pub fn text_highlights<'a, T: 'static>(
20557        &'a self,
20558        cx: &'a App,
20559    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20560        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20561    }
20562
20563    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20564        let cleared = self
20565            .display_map
20566            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20567        if cleared {
20568            cx.notify();
20569        }
20570    }
20571
20572    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20573        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20574            && self.focus_handle.is_focused(window)
20575    }
20576
20577    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20578        self.show_cursor_when_unfocused = is_enabled;
20579        cx.notify();
20580    }
20581
20582    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20583        cx.notify();
20584    }
20585
20586    fn on_debug_session_event(
20587        &mut self,
20588        _session: Entity<Session>,
20589        event: &SessionEvent,
20590        cx: &mut Context<Self>,
20591    ) {
20592        if let SessionEvent::InvalidateInlineValue = event {
20593            self.refresh_inline_values(cx);
20594        }
20595    }
20596
20597    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20598        let Some(project) = self.project.clone() else {
20599            return;
20600        };
20601
20602        if !self.inline_value_cache.enabled {
20603            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20604            self.splice_inlays(&inlays, Vec::new(), cx);
20605            return;
20606        }
20607
20608        let current_execution_position = self
20609            .highlighted_rows
20610            .get(&TypeId::of::<ActiveDebugLine>())
20611            .and_then(|lines| lines.last().map(|line| line.range.end));
20612
20613        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20614            let inline_values = editor
20615                .update(cx, |editor, cx| {
20616                    let Some(current_execution_position) = current_execution_position else {
20617                        return Some(Task::ready(Ok(Vec::new())));
20618                    };
20619
20620                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20621                        let snapshot = buffer.snapshot(cx);
20622
20623                        let excerpt = snapshot.excerpt_containing(
20624                            current_execution_position..current_execution_position,
20625                        )?;
20626
20627                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20628                    })?;
20629
20630                    let range =
20631                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20632
20633                    project.inline_values(buffer, range, cx)
20634                })
20635                .ok()
20636                .flatten()?
20637                .await
20638                .context("refreshing debugger inlays")
20639                .log_err()?;
20640
20641            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20642
20643            for (buffer_id, inline_value) in inline_values
20644                .into_iter()
20645                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20646            {
20647                buffer_inline_values
20648                    .entry(buffer_id)
20649                    .or_default()
20650                    .push(inline_value);
20651            }
20652
20653            editor
20654                .update(cx, |editor, cx| {
20655                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20656                    let mut new_inlays = Vec::default();
20657
20658                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20659                        let buffer_id = buffer_snapshot.remote_id();
20660                        buffer_inline_values
20661                            .get(&buffer_id)
20662                            .into_iter()
20663                            .flatten()
20664                            .for_each(|hint| {
20665                                let inlay = Inlay::debugger(
20666                                    post_inc(&mut editor.next_inlay_id),
20667                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20668                                    hint.text(),
20669                                );
20670                                if !inlay.text().chars().contains(&'\n') {
20671                                    new_inlays.push(inlay);
20672                                }
20673                            });
20674                    }
20675
20676                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20677                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20678
20679                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20680                })
20681                .ok()?;
20682            Some(())
20683        });
20684    }
20685
20686    fn on_buffer_event(
20687        &mut self,
20688        multibuffer: &Entity<MultiBuffer>,
20689        event: &multi_buffer::Event,
20690        window: &mut Window,
20691        cx: &mut Context<Self>,
20692    ) {
20693        match event {
20694            multi_buffer::Event::Edited {
20695                singleton_buffer_edited,
20696                edited_buffer,
20697            } => {
20698                self.scrollbar_marker_state.dirty = true;
20699                self.active_indent_guides_state.dirty = true;
20700                self.refresh_active_diagnostics(cx);
20701                self.refresh_code_actions(window, cx);
20702                self.refresh_selected_text_highlights(true, window, cx);
20703                self.refresh_single_line_folds(window, cx);
20704                refresh_matching_bracket_highlights(self, window, cx);
20705                if self.has_active_edit_prediction() {
20706                    self.update_visible_edit_prediction(window, cx);
20707                }
20708                if let Some(project) = self.project.as_ref()
20709                    && let Some(edited_buffer) = edited_buffer
20710                {
20711                    project.update(cx, |project, cx| {
20712                        self.registered_buffers
20713                            .entry(edited_buffer.read(cx).remote_id())
20714                            .or_insert_with(|| {
20715                                project.register_buffer_with_language_servers(edited_buffer, cx)
20716                            });
20717                    });
20718                }
20719                cx.emit(EditorEvent::BufferEdited);
20720                cx.emit(SearchEvent::MatchesInvalidated);
20721
20722                if let Some(buffer) = edited_buffer {
20723                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20724                }
20725
20726                if *singleton_buffer_edited {
20727                    if let Some(buffer) = edited_buffer
20728                        && buffer.read(cx).file().is_none()
20729                    {
20730                        cx.emit(EditorEvent::TitleChanged);
20731                    }
20732                    if let Some(project) = &self.project {
20733                        #[allow(clippy::mutable_key_type)]
20734                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20735                            multibuffer
20736                                .all_buffers()
20737                                .into_iter()
20738                                .filter_map(|buffer| {
20739                                    buffer.update(cx, |buffer, cx| {
20740                                        let language = buffer.language()?;
20741                                        let should_discard = project.update(cx, |project, cx| {
20742                                            project.is_local()
20743                                                && !project.has_language_servers_for(buffer, cx)
20744                                        });
20745                                        should_discard.not().then_some(language.clone())
20746                                    })
20747                                })
20748                                .collect::<HashSet<_>>()
20749                        });
20750                        if !languages_affected.is_empty() {
20751                            self.refresh_inlay_hints(
20752                                InlayHintRefreshReason::BufferEdited(languages_affected),
20753                                cx,
20754                            );
20755                        }
20756                    }
20757                }
20758
20759                let Some(project) = &self.project else { return };
20760                let (telemetry, is_via_ssh) = {
20761                    let project = project.read(cx);
20762                    let telemetry = project.client().telemetry().clone();
20763                    let is_via_ssh = project.is_via_remote_server();
20764                    (telemetry, is_via_ssh)
20765                };
20766                refresh_linked_ranges(self, window, cx);
20767                telemetry.log_edit_event("editor", is_via_ssh);
20768            }
20769            multi_buffer::Event::ExcerptsAdded {
20770                buffer,
20771                predecessor,
20772                excerpts,
20773            } => {
20774                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20775                let buffer_id = buffer.read(cx).remote_id();
20776                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20777                    && let Some(project) = &self.project
20778                {
20779                    update_uncommitted_diff_for_buffer(
20780                        cx.entity(),
20781                        project,
20782                        [buffer.clone()],
20783                        self.buffer.clone(),
20784                        cx,
20785                    )
20786                    .detach();
20787                }
20788                if self.active_diagnostics != ActiveDiagnostic::All {
20789                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20790                }
20791                cx.emit(EditorEvent::ExcerptsAdded {
20792                    buffer: buffer.clone(),
20793                    predecessor: *predecessor,
20794                    excerpts: excerpts.clone(),
20795                });
20796                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20797            }
20798            multi_buffer::Event::ExcerptsRemoved {
20799                ids,
20800                removed_buffer_ids,
20801            } => {
20802                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20803                let buffer = self.buffer.read(cx);
20804                self.registered_buffers
20805                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20806                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20807                cx.emit(EditorEvent::ExcerptsRemoved {
20808                    ids: ids.clone(),
20809                    removed_buffer_ids: removed_buffer_ids.clone(),
20810                });
20811            }
20812            multi_buffer::Event::ExcerptsEdited {
20813                excerpt_ids,
20814                buffer_ids,
20815            } => {
20816                self.display_map.update(cx, |map, cx| {
20817                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20818                });
20819                cx.emit(EditorEvent::ExcerptsEdited {
20820                    ids: excerpt_ids.clone(),
20821                });
20822            }
20823            multi_buffer::Event::ExcerptsExpanded { ids } => {
20824                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20825                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20826            }
20827            multi_buffer::Event::Reparsed(buffer_id) => {
20828                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20829                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20830
20831                cx.emit(EditorEvent::Reparsed(*buffer_id));
20832            }
20833            multi_buffer::Event::DiffHunksToggled => {
20834                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20835            }
20836            multi_buffer::Event::LanguageChanged(buffer_id) => {
20837                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20838                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20839                cx.emit(EditorEvent::Reparsed(*buffer_id));
20840                cx.notify();
20841            }
20842            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20843            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20844            multi_buffer::Event::FileHandleChanged
20845            | multi_buffer::Event::Reloaded
20846            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20847            multi_buffer::Event::DiagnosticsUpdated => {
20848                self.update_diagnostics_state(window, cx);
20849            }
20850            _ => {}
20851        };
20852    }
20853
20854    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20855        if !self.diagnostics_enabled() {
20856            return;
20857        }
20858        self.refresh_active_diagnostics(cx);
20859        self.refresh_inline_diagnostics(true, window, cx);
20860        self.scrollbar_marker_state.dirty = true;
20861        cx.notify();
20862    }
20863
20864    pub fn start_temporary_diff_override(&mut self) {
20865        self.load_diff_task.take();
20866        self.temporary_diff_override = true;
20867    }
20868
20869    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20870        self.temporary_diff_override = false;
20871        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20872        self.buffer.update(cx, |buffer, cx| {
20873            buffer.set_all_diff_hunks_collapsed(cx);
20874        });
20875
20876        if let Some(project) = self.project.clone() {
20877            self.load_diff_task = Some(
20878                update_uncommitted_diff_for_buffer(
20879                    cx.entity(),
20880                    &project,
20881                    self.buffer.read(cx).all_buffers(),
20882                    self.buffer.clone(),
20883                    cx,
20884                )
20885                .shared(),
20886            );
20887        }
20888    }
20889
20890    fn on_display_map_changed(
20891        &mut self,
20892        _: Entity<DisplayMap>,
20893        _: &mut Window,
20894        cx: &mut Context<Self>,
20895    ) {
20896        cx.notify();
20897    }
20898
20899    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20900        if self.diagnostics_enabled() {
20901            let new_severity = EditorSettings::get_global(cx)
20902                .diagnostics_max_severity
20903                .unwrap_or(DiagnosticSeverity::Hint);
20904            self.set_max_diagnostics_severity(new_severity, cx);
20905        }
20906        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20907        self.update_edit_prediction_settings(cx);
20908        self.refresh_edit_prediction(true, false, window, cx);
20909        self.refresh_inline_values(cx);
20910        self.refresh_inlay_hints(
20911            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20912                self.selections.newest_anchor().head(),
20913                &self.buffer.read(cx).snapshot(cx),
20914                cx,
20915            )),
20916            cx,
20917        );
20918
20919        let old_cursor_shape = self.cursor_shape;
20920        let old_show_breadcrumbs = self.show_breadcrumbs;
20921
20922        {
20923            let editor_settings = EditorSettings::get_global(cx);
20924            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20925            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20926            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20927            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20928        }
20929
20930        if old_cursor_shape != self.cursor_shape {
20931            cx.emit(EditorEvent::CursorShapeChanged);
20932        }
20933
20934        if old_show_breadcrumbs != self.show_breadcrumbs {
20935            cx.emit(EditorEvent::BreadcrumbsChanged);
20936        }
20937
20938        let project_settings = ProjectSettings::get_global(cx);
20939        self.serialize_dirty_buffers =
20940            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20941
20942        if self.mode.is_full() {
20943            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20944            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20945            if self.show_inline_diagnostics != show_inline_diagnostics {
20946                self.show_inline_diagnostics = show_inline_diagnostics;
20947                self.refresh_inline_diagnostics(false, window, cx);
20948            }
20949
20950            if self.git_blame_inline_enabled != inline_blame_enabled {
20951                self.toggle_git_blame_inline_internal(false, window, cx);
20952            }
20953
20954            let minimap_settings = EditorSettings::get_global(cx).minimap;
20955            if self.minimap_visibility != MinimapVisibility::Disabled {
20956                if self.minimap_visibility.settings_visibility()
20957                    != minimap_settings.minimap_enabled()
20958                {
20959                    self.set_minimap_visibility(
20960                        MinimapVisibility::for_mode(self.mode(), cx),
20961                        window,
20962                        cx,
20963                    );
20964                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20965                    minimap_entity.update(cx, |minimap_editor, cx| {
20966                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20967                    })
20968                }
20969            }
20970        }
20971
20972        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20973            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20974        }) {
20975            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20976                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20977            }
20978            self.refresh_colors(false, None, window, cx);
20979        }
20980
20981        cx.notify();
20982    }
20983
20984    pub fn set_searchable(&mut self, searchable: bool) {
20985        self.searchable = searchable;
20986    }
20987
20988    pub fn searchable(&self) -> bool {
20989        self.searchable
20990    }
20991
20992    fn open_proposed_changes_editor(
20993        &mut self,
20994        _: &OpenProposedChangesEditor,
20995        window: &mut Window,
20996        cx: &mut Context<Self>,
20997    ) {
20998        let Some(workspace) = self.workspace() else {
20999            cx.propagate();
21000            return;
21001        };
21002
21003        let selections = self.selections.all::<usize>(cx);
21004        let multi_buffer = self.buffer.read(cx);
21005        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21006        let mut new_selections_by_buffer = HashMap::default();
21007        for selection in selections {
21008            for (buffer, range, _) in
21009                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
21010            {
21011                let mut range = range.to_point(buffer);
21012                range.start.column = 0;
21013                range.end.column = buffer.line_len(range.end.row);
21014                new_selections_by_buffer
21015                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
21016                    .or_insert(Vec::new())
21017                    .push(range)
21018            }
21019        }
21020
21021        let proposed_changes_buffers = new_selections_by_buffer
21022            .into_iter()
21023            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
21024            .collect::<Vec<_>>();
21025        let proposed_changes_editor = cx.new(|cx| {
21026            ProposedChangesEditor::new(
21027                "Proposed changes",
21028                proposed_changes_buffers,
21029                self.project.clone(),
21030                window,
21031                cx,
21032            )
21033        });
21034
21035        window.defer(cx, move |window, cx| {
21036            workspace.update(cx, |workspace, cx| {
21037                workspace.active_pane().update(cx, |pane, cx| {
21038                    pane.add_item(
21039                        Box::new(proposed_changes_editor),
21040                        true,
21041                        true,
21042                        None,
21043                        window,
21044                        cx,
21045                    );
21046                });
21047            });
21048        });
21049    }
21050
21051    pub fn open_excerpts_in_split(
21052        &mut self,
21053        _: &OpenExcerptsSplit,
21054        window: &mut Window,
21055        cx: &mut Context<Self>,
21056    ) {
21057        self.open_excerpts_common(None, true, window, cx)
21058    }
21059
21060    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21061        self.open_excerpts_common(None, false, window, cx)
21062    }
21063
21064    fn open_excerpts_common(
21065        &mut self,
21066        jump_data: Option<JumpData>,
21067        split: bool,
21068        window: &mut Window,
21069        cx: &mut Context<Self>,
21070    ) {
21071        let Some(workspace) = self.workspace() else {
21072            cx.propagate();
21073            return;
21074        };
21075
21076        if self.buffer.read(cx).is_singleton() {
21077            cx.propagate();
21078            return;
21079        }
21080
21081        let mut new_selections_by_buffer = HashMap::default();
21082        match &jump_data {
21083            Some(JumpData::MultiBufferPoint {
21084                excerpt_id,
21085                position,
21086                anchor,
21087                line_offset_from_top,
21088            }) => {
21089                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21090                if let Some(buffer) = multi_buffer_snapshot
21091                    .buffer_id_for_excerpt(*excerpt_id)
21092                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21093                {
21094                    let buffer_snapshot = buffer.read(cx).snapshot();
21095                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21096                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21097                    } else {
21098                        buffer_snapshot.clip_point(*position, Bias::Left)
21099                    };
21100                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21101                    new_selections_by_buffer.insert(
21102                        buffer,
21103                        (
21104                            vec![jump_to_offset..jump_to_offset],
21105                            Some(*line_offset_from_top),
21106                        ),
21107                    );
21108                }
21109            }
21110            Some(JumpData::MultiBufferRow {
21111                row,
21112                line_offset_from_top,
21113            }) => {
21114                let point = MultiBufferPoint::new(row.0, 0);
21115                if let Some((buffer, buffer_point, _)) =
21116                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21117                {
21118                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21119                    new_selections_by_buffer
21120                        .entry(buffer)
21121                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21122                        .0
21123                        .push(buffer_offset..buffer_offset)
21124                }
21125            }
21126            None => {
21127                let selections = self.selections.all::<usize>(cx);
21128                let multi_buffer = self.buffer.read(cx);
21129                for selection in selections {
21130                    for (snapshot, range, _, anchor) in multi_buffer
21131                        .snapshot(cx)
21132                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21133                    {
21134                        if let Some(anchor) = anchor {
21135                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21136                            else {
21137                                continue;
21138                            };
21139                            let offset = text::ToOffset::to_offset(
21140                                &anchor.text_anchor,
21141                                &buffer_handle.read(cx).snapshot(),
21142                            );
21143                            let range = offset..offset;
21144                            new_selections_by_buffer
21145                                .entry(buffer_handle)
21146                                .or_insert((Vec::new(), None))
21147                                .0
21148                                .push(range)
21149                        } else {
21150                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21151                            else {
21152                                continue;
21153                            };
21154                            new_selections_by_buffer
21155                                .entry(buffer_handle)
21156                                .or_insert((Vec::new(), None))
21157                                .0
21158                                .push(range)
21159                        }
21160                    }
21161                }
21162            }
21163        }
21164
21165        new_selections_by_buffer
21166            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21167
21168        if new_selections_by_buffer.is_empty() {
21169            return;
21170        }
21171
21172        // We defer the pane interaction because we ourselves are a workspace item
21173        // and activating a new item causes the pane to call a method on us reentrantly,
21174        // which panics if we're on the stack.
21175        window.defer(cx, move |window, cx| {
21176            workspace.update(cx, |workspace, cx| {
21177                let pane = if split {
21178                    workspace.adjacent_pane(window, cx)
21179                } else {
21180                    workspace.active_pane().clone()
21181                };
21182
21183                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21184                    let editor = buffer
21185                        .read(cx)
21186                        .file()
21187                        .is_none()
21188                        .then(|| {
21189                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21190                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21191                            // Instead, we try to activate the existing editor in the pane first.
21192                            let (editor, pane_item_index) =
21193                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21194                                    let editor = item.downcast::<Editor>()?;
21195                                    let singleton_buffer =
21196                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21197                                    if singleton_buffer == buffer {
21198                                        Some((editor, i))
21199                                    } else {
21200                                        None
21201                                    }
21202                                })?;
21203                            pane.update(cx, |pane, cx| {
21204                                pane.activate_item(pane_item_index, true, true, window, cx)
21205                            });
21206                            Some(editor)
21207                        })
21208                        .flatten()
21209                        .unwrap_or_else(|| {
21210                            workspace.open_project_item::<Self>(
21211                                pane.clone(),
21212                                buffer,
21213                                true,
21214                                true,
21215                                window,
21216                                cx,
21217                            )
21218                        });
21219
21220                    editor.update(cx, |editor, cx| {
21221                        let autoscroll = match scroll_offset {
21222                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21223                            None => Autoscroll::newest(),
21224                        };
21225                        let nav_history = editor.nav_history.take();
21226                        editor.change_selections(
21227                            SelectionEffects::scroll(autoscroll),
21228                            window,
21229                            cx,
21230                            |s| {
21231                                s.select_ranges(ranges);
21232                            },
21233                        );
21234                        editor.nav_history = nav_history;
21235                    });
21236                }
21237            })
21238        });
21239    }
21240
21241    // For now, don't allow opening excerpts in buffers that aren't backed by
21242    // regular project files.
21243    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21244        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21245    }
21246
21247    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21248        let snapshot = self.buffer.read(cx).read(cx);
21249        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21250        Some(
21251            ranges
21252                .iter()
21253                .map(move |range| {
21254                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21255                })
21256                .collect(),
21257        )
21258    }
21259
21260    fn selection_replacement_ranges(
21261        &self,
21262        range: Range<OffsetUtf16>,
21263        cx: &mut App,
21264    ) -> Vec<Range<OffsetUtf16>> {
21265        let selections = self.selections.all::<OffsetUtf16>(cx);
21266        let newest_selection = selections
21267            .iter()
21268            .max_by_key(|selection| selection.id)
21269            .unwrap();
21270        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21271        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21272        let snapshot = self.buffer.read(cx).read(cx);
21273        selections
21274            .into_iter()
21275            .map(|mut selection| {
21276                selection.start.0 =
21277                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21278                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21279                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21280                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21281            })
21282            .collect()
21283    }
21284
21285    fn report_editor_event(
21286        &self,
21287        reported_event: ReportEditorEvent,
21288        file_extension: Option<String>,
21289        cx: &App,
21290    ) {
21291        if cfg!(any(test, feature = "test-support")) {
21292            return;
21293        }
21294
21295        let Some(project) = &self.project else { return };
21296
21297        // If None, we are in a file without an extension
21298        let file = self
21299            .buffer
21300            .read(cx)
21301            .as_singleton()
21302            .and_then(|b| b.read(cx).file());
21303        let file_extension = file_extension.or(file
21304            .as_ref()
21305            .and_then(|file| Path::new(file.file_name(cx)).extension())
21306            .and_then(|e| e.to_str())
21307            .map(|a| a.to_string()));
21308
21309        let vim_mode = vim_enabled(cx);
21310
21311        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21312        let copilot_enabled = edit_predictions_provider
21313            == language::language_settings::EditPredictionProvider::Copilot;
21314        let copilot_enabled_for_language = self
21315            .buffer
21316            .read(cx)
21317            .language_settings(cx)
21318            .show_edit_predictions;
21319
21320        let project = project.read(cx);
21321        let event_type = reported_event.event_type();
21322
21323        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21324            telemetry::event!(
21325                event_type,
21326                type = if auto_saved {"autosave"} else {"manual"},
21327                file_extension,
21328                vim_mode,
21329                copilot_enabled,
21330                copilot_enabled_for_language,
21331                edit_predictions_provider,
21332                is_via_ssh = project.is_via_remote_server(),
21333            );
21334        } else {
21335            telemetry::event!(
21336                event_type,
21337                file_extension,
21338                vim_mode,
21339                copilot_enabled,
21340                copilot_enabled_for_language,
21341                edit_predictions_provider,
21342                is_via_ssh = project.is_via_remote_server(),
21343            );
21344        };
21345    }
21346
21347    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21348    /// with each line being an array of {text, highlight} objects.
21349    fn copy_highlight_json(
21350        &mut self,
21351        _: &CopyHighlightJson,
21352        window: &mut Window,
21353        cx: &mut Context<Self>,
21354    ) {
21355        #[derive(Serialize)]
21356        struct Chunk<'a> {
21357            text: String,
21358            highlight: Option<&'a str>,
21359        }
21360
21361        let snapshot = self.buffer.read(cx).snapshot(cx);
21362        let range = self
21363            .selected_text_range(false, window, cx)
21364            .and_then(|selection| {
21365                if selection.range.is_empty() {
21366                    None
21367                } else {
21368                    Some(selection.range)
21369                }
21370            })
21371            .unwrap_or_else(|| 0..snapshot.len());
21372
21373        let chunks = snapshot.chunks(range, true);
21374        let mut lines = Vec::new();
21375        let mut line: VecDeque<Chunk> = VecDeque::new();
21376
21377        let Some(style) = self.style.as_ref() else {
21378            return;
21379        };
21380
21381        for chunk in chunks {
21382            let highlight = chunk
21383                .syntax_highlight_id
21384                .and_then(|id| id.name(&style.syntax));
21385            let mut chunk_lines = chunk.text.split('\n').peekable();
21386            while let Some(text) = chunk_lines.next() {
21387                let mut merged_with_last_token = false;
21388                if let Some(last_token) = line.back_mut()
21389                    && last_token.highlight == highlight
21390                {
21391                    last_token.text.push_str(text);
21392                    merged_with_last_token = true;
21393                }
21394
21395                if !merged_with_last_token {
21396                    line.push_back(Chunk {
21397                        text: text.into(),
21398                        highlight,
21399                    });
21400                }
21401
21402                if chunk_lines.peek().is_some() {
21403                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21404                        line.pop_front();
21405                    }
21406                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21407                        line.pop_back();
21408                    }
21409
21410                    lines.push(mem::take(&mut line));
21411                }
21412            }
21413        }
21414
21415        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21416            return;
21417        };
21418        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21419    }
21420
21421    pub fn open_context_menu(
21422        &mut self,
21423        _: &OpenContextMenu,
21424        window: &mut Window,
21425        cx: &mut Context<Self>,
21426    ) {
21427        self.request_autoscroll(Autoscroll::newest(), cx);
21428        let position = self.selections.newest_display(cx).start;
21429        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21430    }
21431
21432    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21433        &self.inlay_hint_cache
21434    }
21435
21436    pub fn replay_insert_event(
21437        &mut self,
21438        text: &str,
21439        relative_utf16_range: Option<Range<isize>>,
21440        window: &mut Window,
21441        cx: &mut Context<Self>,
21442    ) {
21443        if !self.input_enabled {
21444            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21445            return;
21446        }
21447        if let Some(relative_utf16_range) = relative_utf16_range {
21448            let selections = self.selections.all::<OffsetUtf16>(cx);
21449            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21450                let new_ranges = selections.into_iter().map(|range| {
21451                    let start = OffsetUtf16(
21452                        range
21453                            .head()
21454                            .0
21455                            .saturating_add_signed(relative_utf16_range.start),
21456                    );
21457                    let end = OffsetUtf16(
21458                        range
21459                            .head()
21460                            .0
21461                            .saturating_add_signed(relative_utf16_range.end),
21462                    );
21463                    start..end
21464                });
21465                s.select_ranges(new_ranges);
21466            });
21467        }
21468
21469        self.handle_input(text, window, cx);
21470    }
21471
21472    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21473        let Some(provider) = self.semantics_provider.as_ref() else {
21474            return false;
21475        };
21476
21477        let mut supports = false;
21478        self.buffer().update(cx, |this, cx| {
21479            this.for_each_buffer(|buffer| {
21480                supports |= provider.supports_inlay_hints(buffer, cx);
21481            });
21482        });
21483
21484        supports
21485    }
21486
21487    pub fn is_focused(&self, window: &Window) -> bool {
21488        self.focus_handle.is_focused(window)
21489    }
21490
21491    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21492        cx.emit(EditorEvent::Focused);
21493
21494        if let Some(descendant) = self
21495            .last_focused_descendant
21496            .take()
21497            .and_then(|descendant| descendant.upgrade())
21498        {
21499            window.focus(&descendant);
21500        } else {
21501            if let Some(blame) = self.blame.as_ref() {
21502                blame.update(cx, GitBlame::focus)
21503            }
21504
21505            self.blink_manager.update(cx, BlinkManager::enable);
21506            self.show_cursor_names(window, cx);
21507            self.buffer.update(cx, |buffer, cx| {
21508                buffer.finalize_last_transaction(cx);
21509                if self.leader_id.is_none() {
21510                    buffer.set_active_selections(
21511                        &self.selections.disjoint_anchors_arc(),
21512                        self.selections.line_mode(),
21513                        self.cursor_shape,
21514                        cx,
21515                    );
21516                }
21517            });
21518        }
21519    }
21520
21521    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21522        cx.emit(EditorEvent::FocusedIn)
21523    }
21524
21525    fn handle_focus_out(
21526        &mut self,
21527        event: FocusOutEvent,
21528        _window: &mut Window,
21529        cx: &mut Context<Self>,
21530    ) {
21531        if event.blurred != self.focus_handle {
21532            self.last_focused_descendant = Some(event.blurred);
21533        }
21534        self.selection_drag_state = SelectionDragState::None;
21535        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21536    }
21537
21538    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21539        self.blink_manager.update(cx, BlinkManager::disable);
21540        self.buffer
21541            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21542
21543        if let Some(blame) = self.blame.as_ref() {
21544            blame.update(cx, GitBlame::blur)
21545        }
21546        if !self.hover_state.focused(window, cx) {
21547            hide_hover(self, cx);
21548        }
21549        if !self
21550            .context_menu
21551            .borrow()
21552            .as_ref()
21553            .is_some_and(|context_menu| context_menu.focused(window, cx))
21554        {
21555            self.hide_context_menu(window, cx);
21556        }
21557        self.take_active_edit_prediction(cx);
21558        cx.emit(EditorEvent::Blurred);
21559        cx.notify();
21560    }
21561
21562    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21563        let mut pending: String = window
21564            .pending_input_keystrokes()
21565            .into_iter()
21566            .flatten()
21567            .filter_map(|keystroke| {
21568                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21569                    keystroke.key_char.clone()
21570                } else {
21571                    None
21572                }
21573            })
21574            .collect();
21575
21576        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21577            pending = "".to_string();
21578        }
21579
21580        let existing_pending = self
21581            .text_highlights::<PendingInput>(cx)
21582            .map(|(_, ranges)| ranges.to_vec());
21583        if existing_pending.is_none() && pending.is_empty() {
21584            return;
21585        }
21586        let transaction =
21587            self.transact(window, cx, |this, window, cx| {
21588                let selections = this.selections.all::<usize>(cx);
21589                let edits = selections
21590                    .iter()
21591                    .map(|selection| (selection.end..selection.end, pending.clone()));
21592                this.edit(edits, cx);
21593                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21594                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21595                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21596                    }));
21597                });
21598                if let Some(existing_ranges) = existing_pending {
21599                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21600                    this.edit(edits, cx);
21601                }
21602            });
21603
21604        let snapshot = self.snapshot(window, cx);
21605        let ranges = self
21606            .selections
21607            .all::<usize>(cx)
21608            .into_iter()
21609            .map(|selection| {
21610                snapshot.buffer_snapshot().anchor_after(selection.end)
21611                    ..snapshot
21612                        .buffer_snapshot()
21613                        .anchor_before(selection.end + pending.len())
21614            })
21615            .collect();
21616
21617        if pending.is_empty() {
21618            self.clear_highlights::<PendingInput>(cx);
21619        } else {
21620            self.highlight_text::<PendingInput>(
21621                ranges,
21622                HighlightStyle {
21623                    underline: Some(UnderlineStyle {
21624                        thickness: px(1.),
21625                        color: None,
21626                        wavy: false,
21627                    }),
21628                    ..Default::default()
21629                },
21630                cx,
21631            );
21632        }
21633
21634        self.ime_transaction = self.ime_transaction.or(transaction);
21635        if let Some(transaction) = self.ime_transaction {
21636            self.buffer.update(cx, |buffer, cx| {
21637                buffer.group_until_transaction(transaction, cx);
21638            });
21639        }
21640
21641        if self.text_highlights::<PendingInput>(cx).is_none() {
21642            self.ime_transaction.take();
21643        }
21644    }
21645
21646    pub fn register_action_renderer(
21647        &mut self,
21648        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21649    ) -> Subscription {
21650        let id = self.next_editor_action_id.post_inc();
21651        self.editor_actions
21652            .borrow_mut()
21653            .insert(id, Box::new(listener));
21654
21655        let editor_actions = self.editor_actions.clone();
21656        Subscription::new(move || {
21657            editor_actions.borrow_mut().remove(&id);
21658        })
21659    }
21660
21661    pub fn register_action<A: Action>(
21662        &mut self,
21663        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21664    ) -> Subscription {
21665        let id = self.next_editor_action_id.post_inc();
21666        let listener = Arc::new(listener);
21667        self.editor_actions.borrow_mut().insert(
21668            id,
21669            Box::new(move |_, window, _| {
21670                let listener = listener.clone();
21671                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21672                    let action = action.downcast_ref().unwrap();
21673                    if phase == DispatchPhase::Bubble {
21674                        listener(action, window, cx)
21675                    }
21676                })
21677            }),
21678        );
21679
21680        let editor_actions = self.editor_actions.clone();
21681        Subscription::new(move || {
21682            editor_actions.borrow_mut().remove(&id);
21683        })
21684    }
21685
21686    pub fn file_header_size(&self) -> u32 {
21687        FILE_HEADER_HEIGHT
21688    }
21689
21690    pub fn restore(
21691        &mut self,
21692        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21693        window: &mut Window,
21694        cx: &mut Context<Self>,
21695    ) {
21696        let workspace = self.workspace();
21697        let project = self.project();
21698        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21699            let mut tasks = Vec::new();
21700            for (buffer_id, changes) in revert_changes {
21701                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21702                    buffer.update(cx, |buffer, cx| {
21703                        buffer.edit(
21704                            changes
21705                                .into_iter()
21706                                .map(|(range, text)| (range, text.to_string())),
21707                            None,
21708                            cx,
21709                        );
21710                    });
21711
21712                    if let Some(project) =
21713                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21714                    {
21715                        project.update(cx, |project, cx| {
21716                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21717                        })
21718                    }
21719                }
21720            }
21721            tasks
21722        });
21723        cx.spawn_in(window, async move |_, cx| {
21724            for (buffer, task) in save_tasks {
21725                let result = task.await;
21726                if result.is_err() {
21727                    let Some(path) = buffer
21728                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21729                        .ok()
21730                    else {
21731                        continue;
21732                    };
21733                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21734                        let Some(task) = cx
21735                            .update_window_entity(workspace, |workspace, window, cx| {
21736                                workspace
21737                                    .open_path_preview(path, None, false, false, false, window, cx)
21738                            })
21739                            .ok()
21740                        else {
21741                            continue;
21742                        };
21743                        task.await.log_err();
21744                    }
21745                }
21746            }
21747        })
21748        .detach();
21749        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21750            selections.refresh()
21751        });
21752    }
21753
21754    pub fn to_pixel_point(
21755        &self,
21756        source: multi_buffer::Anchor,
21757        editor_snapshot: &EditorSnapshot,
21758        window: &mut Window,
21759    ) -> Option<gpui::Point<Pixels>> {
21760        let source_point = source.to_display_point(editor_snapshot);
21761        self.display_to_pixel_point(source_point, editor_snapshot, window)
21762    }
21763
21764    pub fn display_to_pixel_point(
21765        &self,
21766        source: DisplayPoint,
21767        editor_snapshot: &EditorSnapshot,
21768        window: &mut Window,
21769    ) -> Option<gpui::Point<Pixels>> {
21770        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21771        let text_layout_details = self.text_layout_details(window);
21772        let scroll_top = text_layout_details
21773            .scroll_anchor
21774            .scroll_position(editor_snapshot)
21775            .y;
21776
21777        if source.row().as_f64() < scroll_top.floor() {
21778            return None;
21779        }
21780        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21781        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21782        Some(gpui::Point::new(source_x, source_y))
21783    }
21784
21785    pub fn has_visible_completions_menu(&self) -> bool {
21786        !self.edit_prediction_preview_is_active()
21787            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21788                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21789            })
21790    }
21791
21792    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21793        if self.mode.is_minimap() {
21794            return;
21795        }
21796        self.addons
21797            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21798    }
21799
21800    pub fn unregister_addon<T: Addon>(&mut self) {
21801        self.addons.remove(&std::any::TypeId::of::<T>());
21802    }
21803
21804    pub fn addon<T: Addon>(&self) -> Option<&T> {
21805        let type_id = std::any::TypeId::of::<T>();
21806        self.addons
21807            .get(&type_id)
21808            .and_then(|item| item.to_any().downcast_ref::<T>())
21809    }
21810
21811    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21812        let type_id = std::any::TypeId::of::<T>();
21813        self.addons
21814            .get_mut(&type_id)
21815            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21816    }
21817
21818    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21819        let text_layout_details = self.text_layout_details(window);
21820        let style = &text_layout_details.editor_style;
21821        let font_id = window.text_system().resolve_font(&style.text.font());
21822        let font_size = style.text.font_size.to_pixels(window.rem_size());
21823        let line_height = style.text.line_height_in_pixels(window.rem_size());
21824        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21825        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21826
21827        CharacterDimensions {
21828            em_width,
21829            em_advance,
21830            line_height,
21831        }
21832    }
21833
21834    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21835        self.load_diff_task.clone()
21836    }
21837
21838    fn read_metadata_from_db(
21839        &mut self,
21840        item_id: u64,
21841        workspace_id: WorkspaceId,
21842        window: &mut Window,
21843        cx: &mut Context<Editor>,
21844    ) {
21845        if self.buffer_kind(cx) == ItemBufferKind::Singleton
21846            && !self.mode.is_minimap()
21847            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21848        {
21849            let buffer_snapshot = OnceCell::new();
21850
21851            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21852                && !folds.is_empty()
21853            {
21854                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21855                self.fold_ranges(
21856                    folds
21857                        .into_iter()
21858                        .map(|(start, end)| {
21859                            snapshot.clip_offset(start, Bias::Left)
21860                                ..snapshot.clip_offset(end, Bias::Right)
21861                        })
21862                        .collect(),
21863                    false,
21864                    window,
21865                    cx,
21866                );
21867            }
21868
21869            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21870                && !selections.is_empty()
21871            {
21872                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21873                // skip adding the initial selection to selection history
21874                self.selection_history.mode = SelectionHistoryMode::Skipping;
21875                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21876                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21877                        snapshot.clip_offset(start, Bias::Left)
21878                            ..snapshot.clip_offset(end, Bias::Right)
21879                    }));
21880                });
21881                self.selection_history.mode = SelectionHistoryMode::Normal;
21882            };
21883        }
21884
21885        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21886    }
21887
21888    fn update_lsp_data(
21889        &mut self,
21890        ignore_cache: bool,
21891        for_buffer: Option<BufferId>,
21892        window: &mut Window,
21893        cx: &mut Context<'_, Self>,
21894    ) {
21895        self.pull_diagnostics(for_buffer, window, cx);
21896        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21897    }
21898}
21899
21900fn edit_for_markdown_paste<'a>(
21901    buffer: &MultiBufferSnapshot,
21902    range: Range<usize>,
21903    to_insert: &'a str,
21904    url: Option<url::Url>,
21905) -> (Range<usize>, Cow<'a, str>) {
21906    if url.is_none() {
21907        return (range, Cow::Borrowed(to_insert));
21908    };
21909
21910    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
21911
21912    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
21913        Cow::Borrowed(to_insert)
21914    } else {
21915        Cow::Owned(format!("[{old_text}]({to_insert})"))
21916    };
21917    (range, new_text)
21918}
21919
21920fn vim_enabled(cx: &App) -> bool {
21921    vim_mode_setting::VimModeSetting::try_get(cx)
21922        .map(|vim_mode| vim_mode.0)
21923        .unwrap_or(false)
21924}
21925
21926fn process_completion_for_edit(
21927    completion: &Completion,
21928    intent: CompletionIntent,
21929    buffer: &Entity<Buffer>,
21930    cursor_position: &text::Anchor,
21931    cx: &mut Context<Editor>,
21932) -> CompletionEdit {
21933    let buffer = buffer.read(cx);
21934    let buffer_snapshot = buffer.snapshot();
21935    let (snippet, new_text) = if completion.is_snippet() {
21936        let mut snippet_source = completion.new_text.clone();
21937        // Workaround for typescript language server issues so that methods don't expand within
21938        // strings and functions with type expressions. The previous point is used because the query
21939        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21940        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
21941        let previous_point = if previous_point.column > 0 {
21942            cursor_position.to_previous_offset(&buffer_snapshot)
21943        } else {
21944            cursor_position.to_offset(&buffer_snapshot)
21945        };
21946        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21947            && scope.prefers_label_for_snippet_in_completion()
21948            && let Some(label) = completion.label()
21949            && matches!(
21950                completion.kind(),
21951                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21952            )
21953        {
21954            snippet_source = label;
21955        }
21956        match Snippet::parse(&snippet_source).log_err() {
21957            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21958            None => (None, completion.new_text.clone()),
21959        }
21960    } else {
21961        (None, completion.new_text.clone())
21962    };
21963
21964    let mut range_to_replace = {
21965        let replace_range = &completion.replace_range;
21966        if let CompletionSource::Lsp {
21967            insert_range: Some(insert_range),
21968            ..
21969        } = &completion.source
21970        {
21971            debug_assert_eq!(
21972                insert_range.start, replace_range.start,
21973                "insert_range and replace_range should start at the same position"
21974            );
21975            debug_assert!(
21976                insert_range
21977                    .start
21978                    .cmp(cursor_position, &buffer_snapshot)
21979                    .is_le(),
21980                "insert_range should start before or at cursor position"
21981            );
21982            debug_assert!(
21983                replace_range
21984                    .start
21985                    .cmp(cursor_position, &buffer_snapshot)
21986                    .is_le(),
21987                "replace_range should start before or at cursor position"
21988            );
21989
21990            let should_replace = match intent {
21991                CompletionIntent::CompleteWithInsert => false,
21992                CompletionIntent::CompleteWithReplace => true,
21993                CompletionIntent::Complete | CompletionIntent::Compose => {
21994                    let insert_mode =
21995                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21996                            .completions
21997                            .lsp_insert_mode;
21998                    match insert_mode {
21999                        LspInsertMode::Insert => false,
22000                        LspInsertMode::Replace => true,
22001                        LspInsertMode::ReplaceSubsequence => {
22002                            let mut text_to_replace = buffer.chars_for_range(
22003                                buffer.anchor_before(replace_range.start)
22004                                    ..buffer.anchor_after(replace_range.end),
22005                            );
22006                            let mut current_needle = text_to_replace.next();
22007                            for haystack_ch in completion.label.text.chars() {
22008                                if let Some(needle_ch) = current_needle
22009                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22010                                {
22011                                    current_needle = text_to_replace.next();
22012                                }
22013                            }
22014                            current_needle.is_none()
22015                        }
22016                        LspInsertMode::ReplaceSuffix => {
22017                            if replace_range
22018                                .end
22019                                .cmp(cursor_position, &buffer_snapshot)
22020                                .is_gt()
22021                            {
22022                                let range_after_cursor = *cursor_position..replace_range.end;
22023                                let text_after_cursor = buffer
22024                                    .text_for_range(
22025                                        buffer.anchor_before(range_after_cursor.start)
22026                                            ..buffer.anchor_after(range_after_cursor.end),
22027                                    )
22028                                    .collect::<String>()
22029                                    .to_ascii_lowercase();
22030                                completion
22031                                    .label
22032                                    .text
22033                                    .to_ascii_lowercase()
22034                                    .ends_with(&text_after_cursor)
22035                            } else {
22036                                true
22037                            }
22038                        }
22039                    }
22040                }
22041            };
22042
22043            if should_replace {
22044                replace_range.clone()
22045            } else {
22046                insert_range.clone()
22047            }
22048        } else {
22049            replace_range.clone()
22050        }
22051    };
22052
22053    if range_to_replace
22054        .end
22055        .cmp(cursor_position, &buffer_snapshot)
22056        .is_lt()
22057    {
22058        range_to_replace.end = *cursor_position;
22059    }
22060
22061    CompletionEdit {
22062        new_text,
22063        replace_range: range_to_replace.to_offset(buffer),
22064        snippet,
22065    }
22066}
22067
22068struct CompletionEdit {
22069    new_text: String,
22070    replace_range: Range<usize>,
22071    snippet: Option<Snippet>,
22072}
22073
22074fn insert_extra_newline_brackets(
22075    buffer: &MultiBufferSnapshot,
22076    range: Range<usize>,
22077    language: &language::LanguageScope,
22078) -> bool {
22079    let leading_whitespace_len = buffer
22080        .reversed_chars_at(range.start)
22081        .take_while(|c| c.is_whitespace() && *c != '\n')
22082        .map(|c| c.len_utf8())
22083        .sum::<usize>();
22084    let trailing_whitespace_len = buffer
22085        .chars_at(range.end)
22086        .take_while(|c| c.is_whitespace() && *c != '\n')
22087        .map(|c| c.len_utf8())
22088        .sum::<usize>();
22089    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22090
22091    language.brackets().any(|(pair, enabled)| {
22092        let pair_start = pair.start.trim_end();
22093        let pair_end = pair.end.trim_start();
22094
22095        enabled
22096            && pair.newline
22097            && buffer.contains_str_at(range.end, pair_end)
22098            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22099    })
22100}
22101
22102fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22103    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22104        [(buffer, range, _)] => (*buffer, range.clone()),
22105        _ => return false,
22106    };
22107    let pair = {
22108        let mut result: Option<BracketMatch> = None;
22109
22110        for pair in buffer
22111            .all_bracket_ranges(range.clone())
22112            .filter(move |pair| {
22113                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22114            })
22115        {
22116            let len = pair.close_range.end - pair.open_range.start;
22117
22118            if let Some(existing) = &result {
22119                let existing_len = existing.close_range.end - existing.open_range.start;
22120                if len > existing_len {
22121                    continue;
22122                }
22123            }
22124
22125            result = Some(pair);
22126        }
22127
22128        result
22129    };
22130    let Some(pair) = pair else {
22131        return false;
22132    };
22133    pair.newline_only
22134        && buffer
22135            .chars_for_range(pair.open_range.end..range.start)
22136            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22137            .all(|c| c.is_whitespace() && c != '\n')
22138}
22139
22140fn update_uncommitted_diff_for_buffer(
22141    editor: Entity<Editor>,
22142    project: &Entity<Project>,
22143    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22144    buffer: Entity<MultiBuffer>,
22145    cx: &mut App,
22146) -> Task<()> {
22147    let mut tasks = Vec::new();
22148    project.update(cx, |project, cx| {
22149        for buffer in buffers {
22150            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22151                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22152            }
22153        }
22154    });
22155    cx.spawn(async move |cx| {
22156        let diffs = future::join_all(tasks).await;
22157        if editor
22158            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22159            .unwrap_or(false)
22160        {
22161            return;
22162        }
22163
22164        buffer
22165            .update(cx, |buffer, cx| {
22166                for diff in diffs.into_iter().flatten() {
22167                    buffer.add_diff(diff, cx);
22168                }
22169            })
22170            .ok();
22171    })
22172}
22173
22174fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22175    let tab_size = tab_size.get() as usize;
22176    let mut width = offset;
22177
22178    for ch in text.chars() {
22179        width += if ch == '\t' {
22180            tab_size - (width % tab_size)
22181        } else {
22182            1
22183        };
22184    }
22185
22186    width - offset
22187}
22188
22189#[cfg(test)]
22190mod tests {
22191    use super::*;
22192
22193    #[test]
22194    fn test_string_size_with_expanded_tabs() {
22195        let nz = |val| NonZeroU32::new(val).unwrap();
22196        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22197        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22198        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22199        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22200        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22201        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22202        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22203        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22204    }
22205}
22206
22207/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22208struct WordBreakingTokenizer<'a> {
22209    input: &'a str,
22210}
22211
22212impl<'a> WordBreakingTokenizer<'a> {
22213    fn new(input: &'a str) -> Self {
22214        Self { input }
22215    }
22216}
22217
22218fn is_char_ideographic(ch: char) -> bool {
22219    use unicode_script::Script::*;
22220    use unicode_script::UnicodeScript;
22221    matches!(ch.script(), Han | Tangut | Yi)
22222}
22223
22224fn is_grapheme_ideographic(text: &str) -> bool {
22225    text.chars().any(is_char_ideographic)
22226}
22227
22228fn is_grapheme_whitespace(text: &str) -> bool {
22229    text.chars().any(|x| x.is_whitespace())
22230}
22231
22232fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22233    text.chars()
22234        .next()
22235        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22236}
22237
22238#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22239enum WordBreakToken<'a> {
22240    Word { token: &'a str, grapheme_len: usize },
22241    InlineWhitespace { token: &'a str, grapheme_len: usize },
22242    Newline,
22243}
22244
22245impl<'a> Iterator for WordBreakingTokenizer<'a> {
22246    /// Yields a span, the count of graphemes in the token, and whether it was
22247    /// whitespace. Note that it also breaks at word boundaries.
22248    type Item = WordBreakToken<'a>;
22249
22250    fn next(&mut self) -> Option<Self::Item> {
22251        use unicode_segmentation::UnicodeSegmentation;
22252        if self.input.is_empty() {
22253            return None;
22254        }
22255
22256        let mut iter = self.input.graphemes(true).peekable();
22257        let mut offset = 0;
22258        let mut grapheme_len = 0;
22259        if let Some(first_grapheme) = iter.next() {
22260            let is_newline = first_grapheme == "\n";
22261            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22262            offset += first_grapheme.len();
22263            grapheme_len += 1;
22264            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22265                if let Some(grapheme) = iter.peek().copied()
22266                    && should_stay_with_preceding_ideograph(grapheme)
22267                {
22268                    offset += grapheme.len();
22269                    grapheme_len += 1;
22270                }
22271            } else {
22272                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22273                let mut next_word_bound = words.peek().copied();
22274                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22275                    next_word_bound = words.next();
22276                }
22277                while let Some(grapheme) = iter.peek().copied() {
22278                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22279                        break;
22280                    };
22281                    if is_grapheme_whitespace(grapheme) != is_whitespace
22282                        || (grapheme == "\n") != is_newline
22283                    {
22284                        break;
22285                    };
22286                    offset += grapheme.len();
22287                    grapheme_len += 1;
22288                    iter.next();
22289                }
22290            }
22291            let token = &self.input[..offset];
22292            self.input = &self.input[offset..];
22293            if token == "\n" {
22294                Some(WordBreakToken::Newline)
22295            } else if is_whitespace {
22296                Some(WordBreakToken::InlineWhitespace {
22297                    token,
22298                    grapheme_len,
22299                })
22300            } else {
22301                Some(WordBreakToken::Word {
22302                    token,
22303                    grapheme_len,
22304                })
22305            }
22306        } else {
22307            None
22308        }
22309    }
22310}
22311
22312#[test]
22313fn test_word_breaking_tokenizer() {
22314    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22315        ("", &[]),
22316        ("  ", &[whitespace("  ", 2)]),
22317        ("Ʒ", &[word("Ʒ", 1)]),
22318        ("Ǽ", &[word("Ǽ", 1)]),
22319        ("", &[word("", 1)]),
22320        ("⋑⋑", &[word("⋑⋑", 2)]),
22321        (
22322            "原理,进而",
22323            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22324        ),
22325        (
22326            "hello world",
22327            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22328        ),
22329        (
22330            "hello, world",
22331            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22332        ),
22333        (
22334            "  hello world",
22335            &[
22336                whitespace("  ", 2),
22337                word("hello", 5),
22338                whitespace(" ", 1),
22339                word("world", 5),
22340            ],
22341        ),
22342        (
22343            "这是什么 \n 钢笔",
22344            &[
22345                word("", 1),
22346                word("", 1),
22347                word("", 1),
22348                word("", 1),
22349                whitespace(" ", 1),
22350                newline(),
22351                whitespace(" ", 1),
22352                word("", 1),
22353                word("", 1),
22354            ],
22355        ),
22356        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22357    ];
22358
22359    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22360        WordBreakToken::Word {
22361            token,
22362            grapheme_len,
22363        }
22364    }
22365
22366    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22367        WordBreakToken::InlineWhitespace {
22368            token,
22369            grapheme_len,
22370        }
22371    }
22372
22373    fn newline() -> WordBreakToken<'static> {
22374        WordBreakToken::Newline
22375    }
22376
22377    for (input, result) in tests {
22378        assert_eq!(
22379            WordBreakingTokenizer::new(input)
22380                .collect::<Vec<_>>()
22381                .as_slice(),
22382            *result,
22383        );
22384    }
22385}
22386
22387fn wrap_with_prefix(
22388    first_line_prefix: String,
22389    subsequent_lines_prefix: String,
22390    unwrapped_text: String,
22391    wrap_column: usize,
22392    tab_size: NonZeroU32,
22393    preserve_existing_whitespace: bool,
22394) -> String {
22395    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22396    let subsequent_lines_prefix_len =
22397        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22398    let mut wrapped_text = String::new();
22399    let mut current_line = first_line_prefix;
22400    let mut is_first_line = true;
22401
22402    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22403    let mut current_line_len = first_line_prefix_len;
22404    let mut in_whitespace = false;
22405    for token in tokenizer {
22406        let have_preceding_whitespace = in_whitespace;
22407        match token {
22408            WordBreakToken::Word {
22409                token,
22410                grapheme_len,
22411            } => {
22412                in_whitespace = false;
22413                let current_prefix_len = if is_first_line {
22414                    first_line_prefix_len
22415                } else {
22416                    subsequent_lines_prefix_len
22417                };
22418                if current_line_len + grapheme_len > wrap_column
22419                    && current_line_len != current_prefix_len
22420                {
22421                    wrapped_text.push_str(current_line.trim_end());
22422                    wrapped_text.push('\n');
22423                    is_first_line = false;
22424                    current_line = subsequent_lines_prefix.clone();
22425                    current_line_len = subsequent_lines_prefix_len;
22426                }
22427                current_line.push_str(token);
22428                current_line_len += grapheme_len;
22429            }
22430            WordBreakToken::InlineWhitespace {
22431                mut token,
22432                mut grapheme_len,
22433            } => {
22434                in_whitespace = true;
22435                if have_preceding_whitespace && !preserve_existing_whitespace {
22436                    continue;
22437                }
22438                if !preserve_existing_whitespace {
22439                    // Keep a single whitespace grapheme as-is
22440                    if let Some(first) =
22441                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22442                    {
22443                        token = first;
22444                    } else {
22445                        token = " ";
22446                    }
22447                    grapheme_len = 1;
22448                }
22449                let current_prefix_len = if is_first_line {
22450                    first_line_prefix_len
22451                } else {
22452                    subsequent_lines_prefix_len
22453                };
22454                if current_line_len + grapheme_len > wrap_column {
22455                    wrapped_text.push_str(current_line.trim_end());
22456                    wrapped_text.push('\n');
22457                    is_first_line = false;
22458                    current_line = subsequent_lines_prefix.clone();
22459                    current_line_len = subsequent_lines_prefix_len;
22460                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22461                    current_line.push_str(token);
22462                    current_line_len += grapheme_len;
22463                }
22464            }
22465            WordBreakToken::Newline => {
22466                in_whitespace = true;
22467                let current_prefix_len = if is_first_line {
22468                    first_line_prefix_len
22469                } else {
22470                    subsequent_lines_prefix_len
22471                };
22472                if preserve_existing_whitespace {
22473                    wrapped_text.push_str(current_line.trim_end());
22474                    wrapped_text.push('\n');
22475                    is_first_line = false;
22476                    current_line = subsequent_lines_prefix.clone();
22477                    current_line_len = subsequent_lines_prefix_len;
22478                } else if have_preceding_whitespace {
22479                    continue;
22480                } else if current_line_len + 1 > wrap_column
22481                    && current_line_len != current_prefix_len
22482                {
22483                    wrapped_text.push_str(current_line.trim_end());
22484                    wrapped_text.push('\n');
22485                    is_first_line = false;
22486                    current_line = subsequent_lines_prefix.clone();
22487                    current_line_len = subsequent_lines_prefix_len;
22488                } else if current_line_len != current_prefix_len {
22489                    current_line.push(' ');
22490                    current_line_len += 1;
22491                }
22492            }
22493        }
22494    }
22495
22496    if !current_line.is_empty() {
22497        wrapped_text.push_str(&current_line);
22498    }
22499    wrapped_text
22500}
22501
22502#[test]
22503fn test_wrap_with_prefix() {
22504    assert_eq!(
22505        wrap_with_prefix(
22506            "# ".to_string(),
22507            "# ".to_string(),
22508            "abcdefg".to_string(),
22509            4,
22510            NonZeroU32::new(4).unwrap(),
22511            false,
22512        ),
22513        "# abcdefg"
22514    );
22515    assert_eq!(
22516        wrap_with_prefix(
22517            "".to_string(),
22518            "".to_string(),
22519            "\thello world".to_string(),
22520            8,
22521            NonZeroU32::new(4).unwrap(),
22522            false,
22523        ),
22524        "hello\nworld"
22525    );
22526    assert_eq!(
22527        wrap_with_prefix(
22528            "// ".to_string(),
22529            "// ".to_string(),
22530            "xx \nyy zz aa bb cc".to_string(),
22531            12,
22532            NonZeroU32::new(4).unwrap(),
22533            false,
22534        ),
22535        "// xx yy zz\n// aa bb cc"
22536    );
22537    assert_eq!(
22538        wrap_with_prefix(
22539            String::new(),
22540            String::new(),
22541            "这是什么 \n 钢笔".to_string(),
22542            3,
22543            NonZeroU32::new(4).unwrap(),
22544            false,
22545        ),
22546        "这是什\n么 钢\n"
22547    );
22548    assert_eq!(
22549        wrap_with_prefix(
22550            String::new(),
22551            String::new(),
22552            format!("foo{}bar", '\u{2009}'), // thin space
22553            80,
22554            NonZeroU32::new(4).unwrap(),
22555            false,
22556        ),
22557        format!("foo{}bar", '\u{2009}')
22558    );
22559}
22560
22561pub trait CollaborationHub {
22562    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22563    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22564    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22565}
22566
22567impl CollaborationHub for Entity<Project> {
22568    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22569        self.read(cx).collaborators()
22570    }
22571
22572    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22573        self.read(cx).user_store().read(cx).participant_indices()
22574    }
22575
22576    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22577        let this = self.read(cx);
22578        let user_ids = this.collaborators().values().map(|c| c.user_id);
22579        this.user_store().read(cx).participant_names(user_ids, cx)
22580    }
22581}
22582
22583pub trait SemanticsProvider {
22584    fn hover(
22585        &self,
22586        buffer: &Entity<Buffer>,
22587        position: text::Anchor,
22588        cx: &mut App,
22589    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22590
22591    fn inline_values(
22592        &self,
22593        buffer_handle: Entity<Buffer>,
22594        range: Range<text::Anchor>,
22595        cx: &mut App,
22596    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22597
22598    fn inlay_hints(
22599        &self,
22600        buffer_handle: Entity<Buffer>,
22601        range: Range<text::Anchor>,
22602        cx: &mut App,
22603    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22604
22605    fn resolve_inlay_hint(
22606        &self,
22607        hint: InlayHint,
22608        buffer_handle: Entity<Buffer>,
22609        server_id: LanguageServerId,
22610        cx: &mut App,
22611    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22612
22613    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22614
22615    fn document_highlights(
22616        &self,
22617        buffer: &Entity<Buffer>,
22618        position: text::Anchor,
22619        cx: &mut App,
22620    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22621
22622    fn definitions(
22623        &self,
22624        buffer: &Entity<Buffer>,
22625        position: text::Anchor,
22626        kind: GotoDefinitionKind,
22627        cx: &mut App,
22628    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22629
22630    fn range_for_rename(
22631        &self,
22632        buffer: &Entity<Buffer>,
22633        position: text::Anchor,
22634        cx: &mut App,
22635    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22636
22637    fn perform_rename(
22638        &self,
22639        buffer: &Entity<Buffer>,
22640        position: text::Anchor,
22641        new_name: String,
22642        cx: &mut App,
22643    ) -> Option<Task<Result<ProjectTransaction>>>;
22644}
22645
22646pub trait CompletionProvider {
22647    fn completions(
22648        &self,
22649        excerpt_id: ExcerptId,
22650        buffer: &Entity<Buffer>,
22651        buffer_position: text::Anchor,
22652        trigger: CompletionContext,
22653        window: &mut Window,
22654        cx: &mut Context<Editor>,
22655    ) -> Task<Result<Vec<CompletionResponse>>>;
22656
22657    fn resolve_completions(
22658        &self,
22659        _buffer: Entity<Buffer>,
22660        _completion_indices: Vec<usize>,
22661        _completions: Rc<RefCell<Box<[Completion]>>>,
22662        _cx: &mut Context<Editor>,
22663    ) -> Task<Result<bool>> {
22664        Task::ready(Ok(false))
22665    }
22666
22667    fn apply_additional_edits_for_completion(
22668        &self,
22669        _buffer: Entity<Buffer>,
22670        _completions: Rc<RefCell<Box<[Completion]>>>,
22671        _completion_index: usize,
22672        _push_to_history: bool,
22673        _cx: &mut Context<Editor>,
22674    ) -> Task<Result<Option<language::Transaction>>> {
22675        Task::ready(Ok(None))
22676    }
22677
22678    fn is_completion_trigger(
22679        &self,
22680        buffer: &Entity<Buffer>,
22681        position: language::Anchor,
22682        text: &str,
22683        trigger_in_words: bool,
22684        menu_is_open: bool,
22685        cx: &mut Context<Editor>,
22686    ) -> bool;
22687
22688    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22689
22690    fn sort_completions(&self) -> bool {
22691        true
22692    }
22693
22694    fn filter_completions(&self) -> bool {
22695        true
22696    }
22697}
22698
22699pub trait CodeActionProvider {
22700    fn id(&self) -> Arc<str>;
22701
22702    fn code_actions(
22703        &self,
22704        buffer: &Entity<Buffer>,
22705        range: Range<text::Anchor>,
22706        window: &mut Window,
22707        cx: &mut App,
22708    ) -> Task<Result<Vec<CodeAction>>>;
22709
22710    fn apply_code_action(
22711        &self,
22712        buffer_handle: Entity<Buffer>,
22713        action: CodeAction,
22714        excerpt_id: ExcerptId,
22715        push_to_history: bool,
22716        window: &mut Window,
22717        cx: &mut App,
22718    ) -> Task<Result<ProjectTransaction>>;
22719}
22720
22721impl CodeActionProvider for Entity<Project> {
22722    fn id(&self) -> Arc<str> {
22723        "project".into()
22724    }
22725
22726    fn code_actions(
22727        &self,
22728        buffer: &Entity<Buffer>,
22729        range: Range<text::Anchor>,
22730        _window: &mut Window,
22731        cx: &mut App,
22732    ) -> Task<Result<Vec<CodeAction>>> {
22733        self.update(cx, |project, cx| {
22734            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22735            let code_actions = project.code_actions(buffer, range, None, cx);
22736            cx.background_spawn(async move {
22737                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22738                Ok(code_lens_actions
22739                    .context("code lens fetch")?
22740                    .into_iter()
22741                    .flatten()
22742                    .chain(
22743                        code_actions
22744                            .context("code action fetch")?
22745                            .into_iter()
22746                            .flatten(),
22747                    )
22748                    .collect())
22749            })
22750        })
22751    }
22752
22753    fn apply_code_action(
22754        &self,
22755        buffer_handle: Entity<Buffer>,
22756        action: CodeAction,
22757        _excerpt_id: ExcerptId,
22758        push_to_history: bool,
22759        _window: &mut Window,
22760        cx: &mut App,
22761    ) -> Task<Result<ProjectTransaction>> {
22762        self.update(cx, |project, cx| {
22763            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22764        })
22765    }
22766}
22767
22768fn snippet_completions(
22769    project: &Project,
22770    buffer: &Entity<Buffer>,
22771    buffer_position: text::Anchor,
22772    cx: &mut App,
22773) -> Task<Result<CompletionResponse>> {
22774    let languages = buffer.read(cx).languages_at(buffer_position);
22775    let snippet_store = project.snippets().read(cx);
22776
22777    let scopes: Vec<_> = languages
22778        .iter()
22779        .filter_map(|language| {
22780            let language_name = language.lsp_id();
22781            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22782
22783            if snippets.is_empty() {
22784                None
22785            } else {
22786                Some((language.default_scope(), snippets))
22787            }
22788        })
22789        .collect();
22790
22791    if scopes.is_empty() {
22792        return Task::ready(Ok(CompletionResponse {
22793            completions: vec![],
22794            display_options: CompletionDisplayOptions::default(),
22795            is_incomplete: false,
22796        }));
22797    }
22798
22799    let snapshot = buffer.read(cx).text_snapshot();
22800    let executor = cx.background_executor().clone();
22801
22802    cx.background_spawn(async move {
22803        let mut is_incomplete = false;
22804        let mut completions: Vec<Completion> = Vec::new();
22805        for (scope, snippets) in scopes.into_iter() {
22806            let classifier =
22807                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22808
22809            const MAX_WORD_PREFIX_LEN: usize = 128;
22810            let last_word: String = snapshot
22811                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22812                .take(MAX_WORD_PREFIX_LEN)
22813                .take_while(|c| classifier.is_word(*c))
22814                .collect::<String>()
22815                .chars()
22816                .rev()
22817                .collect();
22818
22819            if last_word.is_empty() {
22820                return Ok(CompletionResponse {
22821                    completions: vec![],
22822                    display_options: CompletionDisplayOptions::default(),
22823                    is_incomplete: true,
22824                });
22825            }
22826
22827            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22828            let to_lsp = |point: &text::Anchor| {
22829                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22830                point_to_lsp(end)
22831            };
22832            let lsp_end = to_lsp(&buffer_position);
22833
22834            let candidates = snippets
22835                .iter()
22836                .enumerate()
22837                .flat_map(|(ix, snippet)| {
22838                    snippet
22839                        .prefix
22840                        .iter()
22841                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22842                })
22843                .collect::<Vec<StringMatchCandidate>>();
22844
22845            const MAX_RESULTS: usize = 100;
22846            let mut matches = fuzzy::match_strings(
22847                &candidates,
22848                &last_word,
22849                last_word.chars().any(|c| c.is_uppercase()),
22850                true,
22851                MAX_RESULTS,
22852                &Default::default(),
22853                executor.clone(),
22854            )
22855            .await;
22856
22857            if matches.len() >= MAX_RESULTS {
22858                is_incomplete = true;
22859            }
22860
22861            // Remove all candidates where the query's start does not match the start of any word in the candidate
22862            if let Some(query_start) = last_word.chars().next() {
22863                matches.retain(|string_match| {
22864                    split_words(&string_match.string).any(|word| {
22865                        // Check that the first codepoint of the word as lowercase matches the first
22866                        // codepoint of the query as lowercase
22867                        word.chars()
22868                            .flat_map(|codepoint| codepoint.to_lowercase())
22869                            .zip(query_start.to_lowercase())
22870                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22871                    })
22872                });
22873            }
22874
22875            let matched_strings = matches
22876                .into_iter()
22877                .map(|m| m.string)
22878                .collect::<HashSet<_>>();
22879
22880            completions.extend(snippets.iter().filter_map(|snippet| {
22881                let matching_prefix = snippet
22882                    .prefix
22883                    .iter()
22884                    .find(|prefix| matched_strings.contains(*prefix))?;
22885                let start = as_offset - last_word.len();
22886                let start = snapshot.anchor_before(start);
22887                let range = start..buffer_position;
22888                let lsp_start = to_lsp(&start);
22889                let lsp_range = lsp::Range {
22890                    start: lsp_start,
22891                    end: lsp_end,
22892                };
22893                Some(Completion {
22894                    replace_range: range,
22895                    new_text: snippet.body.clone(),
22896                    source: CompletionSource::Lsp {
22897                        insert_range: None,
22898                        server_id: LanguageServerId(usize::MAX),
22899                        resolved: true,
22900                        lsp_completion: Box::new(lsp::CompletionItem {
22901                            label: snippet.prefix.first().unwrap().clone(),
22902                            kind: Some(CompletionItemKind::SNIPPET),
22903                            label_details: snippet.description.as_ref().map(|description| {
22904                                lsp::CompletionItemLabelDetails {
22905                                    detail: Some(description.clone()),
22906                                    description: None,
22907                                }
22908                            }),
22909                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22910                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22911                                lsp::InsertReplaceEdit {
22912                                    new_text: snippet.body.clone(),
22913                                    insert: lsp_range,
22914                                    replace: lsp_range,
22915                                },
22916                            )),
22917                            filter_text: Some(snippet.body.clone()),
22918                            sort_text: Some(char::MAX.to_string()),
22919                            ..lsp::CompletionItem::default()
22920                        }),
22921                        lsp_defaults: None,
22922                    },
22923                    label: CodeLabel {
22924                        text: matching_prefix.clone(),
22925                        runs: Vec::new(),
22926                        filter_range: 0..matching_prefix.len(),
22927                    },
22928                    icon_path: None,
22929                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22930                        single_line: snippet.name.clone().into(),
22931                        plain_text: snippet
22932                            .description
22933                            .clone()
22934                            .map(|description| description.into()),
22935                    }),
22936                    insert_text_mode: None,
22937                    confirm: None,
22938                })
22939            }))
22940        }
22941
22942        Ok(CompletionResponse {
22943            completions,
22944            display_options: CompletionDisplayOptions::default(),
22945            is_incomplete,
22946        })
22947    })
22948}
22949
22950impl CompletionProvider for Entity<Project> {
22951    fn completions(
22952        &self,
22953        _excerpt_id: ExcerptId,
22954        buffer: &Entity<Buffer>,
22955        buffer_position: text::Anchor,
22956        options: CompletionContext,
22957        _window: &mut Window,
22958        cx: &mut Context<Editor>,
22959    ) -> Task<Result<Vec<CompletionResponse>>> {
22960        self.update(cx, |project, cx| {
22961            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22962            let project_completions = project.completions(buffer, buffer_position, options, cx);
22963            cx.background_spawn(async move {
22964                let mut responses = project_completions.await?;
22965                let snippets = snippets.await?;
22966                if !snippets.completions.is_empty() {
22967                    responses.push(snippets);
22968                }
22969                Ok(responses)
22970            })
22971        })
22972    }
22973
22974    fn resolve_completions(
22975        &self,
22976        buffer: Entity<Buffer>,
22977        completion_indices: Vec<usize>,
22978        completions: Rc<RefCell<Box<[Completion]>>>,
22979        cx: &mut Context<Editor>,
22980    ) -> Task<Result<bool>> {
22981        self.update(cx, |project, cx| {
22982            project.lsp_store().update(cx, |lsp_store, cx| {
22983                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22984            })
22985        })
22986    }
22987
22988    fn apply_additional_edits_for_completion(
22989        &self,
22990        buffer: Entity<Buffer>,
22991        completions: Rc<RefCell<Box<[Completion]>>>,
22992        completion_index: usize,
22993        push_to_history: bool,
22994        cx: &mut Context<Editor>,
22995    ) -> Task<Result<Option<language::Transaction>>> {
22996        self.update(cx, |project, cx| {
22997            project.lsp_store().update(cx, |lsp_store, cx| {
22998                lsp_store.apply_additional_edits_for_completion(
22999                    buffer,
23000                    completions,
23001                    completion_index,
23002                    push_to_history,
23003                    cx,
23004                )
23005            })
23006        })
23007    }
23008
23009    fn is_completion_trigger(
23010        &self,
23011        buffer: &Entity<Buffer>,
23012        position: language::Anchor,
23013        text: &str,
23014        trigger_in_words: bool,
23015        menu_is_open: bool,
23016        cx: &mut Context<Editor>,
23017    ) -> bool {
23018        let mut chars = text.chars();
23019        let char = if let Some(char) = chars.next() {
23020            char
23021        } else {
23022            return false;
23023        };
23024        if chars.next().is_some() {
23025            return false;
23026        }
23027
23028        let buffer = buffer.read(cx);
23029        let snapshot = buffer.snapshot();
23030        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23031            return false;
23032        }
23033        let classifier = snapshot
23034            .char_classifier_at(position)
23035            .scope_context(Some(CharScopeContext::Completion));
23036        if trigger_in_words && classifier.is_word(char) {
23037            return true;
23038        }
23039
23040        buffer.completion_triggers().contains(text)
23041    }
23042}
23043
23044impl SemanticsProvider for Entity<Project> {
23045    fn hover(
23046        &self,
23047        buffer: &Entity<Buffer>,
23048        position: text::Anchor,
23049        cx: &mut App,
23050    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23051        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23052    }
23053
23054    fn document_highlights(
23055        &self,
23056        buffer: &Entity<Buffer>,
23057        position: text::Anchor,
23058        cx: &mut App,
23059    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23060        Some(self.update(cx, |project, cx| {
23061            project.document_highlights(buffer, position, cx)
23062        }))
23063    }
23064
23065    fn definitions(
23066        &self,
23067        buffer: &Entity<Buffer>,
23068        position: text::Anchor,
23069        kind: GotoDefinitionKind,
23070        cx: &mut App,
23071    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23072        Some(self.update(cx, |project, cx| match kind {
23073            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23074            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23075            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23076            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23077        }))
23078    }
23079
23080    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23081        self.update(cx, |project, cx| {
23082            if project
23083                .active_debug_session(cx)
23084                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23085            {
23086                return true;
23087            }
23088
23089            buffer.update(cx, |buffer, cx| {
23090                project.any_language_server_supports_inlay_hints(buffer, cx)
23091            })
23092        })
23093    }
23094
23095    fn inline_values(
23096        &self,
23097        buffer_handle: Entity<Buffer>,
23098        range: Range<text::Anchor>,
23099        cx: &mut App,
23100    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23101        self.update(cx, |project, cx| {
23102            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23103
23104            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23105        })
23106    }
23107
23108    fn inlay_hints(
23109        &self,
23110        buffer_handle: Entity<Buffer>,
23111        range: Range<text::Anchor>,
23112        cx: &mut App,
23113    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23114        Some(self.update(cx, |project, cx| {
23115            project.inlay_hints(buffer_handle, range, cx)
23116        }))
23117    }
23118
23119    fn resolve_inlay_hint(
23120        &self,
23121        hint: InlayHint,
23122        buffer_handle: Entity<Buffer>,
23123        server_id: LanguageServerId,
23124        cx: &mut App,
23125    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23126        Some(self.update(cx, |project, cx| {
23127            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23128        }))
23129    }
23130
23131    fn range_for_rename(
23132        &self,
23133        buffer: &Entity<Buffer>,
23134        position: text::Anchor,
23135        cx: &mut App,
23136    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23137        Some(self.update(cx, |project, cx| {
23138            let buffer = buffer.clone();
23139            let task = project.prepare_rename(buffer.clone(), position, cx);
23140            cx.spawn(async move |_, cx| {
23141                Ok(match task.await? {
23142                    PrepareRenameResponse::Success(range) => Some(range),
23143                    PrepareRenameResponse::InvalidPosition => None,
23144                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23145                        // Fallback on using TreeSitter info to determine identifier range
23146                        buffer.read_with(cx, |buffer, _| {
23147                            let snapshot = buffer.snapshot();
23148                            let (range, kind) = snapshot.surrounding_word(position, None);
23149                            if kind != Some(CharKind::Word) {
23150                                return None;
23151                            }
23152                            Some(
23153                                snapshot.anchor_before(range.start)
23154                                    ..snapshot.anchor_after(range.end),
23155                            )
23156                        })?
23157                    }
23158                })
23159            })
23160        }))
23161    }
23162
23163    fn perform_rename(
23164        &self,
23165        buffer: &Entity<Buffer>,
23166        position: text::Anchor,
23167        new_name: String,
23168        cx: &mut App,
23169    ) -> Option<Task<Result<ProjectTransaction>>> {
23170        Some(self.update(cx, |project, cx| {
23171            project.perform_rename(buffer.clone(), position, new_name, cx)
23172        }))
23173    }
23174}
23175
23176fn inlay_hint_settings(
23177    location: Anchor,
23178    snapshot: &MultiBufferSnapshot,
23179    cx: &mut Context<Editor>,
23180) -> InlayHintSettings {
23181    let file = snapshot.file_at(location);
23182    let language = snapshot.language_at(location).map(|l| l.name());
23183    language_settings(language, file, cx).inlay_hints
23184}
23185
23186fn consume_contiguous_rows(
23187    contiguous_row_selections: &mut Vec<Selection<Point>>,
23188    selection: &Selection<Point>,
23189    display_map: &DisplaySnapshot,
23190    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23191) -> (MultiBufferRow, MultiBufferRow) {
23192    contiguous_row_selections.push(selection.clone());
23193    let start_row = starting_row(selection, display_map);
23194    let mut end_row = ending_row(selection, display_map);
23195
23196    while let Some(next_selection) = selections.peek() {
23197        if next_selection.start.row <= end_row.0 {
23198            end_row = ending_row(next_selection, display_map);
23199            contiguous_row_selections.push(selections.next().unwrap().clone());
23200        } else {
23201            break;
23202        }
23203    }
23204    (start_row, end_row)
23205}
23206
23207fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23208    if selection.start.column > 0 {
23209        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23210    } else {
23211        MultiBufferRow(selection.start.row)
23212    }
23213}
23214
23215fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23216    if next_selection.end.column > 0 || next_selection.is_empty() {
23217        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23218    } else {
23219        MultiBufferRow(next_selection.end.row)
23220    }
23221}
23222
23223impl EditorSnapshot {
23224    pub fn remote_selections_in_range<'a>(
23225        &'a self,
23226        range: &'a Range<Anchor>,
23227        collaboration_hub: &dyn CollaborationHub,
23228        cx: &'a App,
23229    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23230        let participant_names = collaboration_hub.user_names(cx);
23231        let participant_indices = collaboration_hub.user_participant_indices(cx);
23232        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23233        let collaborators_by_replica_id = collaborators_by_peer_id
23234            .values()
23235            .map(|collaborator| (collaborator.replica_id, collaborator))
23236            .collect::<HashMap<_, _>>();
23237        self.buffer_snapshot()
23238            .selections_in_range(range, false)
23239            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23240                if replica_id == AGENT_REPLICA_ID {
23241                    Some(RemoteSelection {
23242                        replica_id,
23243                        selection,
23244                        cursor_shape,
23245                        line_mode,
23246                        collaborator_id: CollaboratorId::Agent,
23247                        user_name: Some("Agent".into()),
23248                        color: cx.theme().players().agent(),
23249                    })
23250                } else {
23251                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23252                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23253                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23254                    Some(RemoteSelection {
23255                        replica_id,
23256                        selection,
23257                        cursor_shape,
23258                        line_mode,
23259                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23260                        user_name,
23261                        color: if let Some(index) = participant_index {
23262                            cx.theme().players().color_for_participant(index.0)
23263                        } else {
23264                            cx.theme().players().absent()
23265                        },
23266                    })
23267                }
23268            })
23269    }
23270
23271    pub fn hunks_for_ranges(
23272        &self,
23273        ranges: impl IntoIterator<Item = Range<Point>>,
23274    ) -> Vec<MultiBufferDiffHunk> {
23275        let mut hunks = Vec::new();
23276        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23277            HashMap::default();
23278        for query_range in ranges {
23279            let query_rows =
23280                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23281            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23282                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23283            ) {
23284                // Include deleted hunks that are adjacent to the query range, because
23285                // otherwise they would be missed.
23286                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23287                if hunk.status().is_deleted() {
23288                    intersects_range |= hunk.row_range.start == query_rows.end;
23289                    intersects_range |= hunk.row_range.end == query_rows.start;
23290                }
23291                if intersects_range {
23292                    if !processed_buffer_rows
23293                        .entry(hunk.buffer_id)
23294                        .or_default()
23295                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23296                    {
23297                        continue;
23298                    }
23299                    hunks.push(hunk);
23300                }
23301            }
23302        }
23303
23304        hunks
23305    }
23306
23307    fn display_diff_hunks_for_rows<'a>(
23308        &'a self,
23309        display_rows: Range<DisplayRow>,
23310        folded_buffers: &'a HashSet<BufferId>,
23311    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23312        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23313        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23314
23315        self.buffer_snapshot()
23316            .diff_hunks_in_range(buffer_start..buffer_end)
23317            .filter_map(|hunk| {
23318                if folded_buffers.contains(&hunk.buffer_id) {
23319                    return None;
23320                }
23321
23322                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23323                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23324
23325                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23326                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23327
23328                let display_hunk = if hunk_display_start.column() != 0 {
23329                    DisplayDiffHunk::Folded {
23330                        display_row: hunk_display_start.row(),
23331                    }
23332                } else {
23333                    let mut end_row = hunk_display_end.row();
23334                    if hunk_display_end.column() > 0 {
23335                        end_row.0 += 1;
23336                    }
23337                    let is_created_file = hunk.is_created_file();
23338                    DisplayDiffHunk::Unfolded {
23339                        status: hunk.status(),
23340                        diff_base_byte_range: hunk.diff_base_byte_range,
23341                        display_row_range: hunk_display_start.row()..end_row,
23342                        multi_buffer_range: Anchor::range_in_buffer(
23343                            hunk.excerpt_id,
23344                            hunk.buffer_id,
23345                            hunk.buffer_range,
23346                        ),
23347                        is_created_file,
23348                    }
23349                };
23350
23351                Some(display_hunk)
23352            })
23353    }
23354
23355    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23356        self.display_snapshot
23357            .buffer_snapshot()
23358            .language_at(position)
23359    }
23360
23361    pub fn is_focused(&self) -> bool {
23362        self.is_focused
23363    }
23364
23365    pub fn placeholder_text(&self) -> Option<String> {
23366        self.placeholder_display_snapshot
23367            .as_ref()
23368            .map(|display_map| display_map.text())
23369    }
23370
23371    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23372        self.scroll_anchor.scroll_position(&self.display_snapshot)
23373    }
23374
23375    fn gutter_dimensions(
23376        &self,
23377        font_id: FontId,
23378        font_size: Pixels,
23379        max_line_number_width: Pixels,
23380        cx: &App,
23381    ) -> Option<GutterDimensions> {
23382        if !self.show_gutter {
23383            return None;
23384        }
23385
23386        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23387        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23388
23389        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23390            matches!(
23391                ProjectSettings::get_global(cx).git.git_gutter,
23392                GitGutterSetting::TrackedFiles
23393            )
23394        });
23395        let gutter_settings = EditorSettings::get_global(cx).gutter;
23396        let show_line_numbers = self
23397            .show_line_numbers
23398            .unwrap_or(gutter_settings.line_numbers);
23399        let line_gutter_width = if show_line_numbers {
23400            // Avoid flicker-like gutter resizes when the line number gains another digit by
23401            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23402            let min_width_for_number_on_gutter =
23403                ch_advance * gutter_settings.min_line_number_digits as f32;
23404            max_line_number_width.max(min_width_for_number_on_gutter)
23405        } else {
23406            0.0.into()
23407        };
23408
23409        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23410        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23411
23412        let git_blame_entries_width =
23413            self.git_blame_gutter_max_author_length
23414                .map(|max_author_length| {
23415                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23416                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23417
23418                    /// The number of characters to dedicate to gaps and margins.
23419                    const SPACING_WIDTH: usize = 4;
23420
23421                    let max_char_count = max_author_length.min(renderer.max_author_length())
23422                        + ::git::SHORT_SHA_LENGTH
23423                        + MAX_RELATIVE_TIMESTAMP.len()
23424                        + SPACING_WIDTH;
23425
23426                    ch_advance * max_char_count
23427                });
23428
23429        let is_singleton = self.buffer_snapshot().is_singleton();
23430
23431        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23432        left_padding += if !is_singleton {
23433            ch_width * 4.0
23434        } else if show_runnables || show_breakpoints {
23435            ch_width * 3.0
23436        } else if show_git_gutter && show_line_numbers {
23437            ch_width * 2.0
23438        } else if show_git_gutter || show_line_numbers {
23439            ch_width
23440        } else {
23441            px(0.)
23442        };
23443
23444        let shows_folds = is_singleton && gutter_settings.folds;
23445
23446        let right_padding = if shows_folds && show_line_numbers {
23447            ch_width * 4.0
23448        } else if shows_folds || (!is_singleton && show_line_numbers) {
23449            ch_width * 3.0
23450        } else if show_line_numbers {
23451            ch_width
23452        } else {
23453            px(0.)
23454        };
23455
23456        Some(GutterDimensions {
23457            left_padding,
23458            right_padding,
23459            width: line_gutter_width + left_padding + right_padding,
23460            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23461            git_blame_entries_width,
23462        })
23463    }
23464
23465    pub fn render_crease_toggle(
23466        &self,
23467        buffer_row: MultiBufferRow,
23468        row_contains_cursor: bool,
23469        editor: Entity<Editor>,
23470        window: &mut Window,
23471        cx: &mut App,
23472    ) -> Option<AnyElement> {
23473        let folded = self.is_line_folded(buffer_row);
23474        let mut is_foldable = false;
23475
23476        if let Some(crease) = self
23477            .crease_snapshot
23478            .query_row(buffer_row, self.buffer_snapshot())
23479        {
23480            is_foldable = true;
23481            match crease {
23482                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23483                    if let Some(render_toggle) = render_toggle {
23484                        let toggle_callback =
23485                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23486                                if folded {
23487                                    editor.update(cx, |editor, cx| {
23488                                        editor.fold_at(buffer_row, window, cx)
23489                                    });
23490                                } else {
23491                                    editor.update(cx, |editor, cx| {
23492                                        editor.unfold_at(buffer_row, window, cx)
23493                                    });
23494                                }
23495                            });
23496                        return Some((render_toggle)(
23497                            buffer_row,
23498                            folded,
23499                            toggle_callback,
23500                            window,
23501                            cx,
23502                        ));
23503                    }
23504                }
23505            }
23506        }
23507
23508        is_foldable |= self.starts_indent(buffer_row);
23509
23510        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23511            Some(
23512                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23513                    .toggle_state(folded)
23514                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23515                        if folded {
23516                            this.unfold_at(buffer_row, window, cx);
23517                        } else {
23518                            this.fold_at(buffer_row, window, cx);
23519                        }
23520                    }))
23521                    .into_any_element(),
23522            )
23523        } else {
23524            None
23525        }
23526    }
23527
23528    pub fn render_crease_trailer(
23529        &self,
23530        buffer_row: MultiBufferRow,
23531        window: &mut Window,
23532        cx: &mut App,
23533    ) -> Option<AnyElement> {
23534        let folded = self.is_line_folded(buffer_row);
23535        if let Crease::Inline { render_trailer, .. } = self
23536            .crease_snapshot
23537            .query_row(buffer_row, self.buffer_snapshot())?
23538        {
23539            let render_trailer = render_trailer.as_ref()?;
23540            Some(render_trailer(buffer_row, folded, window, cx))
23541        } else {
23542            None
23543        }
23544    }
23545}
23546
23547impl Deref for EditorSnapshot {
23548    type Target = DisplaySnapshot;
23549
23550    fn deref(&self) -> &Self::Target {
23551        &self.display_snapshot
23552    }
23553}
23554
23555#[derive(Clone, Debug, PartialEq, Eq)]
23556pub enum EditorEvent {
23557    InputIgnored {
23558        text: Arc<str>,
23559    },
23560    InputHandled {
23561        utf16_range_to_replace: Option<Range<isize>>,
23562        text: Arc<str>,
23563    },
23564    ExcerptsAdded {
23565        buffer: Entity<Buffer>,
23566        predecessor: ExcerptId,
23567        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23568    },
23569    ExcerptsRemoved {
23570        ids: Vec<ExcerptId>,
23571        removed_buffer_ids: Vec<BufferId>,
23572    },
23573    BufferFoldToggled {
23574        ids: Vec<ExcerptId>,
23575        folded: bool,
23576    },
23577    ExcerptsEdited {
23578        ids: Vec<ExcerptId>,
23579    },
23580    ExcerptsExpanded {
23581        ids: Vec<ExcerptId>,
23582    },
23583    BufferEdited,
23584    Edited {
23585        transaction_id: clock::Lamport,
23586    },
23587    Reparsed(BufferId),
23588    Focused,
23589    FocusedIn,
23590    Blurred,
23591    DirtyChanged,
23592    Saved,
23593    TitleChanged,
23594    SelectionsChanged {
23595        local: bool,
23596    },
23597    ScrollPositionChanged {
23598        local: bool,
23599        autoscroll: bool,
23600    },
23601    TransactionUndone {
23602        transaction_id: clock::Lamport,
23603    },
23604    TransactionBegun {
23605        transaction_id: clock::Lamport,
23606    },
23607    CursorShapeChanged,
23608    BreadcrumbsChanged,
23609    PushedToNavHistory {
23610        anchor: Anchor,
23611        is_deactivate: bool,
23612    },
23613}
23614
23615impl EventEmitter<EditorEvent> for Editor {}
23616
23617impl Focusable for Editor {
23618    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23619        self.focus_handle.clone()
23620    }
23621}
23622
23623impl Render for Editor {
23624    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23625        let settings = ThemeSettings::get_global(cx);
23626
23627        let mut text_style = match self.mode {
23628            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23629                color: cx.theme().colors().editor_foreground,
23630                font_family: settings.ui_font.family.clone(),
23631                font_features: settings.ui_font.features.clone(),
23632                font_fallbacks: settings.ui_font.fallbacks.clone(),
23633                font_size: rems(0.875).into(),
23634                font_weight: settings.ui_font.weight,
23635                line_height: relative(settings.buffer_line_height.value()),
23636                ..Default::default()
23637            },
23638            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23639                color: cx.theme().colors().editor_foreground,
23640                font_family: settings.buffer_font.family.clone(),
23641                font_features: settings.buffer_font.features.clone(),
23642                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23643                font_size: settings.buffer_font_size(cx).into(),
23644                font_weight: settings.buffer_font.weight,
23645                line_height: relative(settings.buffer_line_height.value()),
23646                ..Default::default()
23647            },
23648        };
23649        if let Some(text_style_refinement) = &self.text_style_refinement {
23650            text_style.refine(text_style_refinement)
23651        }
23652
23653        let background = match self.mode {
23654            EditorMode::SingleLine => cx.theme().system().transparent,
23655            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23656            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23657            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23658        };
23659
23660        EditorElement::new(
23661            &cx.entity(),
23662            EditorStyle {
23663                background,
23664                border: cx.theme().colors().border,
23665                local_player: cx.theme().players().local(),
23666                text: text_style,
23667                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23668                syntax: cx.theme().syntax().clone(),
23669                status: cx.theme().status().clone(),
23670                inlay_hints_style: make_inlay_hints_style(cx),
23671                edit_prediction_styles: make_suggestion_styles(cx),
23672                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23673                show_underlines: self.diagnostics_enabled(),
23674            },
23675        )
23676    }
23677}
23678
23679impl EntityInputHandler for Editor {
23680    fn text_for_range(
23681        &mut self,
23682        range_utf16: Range<usize>,
23683        adjusted_range: &mut Option<Range<usize>>,
23684        _: &mut Window,
23685        cx: &mut Context<Self>,
23686    ) -> Option<String> {
23687        let snapshot = self.buffer.read(cx).read(cx);
23688        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23689        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23690        if (start.0..end.0) != range_utf16 {
23691            adjusted_range.replace(start.0..end.0);
23692        }
23693        Some(snapshot.text_for_range(start..end).collect())
23694    }
23695
23696    fn selected_text_range(
23697        &mut self,
23698        ignore_disabled_input: bool,
23699        _: &mut Window,
23700        cx: &mut Context<Self>,
23701    ) -> Option<UTF16Selection> {
23702        // Prevent the IME menu from appearing when holding down an alphabetic key
23703        // while input is disabled.
23704        if !ignore_disabled_input && !self.input_enabled {
23705            return None;
23706        }
23707
23708        let selection = self.selections.newest::<OffsetUtf16>(cx);
23709        let range = selection.range();
23710
23711        Some(UTF16Selection {
23712            range: range.start.0..range.end.0,
23713            reversed: selection.reversed,
23714        })
23715    }
23716
23717    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23718        let snapshot = self.buffer.read(cx).read(cx);
23719        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23720        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23721    }
23722
23723    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23724        self.clear_highlights::<InputComposition>(cx);
23725        self.ime_transaction.take();
23726    }
23727
23728    fn replace_text_in_range(
23729        &mut self,
23730        range_utf16: Option<Range<usize>>,
23731        text: &str,
23732        window: &mut Window,
23733        cx: &mut Context<Self>,
23734    ) {
23735        if !self.input_enabled {
23736            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23737            return;
23738        }
23739
23740        self.transact(window, cx, |this, window, cx| {
23741            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23742                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23743                Some(this.selection_replacement_ranges(range_utf16, cx))
23744            } else {
23745                this.marked_text_ranges(cx)
23746            };
23747
23748            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23749                let newest_selection_id = this.selections.newest_anchor().id;
23750                this.selections
23751                    .all::<OffsetUtf16>(cx)
23752                    .iter()
23753                    .zip(ranges_to_replace.iter())
23754                    .find_map(|(selection, range)| {
23755                        if selection.id == newest_selection_id {
23756                            Some(
23757                                (range.start.0 as isize - selection.head().0 as isize)
23758                                    ..(range.end.0 as isize - selection.head().0 as isize),
23759                            )
23760                        } else {
23761                            None
23762                        }
23763                    })
23764            });
23765
23766            cx.emit(EditorEvent::InputHandled {
23767                utf16_range_to_replace: range_to_replace,
23768                text: text.into(),
23769            });
23770
23771            if let Some(new_selected_ranges) = new_selected_ranges {
23772                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23773                    selections.select_ranges(new_selected_ranges)
23774                });
23775                this.backspace(&Default::default(), window, cx);
23776            }
23777
23778            this.handle_input(text, window, cx);
23779        });
23780
23781        if let Some(transaction) = self.ime_transaction {
23782            self.buffer.update(cx, |buffer, cx| {
23783                buffer.group_until_transaction(transaction, cx);
23784            });
23785        }
23786
23787        self.unmark_text(window, cx);
23788    }
23789
23790    fn replace_and_mark_text_in_range(
23791        &mut self,
23792        range_utf16: Option<Range<usize>>,
23793        text: &str,
23794        new_selected_range_utf16: Option<Range<usize>>,
23795        window: &mut Window,
23796        cx: &mut Context<Self>,
23797    ) {
23798        if !self.input_enabled {
23799            return;
23800        }
23801
23802        let transaction = self.transact(window, cx, |this, window, cx| {
23803            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23804                let snapshot = this.buffer.read(cx).read(cx);
23805                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23806                    for marked_range in &mut marked_ranges {
23807                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23808                        marked_range.start.0 += relative_range_utf16.start;
23809                        marked_range.start =
23810                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23811                        marked_range.end =
23812                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23813                    }
23814                }
23815                Some(marked_ranges)
23816            } else if let Some(range_utf16) = range_utf16 {
23817                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23818                Some(this.selection_replacement_ranges(range_utf16, cx))
23819            } else {
23820                None
23821            };
23822
23823            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23824                let newest_selection_id = this.selections.newest_anchor().id;
23825                this.selections
23826                    .all::<OffsetUtf16>(cx)
23827                    .iter()
23828                    .zip(ranges_to_replace.iter())
23829                    .find_map(|(selection, range)| {
23830                        if selection.id == newest_selection_id {
23831                            Some(
23832                                (range.start.0 as isize - selection.head().0 as isize)
23833                                    ..(range.end.0 as isize - selection.head().0 as isize),
23834                            )
23835                        } else {
23836                            None
23837                        }
23838                    })
23839            });
23840
23841            cx.emit(EditorEvent::InputHandled {
23842                utf16_range_to_replace: range_to_replace,
23843                text: text.into(),
23844            });
23845
23846            if let Some(ranges) = ranges_to_replace {
23847                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23848                    s.select_ranges(ranges)
23849                });
23850            }
23851
23852            let marked_ranges = {
23853                let snapshot = this.buffer.read(cx).read(cx);
23854                this.selections
23855                    .disjoint_anchors_arc()
23856                    .iter()
23857                    .map(|selection| {
23858                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23859                    })
23860                    .collect::<Vec<_>>()
23861            };
23862
23863            if text.is_empty() {
23864                this.unmark_text(window, cx);
23865            } else {
23866                this.highlight_text::<InputComposition>(
23867                    marked_ranges.clone(),
23868                    HighlightStyle {
23869                        underline: Some(UnderlineStyle {
23870                            thickness: px(1.),
23871                            color: None,
23872                            wavy: false,
23873                        }),
23874                        ..Default::default()
23875                    },
23876                    cx,
23877                );
23878            }
23879
23880            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23881            let use_autoclose = this.use_autoclose;
23882            let use_auto_surround = this.use_auto_surround;
23883            this.set_use_autoclose(false);
23884            this.set_use_auto_surround(false);
23885            this.handle_input(text, window, cx);
23886            this.set_use_autoclose(use_autoclose);
23887            this.set_use_auto_surround(use_auto_surround);
23888
23889            if let Some(new_selected_range) = new_selected_range_utf16 {
23890                let snapshot = this.buffer.read(cx).read(cx);
23891                let new_selected_ranges = marked_ranges
23892                    .into_iter()
23893                    .map(|marked_range| {
23894                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23895                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23896                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23897                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23898                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23899                    })
23900                    .collect::<Vec<_>>();
23901
23902                drop(snapshot);
23903                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23904                    selections.select_ranges(new_selected_ranges)
23905                });
23906            }
23907        });
23908
23909        self.ime_transaction = self.ime_transaction.or(transaction);
23910        if let Some(transaction) = self.ime_transaction {
23911            self.buffer.update(cx, |buffer, cx| {
23912                buffer.group_until_transaction(transaction, cx);
23913            });
23914        }
23915
23916        if self.text_highlights::<InputComposition>(cx).is_none() {
23917            self.ime_transaction.take();
23918        }
23919    }
23920
23921    fn bounds_for_range(
23922        &mut self,
23923        range_utf16: Range<usize>,
23924        element_bounds: gpui::Bounds<Pixels>,
23925        window: &mut Window,
23926        cx: &mut Context<Self>,
23927    ) -> Option<gpui::Bounds<Pixels>> {
23928        let text_layout_details = self.text_layout_details(window);
23929        let CharacterDimensions {
23930            em_width,
23931            em_advance,
23932            line_height,
23933        } = self.character_dimensions(window);
23934
23935        let snapshot = self.snapshot(window, cx);
23936        let scroll_position = snapshot.scroll_position();
23937        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
23938
23939        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23940        let x = Pixels::from(
23941            ScrollOffset::from(
23942                snapshot.x_for_display_point(start, &text_layout_details)
23943                    + self.gutter_dimensions.full_width(),
23944            ) - scroll_left,
23945        );
23946        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
23947
23948        Some(Bounds {
23949            origin: element_bounds.origin + point(x, y),
23950            size: size(em_width, line_height),
23951        })
23952    }
23953
23954    fn character_index_for_point(
23955        &mut self,
23956        point: gpui::Point<Pixels>,
23957        _window: &mut Window,
23958        _cx: &mut Context<Self>,
23959    ) -> Option<usize> {
23960        let position_map = self.last_position_map.as_ref()?;
23961        if !position_map.text_hitbox.contains(&point) {
23962            return None;
23963        }
23964        let display_point = position_map.point_for_position(point).previous_valid;
23965        let anchor = position_map
23966            .snapshot
23967            .display_point_to_anchor(display_point, Bias::Left);
23968        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
23969        Some(utf16_offset.0)
23970    }
23971}
23972
23973trait SelectionExt {
23974    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23975    fn spanned_rows(
23976        &self,
23977        include_end_if_at_line_start: bool,
23978        map: &DisplaySnapshot,
23979    ) -> Range<MultiBufferRow>;
23980}
23981
23982impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23983    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23984        let start = self
23985            .start
23986            .to_point(map.buffer_snapshot())
23987            .to_display_point(map);
23988        let end = self
23989            .end
23990            .to_point(map.buffer_snapshot())
23991            .to_display_point(map);
23992        if self.reversed {
23993            end..start
23994        } else {
23995            start..end
23996        }
23997    }
23998
23999    fn spanned_rows(
24000        &self,
24001        include_end_if_at_line_start: bool,
24002        map: &DisplaySnapshot,
24003    ) -> Range<MultiBufferRow> {
24004        let start = self.start.to_point(map.buffer_snapshot());
24005        let mut end = self.end.to_point(map.buffer_snapshot());
24006        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24007            end.row -= 1;
24008        }
24009
24010        let buffer_start = map.prev_line_boundary(start).0;
24011        let buffer_end = map.next_line_boundary(end).0;
24012        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24013    }
24014}
24015
24016impl<T: InvalidationRegion> InvalidationStack<T> {
24017    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24018    where
24019        S: Clone + ToOffset,
24020    {
24021        while let Some(region) = self.last() {
24022            let all_selections_inside_invalidation_ranges =
24023                if selections.len() == region.ranges().len() {
24024                    selections
24025                        .iter()
24026                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24027                        .all(|(selection, invalidation_range)| {
24028                            let head = selection.head().to_offset(buffer);
24029                            invalidation_range.start <= head && invalidation_range.end >= head
24030                        })
24031                } else {
24032                    false
24033                };
24034
24035            if all_selections_inside_invalidation_ranges {
24036                break;
24037            } else {
24038                self.pop();
24039            }
24040        }
24041    }
24042}
24043
24044impl<T> Default for InvalidationStack<T> {
24045    fn default() -> Self {
24046        Self(Default::default())
24047    }
24048}
24049
24050impl<T> Deref for InvalidationStack<T> {
24051    type Target = Vec<T>;
24052
24053    fn deref(&self) -> &Self::Target {
24054        &self.0
24055    }
24056}
24057
24058impl<T> DerefMut for InvalidationStack<T> {
24059    fn deref_mut(&mut self) -> &mut Self::Target {
24060        &mut self.0
24061    }
24062}
24063
24064impl InvalidationRegion for SnippetState {
24065    fn ranges(&self) -> &[Range<Anchor>] {
24066        &self.ranges[self.active_index]
24067    }
24068}
24069
24070fn edit_prediction_edit_text(
24071    current_snapshot: &BufferSnapshot,
24072    edits: &[(Range<Anchor>, String)],
24073    edit_preview: &EditPreview,
24074    include_deletions: bool,
24075    cx: &App,
24076) -> HighlightedText {
24077    let edits = edits
24078        .iter()
24079        .map(|(anchor, text)| {
24080            (
24081                anchor.start.text_anchor..anchor.end.text_anchor,
24082                text.clone(),
24083            )
24084        })
24085        .collect::<Vec<_>>();
24086
24087    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24088}
24089
24090fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24091    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24092    // Just show the raw edit text with basic styling
24093    let mut text = String::new();
24094    let mut highlights = Vec::new();
24095
24096    let insertion_highlight_style = HighlightStyle {
24097        color: Some(cx.theme().colors().text),
24098        ..Default::default()
24099    };
24100
24101    for (_, edit_text) in edits {
24102        let start_offset = text.len();
24103        text.push_str(edit_text);
24104        let end_offset = text.len();
24105
24106        if start_offset < end_offset {
24107            highlights.push((start_offset..end_offset, insertion_highlight_style));
24108        }
24109    }
24110
24111    HighlightedText {
24112        text: text.into(),
24113        highlights,
24114    }
24115}
24116
24117pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24118    match severity {
24119        lsp::DiagnosticSeverity::ERROR => colors.error,
24120        lsp::DiagnosticSeverity::WARNING => colors.warning,
24121        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24122        lsp::DiagnosticSeverity::HINT => colors.info,
24123        _ => colors.ignored,
24124    }
24125}
24126
24127pub fn styled_runs_for_code_label<'a>(
24128    label: &'a CodeLabel,
24129    syntax_theme: &'a theme::SyntaxTheme,
24130) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24131    let fade_out = HighlightStyle {
24132        fade_out: Some(0.35),
24133        ..Default::default()
24134    };
24135
24136    let mut prev_end = label.filter_range.end;
24137    label
24138        .runs
24139        .iter()
24140        .enumerate()
24141        .flat_map(move |(ix, (range, highlight_id))| {
24142            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24143                style
24144            } else {
24145                return Default::default();
24146            };
24147            let muted_style = style.highlight(fade_out);
24148
24149            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24150            if range.start >= label.filter_range.end {
24151                if range.start > prev_end {
24152                    runs.push((prev_end..range.start, fade_out));
24153                }
24154                runs.push((range.clone(), muted_style));
24155            } else if range.end <= label.filter_range.end {
24156                runs.push((range.clone(), style));
24157            } else {
24158                runs.push((range.start..label.filter_range.end, style));
24159                runs.push((label.filter_range.end..range.end, muted_style));
24160            }
24161            prev_end = cmp::max(prev_end, range.end);
24162
24163            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24164                runs.push((prev_end..label.text.len(), fade_out));
24165            }
24166
24167            runs
24168        })
24169}
24170
24171pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24172    let mut prev_index = 0;
24173    let mut prev_codepoint: Option<char> = None;
24174    text.char_indices()
24175        .chain([(text.len(), '\0')])
24176        .filter_map(move |(index, codepoint)| {
24177            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24178            let is_boundary = index == text.len()
24179                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24180                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24181            if is_boundary {
24182                let chunk = &text[prev_index..index];
24183                prev_index = index;
24184                Some(chunk)
24185            } else {
24186                None
24187            }
24188        })
24189}
24190
24191pub trait RangeToAnchorExt: Sized {
24192    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24193
24194    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24195        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24196        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24197    }
24198}
24199
24200impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24201    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24202        let start_offset = self.start.to_offset(snapshot);
24203        let end_offset = self.end.to_offset(snapshot);
24204        if start_offset == end_offset {
24205            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24206        } else {
24207            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24208        }
24209    }
24210}
24211
24212pub trait RowExt {
24213    fn as_f64(&self) -> f64;
24214
24215    fn next_row(&self) -> Self;
24216
24217    fn previous_row(&self) -> Self;
24218
24219    fn minus(&self, other: Self) -> u32;
24220}
24221
24222impl RowExt for DisplayRow {
24223    fn as_f64(&self) -> f64 {
24224        self.0 as _
24225    }
24226
24227    fn next_row(&self) -> Self {
24228        Self(self.0 + 1)
24229    }
24230
24231    fn previous_row(&self) -> Self {
24232        Self(self.0.saturating_sub(1))
24233    }
24234
24235    fn minus(&self, other: Self) -> u32 {
24236        self.0 - other.0
24237    }
24238}
24239
24240impl RowExt for MultiBufferRow {
24241    fn as_f64(&self) -> f64 {
24242        self.0 as _
24243    }
24244
24245    fn next_row(&self) -> Self {
24246        Self(self.0 + 1)
24247    }
24248
24249    fn previous_row(&self) -> Self {
24250        Self(self.0.saturating_sub(1))
24251    }
24252
24253    fn minus(&self, other: Self) -> u32 {
24254        self.0 - other.0
24255    }
24256}
24257
24258trait RowRangeExt {
24259    type Row;
24260
24261    fn len(&self) -> usize;
24262
24263    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24264}
24265
24266impl RowRangeExt for Range<MultiBufferRow> {
24267    type Row = MultiBufferRow;
24268
24269    fn len(&self) -> usize {
24270        (self.end.0 - self.start.0) as usize
24271    }
24272
24273    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24274        (self.start.0..self.end.0).map(MultiBufferRow)
24275    }
24276}
24277
24278impl RowRangeExt for Range<DisplayRow> {
24279    type Row = DisplayRow;
24280
24281    fn len(&self) -> usize {
24282        (self.end.0 - self.start.0) as usize
24283    }
24284
24285    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24286        (self.start.0..self.end.0).map(DisplayRow)
24287    }
24288}
24289
24290/// If select range has more than one line, we
24291/// just point the cursor to range.start.
24292fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24293    if range.start.row == range.end.row {
24294        range
24295    } else {
24296        range.start..range.start
24297    }
24298}
24299pub struct KillRing(ClipboardItem);
24300impl Global for KillRing {}
24301
24302const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24303
24304enum BreakpointPromptEditAction {
24305    Log,
24306    Condition,
24307    HitCondition,
24308}
24309
24310struct BreakpointPromptEditor {
24311    pub(crate) prompt: Entity<Editor>,
24312    editor: WeakEntity<Editor>,
24313    breakpoint_anchor: Anchor,
24314    breakpoint: Breakpoint,
24315    edit_action: BreakpointPromptEditAction,
24316    block_ids: HashSet<CustomBlockId>,
24317    editor_margins: Arc<Mutex<EditorMargins>>,
24318    _subscriptions: Vec<Subscription>,
24319}
24320
24321impl BreakpointPromptEditor {
24322    const MAX_LINES: u8 = 4;
24323
24324    fn new(
24325        editor: WeakEntity<Editor>,
24326        breakpoint_anchor: Anchor,
24327        breakpoint: Breakpoint,
24328        edit_action: BreakpointPromptEditAction,
24329        window: &mut Window,
24330        cx: &mut Context<Self>,
24331    ) -> Self {
24332        let base_text = match edit_action {
24333            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24334            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24335            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24336        }
24337        .map(|msg| msg.to_string())
24338        .unwrap_or_default();
24339
24340        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24341        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24342
24343        let prompt = cx.new(|cx| {
24344            let mut prompt = Editor::new(
24345                EditorMode::AutoHeight {
24346                    min_lines: 1,
24347                    max_lines: Some(Self::MAX_LINES as usize),
24348                },
24349                buffer,
24350                None,
24351                window,
24352                cx,
24353            );
24354            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24355            prompt.set_show_cursor_when_unfocused(false, cx);
24356            prompt.set_placeholder_text(
24357                match edit_action {
24358                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24359                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24360                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24361                },
24362                window,
24363                cx,
24364            );
24365
24366            prompt
24367        });
24368
24369        Self {
24370            prompt,
24371            editor,
24372            breakpoint_anchor,
24373            breakpoint,
24374            edit_action,
24375            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24376            block_ids: Default::default(),
24377            _subscriptions: vec![],
24378        }
24379    }
24380
24381    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24382        self.block_ids.extend(block_ids)
24383    }
24384
24385    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24386        if let Some(editor) = self.editor.upgrade() {
24387            let message = self
24388                .prompt
24389                .read(cx)
24390                .buffer
24391                .read(cx)
24392                .as_singleton()
24393                .expect("A multi buffer in breakpoint prompt isn't possible")
24394                .read(cx)
24395                .as_rope()
24396                .to_string();
24397
24398            editor.update(cx, |editor, cx| {
24399                editor.edit_breakpoint_at_anchor(
24400                    self.breakpoint_anchor,
24401                    self.breakpoint.clone(),
24402                    match self.edit_action {
24403                        BreakpointPromptEditAction::Log => {
24404                            BreakpointEditAction::EditLogMessage(message.into())
24405                        }
24406                        BreakpointPromptEditAction::Condition => {
24407                            BreakpointEditAction::EditCondition(message.into())
24408                        }
24409                        BreakpointPromptEditAction::HitCondition => {
24410                            BreakpointEditAction::EditHitCondition(message.into())
24411                        }
24412                    },
24413                    cx,
24414                );
24415
24416                editor.remove_blocks(self.block_ids.clone(), None, cx);
24417                cx.focus_self(window);
24418            });
24419        }
24420    }
24421
24422    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24423        self.editor
24424            .update(cx, |editor, cx| {
24425                editor.remove_blocks(self.block_ids.clone(), None, cx);
24426                window.focus(&editor.focus_handle);
24427            })
24428            .log_err();
24429    }
24430
24431    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24432        let settings = ThemeSettings::get_global(cx);
24433        let text_style = TextStyle {
24434            color: if self.prompt.read(cx).read_only(cx) {
24435                cx.theme().colors().text_disabled
24436            } else {
24437                cx.theme().colors().text
24438            },
24439            font_family: settings.buffer_font.family.clone(),
24440            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24441            font_size: settings.buffer_font_size(cx).into(),
24442            font_weight: settings.buffer_font.weight,
24443            line_height: relative(settings.buffer_line_height.value()),
24444            ..Default::default()
24445        };
24446        EditorElement::new(
24447            &self.prompt,
24448            EditorStyle {
24449                background: cx.theme().colors().editor_background,
24450                local_player: cx.theme().players().local(),
24451                text: text_style,
24452                ..Default::default()
24453            },
24454        )
24455    }
24456}
24457
24458impl Render for BreakpointPromptEditor {
24459    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24460        let editor_margins = *self.editor_margins.lock();
24461        let gutter_dimensions = editor_margins.gutter;
24462        h_flex()
24463            .key_context("Editor")
24464            .bg(cx.theme().colors().editor_background)
24465            .border_y_1()
24466            .border_color(cx.theme().status().info_border)
24467            .size_full()
24468            .py(window.line_height() / 2.5)
24469            .on_action(cx.listener(Self::confirm))
24470            .on_action(cx.listener(Self::cancel))
24471            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24472            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24473    }
24474}
24475
24476impl Focusable for BreakpointPromptEditor {
24477    fn focus_handle(&self, cx: &App) -> FocusHandle {
24478        self.prompt.focus_handle(cx)
24479    }
24480}
24481
24482fn all_edits_insertions_or_deletions(
24483    edits: &Vec<(Range<Anchor>, String)>,
24484    snapshot: &MultiBufferSnapshot,
24485) -> bool {
24486    let mut all_insertions = true;
24487    let mut all_deletions = true;
24488
24489    for (range, new_text) in edits.iter() {
24490        let range_is_empty = range.to_offset(snapshot).is_empty();
24491        let text_is_empty = new_text.is_empty();
24492
24493        if range_is_empty != text_is_empty {
24494            if range_is_empty {
24495                all_deletions = false;
24496            } else {
24497                all_insertions = false;
24498            }
24499        } else {
24500            return false;
24501        }
24502
24503        if !all_insertions && !all_deletions {
24504            return false;
24505        }
24506    }
24507    all_insertions || all_deletions
24508}
24509
24510struct MissingEditPredictionKeybindingTooltip;
24511
24512impl Render for MissingEditPredictionKeybindingTooltip {
24513    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24514        ui::tooltip_container(cx, |container, cx| {
24515            container
24516                .flex_shrink_0()
24517                .max_w_80()
24518                .min_h(rems_from_px(124.))
24519                .justify_between()
24520                .child(
24521                    v_flex()
24522                        .flex_1()
24523                        .text_ui_sm(cx)
24524                        .child(Label::new("Conflict with Accept Keybinding"))
24525                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24526                )
24527                .child(
24528                    h_flex()
24529                        .pb_1()
24530                        .gap_1()
24531                        .items_end()
24532                        .w_full()
24533                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24534                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24535                        }))
24536                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24537                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24538                        })),
24539                )
24540        })
24541    }
24542}
24543
24544#[derive(Debug, Clone, Copy, PartialEq)]
24545pub struct LineHighlight {
24546    pub background: Background,
24547    pub border: Option<gpui::Hsla>,
24548    pub include_gutter: bool,
24549    pub type_id: Option<TypeId>,
24550}
24551
24552struct LineManipulationResult {
24553    pub new_text: String,
24554    pub line_count_before: usize,
24555    pub line_count_after: usize,
24556}
24557
24558fn render_diff_hunk_controls(
24559    row: u32,
24560    status: &DiffHunkStatus,
24561    hunk_range: Range<Anchor>,
24562    is_created_file: bool,
24563    line_height: Pixels,
24564    editor: &Entity<Editor>,
24565    _window: &mut Window,
24566    cx: &mut App,
24567) -> AnyElement {
24568    h_flex()
24569        .h(line_height)
24570        .mr_1()
24571        .gap_1()
24572        .px_0p5()
24573        .pb_1()
24574        .border_x_1()
24575        .border_b_1()
24576        .border_color(cx.theme().colors().border_variant)
24577        .rounded_b_lg()
24578        .bg(cx.theme().colors().editor_background)
24579        .gap_1()
24580        .block_mouse_except_scroll()
24581        .shadow_md()
24582        .child(if status.has_secondary_hunk() {
24583            Button::new(("stage", row as u64), "Stage")
24584                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24585                .tooltip({
24586                    let focus_handle = editor.focus_handle(cx);
24587                    move |window, cx| {
24588                        Tooltip::for_action_in(
24589                            "Stage Hunk",
24590                            &::git::ToggleStaged,
24591                            &focus_handle,
24592                            window,
24593                            cx,
24594                        )
24595                    }
24596                })
24597                .on_click({
24598                    let editor = editor.clone();
24599                    move |_event, _window, cx| {
24600                        editor.update(cx, |editor, cx| {
24601                            editor.stage_or_unstage_diff_hunks(
24602                                true,
24603                                vec![hunk_range.start..hunk_range.start],
24604                                cx,
24605                            );
24606                        });
24607                    }
24608                })
24609        } else {
24610            Button::new(("unstage", row as u64), "Unstage")
24611                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24612                .tooltip({
24613                    let focus_handle = editor.focus_handle(cx);
24614                    move |window, cx| {
24615                        Tooltip::for_action_in(
24616                            "Unstage Hunk",
24617                            &::git::ToggleStaged,
24618                            &focus_handle,
24619                            window,
24620                            cx,
24621                        )
24622                    }
24623                })
24624                .on_click({
24625                    let editor = editor.clone();
24626                    move |_event, _window, cx| {
24627                        editor.update(cx, |editor, cx| {
24628                            editor.stage_or_unstage_diff_hunks(
24629                                false,
24630                                vec![hunk_range.start..hunk_range.start],
24631                                cx,
24632                            );
24633                        });
24634                    }
24635                })
24636        })
24637        .child(
24638            Button::new(("restore", row as u64), "Restore")
24639                .tooltip({
24640                    let focus_handle = editor.focus_handle(cx);
24641                    move |window, cx| {
24642                        Tooltip::for_action_in(
24643                            "Restore Hunk",
24644                            &::git::Restore,
24645                            &focus_handle,
24646                            window,
24647                            cx,
24648                        )
24649                    }
24650                })
24651                .on_click({
24652                    let editor = editor.clone();
24653                    move |_event, window, cx| {
24654                        editor.update(cx, |editor, cx| {
24655                            let snapshot = editor.snapshot(window, cx);
24656                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24657                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24658                        });
24659                    }
24660                })
24661                .disabled(is_created_file),
24662        )
24663        .when(
24664            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24665            |el| {
24666                el.child(
24667                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24668                        .shape(IconButtonShape::Square)
24669                        .icon_size(IconSize::Small)
24670                        // .disabled(!has_multiple_hunks)
24671                        .tooltip({
24672                            let focus_handle = editor.focus_handle(cx);
24673                            move |window, cx| {
24674                                Tooltip::for_action_in(
24675                                    "Next Hunk",
24676                                    &GoToHunk,
24677                                    &focus_handle,
24678                                    window,
24679                                    cx,
24680                                )
24681                            }
24682                        })
24683                        .on_click({
24684                            let editor = editor.clone();
24685                            move |_event, window, cx| {
24686                                editor.update(cx, |editor, cx| {
24687                                    let snapshot = editor.snapshot(window, cx);
24688                                    let position =
24689                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24690                                    editor.go_to_hunk_before_or_after_position(
24691                                        &snapshot,
24692                                        position,
24693                                        Direction::Next,
24694                                        window,
24695                                        cx,
24696                                    );
24697                                    editor.expand_selected_diff_hunks(cx);
24698                                });
24699                            }
24700                        }),
24701                )
24702                .child(
24703                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24704                        .shape(IconButtonShape::Square)
24705                        .icon_size(IconSize::Small)
24706                        // .disabled(!has_multiple_hunks)
24707                        .tooltip({
24708                            let focus_handle = editor.focus_handle(cx);
24709                            move |window, cx| {
24710                                Tooltip::for_action_in(
24711                                    "Previous Hunk",
24712                                    &GoToPreviousHunk,
24713                                    &focus_handle,
24714                                    window,
24715                                    cx,
24716                                )
24717                            }
24718                        })
24719                        .on_click({
24720                            let editor = editor.clone();
24721                            move |_event, window, cx| {
24722                                editor.update(cx, |editor, cx| {
24723                                    let snapshot = editor.snapshot(window, cx);
24724                                    let point =
24725                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24726                                    editor.go_to_hunk_before_or_after_position(
24727                                        &snapshot,
24728                                        point,
24729                                        Direction::Prev,
24730                                        window,
24731                                        cx,
24732                                    );
24733                                    editor.expand_selected_diff_hunks(cx);
24734                                });
24735                            }
24736                        }),
24737                )
24738            },
24739        )
24740        .into_any_element()
24741}
24742
24743pub fn multibuffer_context_lines(cx: &App) -> u32 {
24744    EditorSettings::try_get(cx)
24745        .map(|settings| settings.excerpt_context_lines)
24746        .unwrap_or(2)
24747        .min(32)
24748}